Building Closot's Real-Time Collaboration Engine

Craft
Tarun Dubey·

Real-time collaboration is table stakes for a modern workspace. But "real-time" hides enormous complexity — especially when you want offline editing, low latency, and correct conflict resolution across dozens of simultaneous editors. In Closot, real-time is not limited to documents. Users collaborate in real time on boards (dragging kanban cards simultaneously), meeting notes (live editing during calls), sprint planning sessions (adding and estimating tickets concurrently), and calendar views (resolving scheduling conflicts as they happen). This post covers how we rebuilt our collaboration engine from the ground up to handle all of these surfaces.

Why we moved from OT to CRDTs

Our original collaboration engine used Operational Transformation (OT). It worked well for 2-3 concurrent editors on text documents, but had two fundamental limitations: it required a central server to order operations (making offline editing unreliable), and it was designed for sequential text — not for the structured, block-based, multi-surface editing that Closot requires.

CRDTs (Conflict-free Replicated Data Types) solve both problems. Operations can be applied in any order and always converge to the same state. There is no central coordinator — each client maintains its own replica and syncs state through a gossip protocol. For Closot, the key advantage is that CRDTs can model any data structure — text, lists, maps, trees — which means a single engine can power collaboration across pages, boards, databases, and calendars.

CRDT sync flow — multi-surfaceClient A(editing doc)Client B(moving card)Client C(offline)bufferedSync server (operation relay)Converged workspace stateDoc blocksBoard columnsCalendar slots

Real-time on boards: Dragging cards simultaneously

Kanban boards are one of the most challenging collaboration surfaces. Multiple users dragging cards between columns simultaneously creates a dense stream of conflicting operations. Our CRDT models each column as an ordered list, and each card as an element with a fractional position index. When two users move different cards into the same column at the same position, the CRDT assigns unique fractional indices that maintain both moves without collision.

The tricky case is when two users move the same card. Our conflict resolution rule is last-writer-wins with a 500ms debounce. If user A drags card X to "In Progress" and user B drags it to "Done" within 500ms, the later operation wins — but both users see the conflict and the card briefly highlights to indicate it was moved by someone else. In practice, same-card conflicts are rare (less than 0.02% of operations) because presence indicators show where teammates are working, naturally distributing attention.

During sprint planning, a special case arises: multiple engineers estimate tickets concurrently. Story point values use a last-writer-wins register, but we added a "planning poker" mode where estimates are hidden until everyone has committed their value, then revealed simultaneously. This uses a sealed CRDT register — a write-once value that becomes readable only when all participants have written.

Live cursors in docs and meeting notes

Showing where teammates are working sounds simple until you need sub-block accuracy across a block-based editor. We track four pieces of state per connected client: cursor position (block ID + character offset), selection range, the active block being edited, and the viewport scroll position. This state is broadcast as ephemeral CRDT operations — they update presence in real time but are not persisted to the document history.

For meeting notes, live cursors are essential. During a meeting, three or four people might be editing the same page simultaneously — one taking notes in the main body, one adding action items in a checklist, one updating the attendee list. Each person sees colored cursors and selection highlights for every other editor. We debounce presence updates at 50ms to avoid flooding the WebSocket connection. At 10 concurrent editors, this produces roughly 200 presence messages per second — well within our connection budget of 1000 messages/second per document.

The AI-generated meeting summary introduces an interesting collaboration challenge. When the meeting ends and a participant requests an AI summary, the Closot AI Agent writes the summary into the meeting notes page. This appears as a new collaborator — the agent has its own cursor, its own colored highlight, and its edits stream in block by block. Other users can continue editing the page while the agent writes. The CRDT handles the interleaving seamlessly.

Concurrent sprint planning

Sprint planning in Closot is a collaborative session where multiple participants interact with the same board and cycle simultaneously. A product manager drags tickets from the backlog into the sprint. An engineer adds story point estimates. A tech lead marks dependencies. Another engineer reorders priorities.

We model the sprint backlog and active cycle as two ordered sets with a bidirectional move operation. Moving a ticket from backlog to sprint is an atomic operation in the CRDT — it removes from one set and inserts into another in a single logical step. This prevents a ticket from appearing in both locations during network delays, which was a constant problem under our old OT system.

The velocity widget updates in real time as points are added to the sprint. It pulls historical data from the last eight cycles and shows a projection: "You've committed 47 points. Your average velocity is 42. You're 12% over capacity." This widget is a read-only derived view — it does not participate in the CRDT directly but recalculates whenever the underlying sprint data changes.

Calendar conflict resolution

The calendar view introduces unique conflict scenarios. When two users drag different events to the same time slot, both moves should succeed (a person can have overlapping events). But when two users reschedule the same event to different times, we need a conflict resolution strategy. We use last-writer-wins with visual feedback: the losing move is shown as a ghost animation that fades to the winning position, and both users receive a notification explaining what happened.

For recurring events, we handle conflicts at the instance level. Rescheduling a single instance of a recurring meeting creates an exception in the recurrence pattern — modeled as an override map in the CRDT. Two users can reschedule different instances of the same recurring meeting without conflict.

Block-level editing: The CRDT library

Closot pages are block-based, and each block type (paragraph, heading, list, database row, embedded board view, calendar widget) has different merge semantics. We built a custom CRDT library — internally called Converge — that understands block structure natively.

Converge models a document as a tree of blocks, where each block contains a sequence CRDT for its content (text, list items) and a map CRDT for its properties (formatting, metadata). Block reordering uses the same fractional indexing as kanban cards. Block deletion is a tombstone operation — the block is marked as deleted but retained in the CRDT state to ensure convergence, then garbage-collected after all clients have acknowledged the deletion.

Text within a block uses a variant of the RGA (Replicated Growable Array) algorithm, which assigns each character a unique identifier based on a Lamport timestamp and client ID. This ensures that concurrent insertions at the same position are deterministically ordered — no matter what order they arrive, the final text is identical on every client.

Converge CRDT: Block document modelDocument (tree CRDT)Heading block (RGA)Paragraph block (RGA)Board embed (map CRDT)content: RGA sequenceprops: LWW map (bold, size...)

Offline reconciliation

The hardest challenge. When a user reconnects after hours offline, their local changes need to merge cleanly with potentially hundreds of remote operations. Our CRDT guarantees convergence, but the visual result needs to make sense to humans too — so we added a "changes since you were away" summary.

On reconnect, the client sends its local operation log to the server. The server replays these operations against the current state, detects conflicts (if any), and sends back a delta of remote operations the client has not seen. The client applies these in a single batch, and the page updates to the converged state. For large offline sessions (100+ operations), this reconciliation takes under 200ms — fast enough that the user sees a single smooth update rather than a cascade of changes.

We also built a visual diff for offline reconciliation. If your offline edits overlapped with significant remote changes, Closot shows a side-by-side view highlighting what changed remotely while you were away. This is opt-in — most reconnections are clean enough that the CRDT handles everything transparently.

Performance at scale

Our target is real-time collaboration with up to 50 simultaneous editors on a single document, with operation latency under 100ms. In production, the median operation latency is 34ms. At 50 concurrent editors generating an average of 5 operations per second each, the server processes 250 operations per second per document. Our sync server is horizontally scaled — each document is assigned to a single server instance via consistent hashing, and clients connect to their document's assigned server via WebSocket.

For boards during active sprint planning sessions, we have measured up to 30 concurrent users with latency staying under 60ms. The bottleneck is not the CRDT computation (which is O(1) per operation) but the WebSocket fan-out — broadcasting each operation to all connected clients. We batch outgoing messages at 16ms intervals (matching a 60fps update rate) to keep the connection efficient.

The result is a collaboration engine that works across every surface in Closot — docs, boards, meeting notes, calendar, sprint planning — with consistent behavior, predictable conflict resolution, and genuine offline support. It took us fourteen months to build. We believe it is the foundation that makes everything else in Closot possible.

Tarun Dubey·
Copy link