Live editing
What actually happens when two people write in the same project at the same time, and where the limits are.
Two writers in the same chapter see each other's words appear as they are typed. There is no lock, no merge dialog, and no save. This page explains how that works and what it cannot do.
The model
Everything you co-edit lives in a CRDT document: the scene list, every scene script, staging headers, cast, variables, HUD config, and even flow-view node positions. Everything administrative lives in Postgres: accounts, roles, share-link slugs, published versions, the asset table.
That split is why edits never need a save button and why membership changes never need a sync. Each chapter is its own document, plus one shared meta document for project-wide things. They all travel over a single websocket per project, so opening a second chapter does not open a second connection.
A CRDT merges concurrent edits by construction. If you and a co-writer type into the same paragraph at once, both sets of characters land, interleaved at the positions you each typed them. Nobody's keystrokes are dropped and nobody is asked to resolve anything.
Who is here
The editor header shows an avatar chip per person connected to the chapter you have open. The color comes from a hash of the name, so the same person is the same color on every machine and every reload.
Inside the script you see remote carets, labeled and tinted to match the roster. In the flow view you see remote pointers moving over the graph. Both read the same presence field, so a person's name and color are consistent wherever they show up.
If an agent run is in flight, a separate chip appears reading writing on agent/run-1a2b3c4d, naming the branch the run is on. That is the agent, not a
person. See
Runs and review.
Presence is per chapter document. Someone working in another chapter is connected to the project but will not appear in your roster.
Connection state
Next to the chapter title, the shell reports one of three things:
- Synced: your changes are on the server.
- Syncing...: local changes are still being pushed, or the document has not finished loading.
- Offline (retrying): the socket is down and the client is reconnecting.
You can keep typing while it says Offline. The edits sit in the local document and push when the connection returns. A red banner appears above the editor if the token fetch itself fails, and it retries on its own.
One real caveat: a chapter is not handed to the editor until its first sync completes, which is why you sometimes get a skeleton for a moment when you switch chapters. That wait exists because a write made before the initial sync can be lost. When you switch away, the client waits for pending saves to flush before closing, but it gives up after three seconds so a dead backend cannot hang you forever.
Undo is yours alone
Undo never touches another person's work. That is deliberate, and it means undo cannot rescue you from what a collaborator did.
There are two undo stacks and both are scoped to edits you made locally:
- Inside a scene script, undo is per-user and per-scene. It rewinds only the changes this browser pushed through the script editor.
- Outside the script (adding, renaming, deleting, or reordering scenes and chapters, and other structural work), a separate stack rewinds only your own structural changes.
So if a co-writer deletes a scene you wanted, pressing undo does nothing about it. That is what checkpoints are for.
What live editing does not do
Be clear-eyed about the edges:
- No locking. Two people can rewrite the same line into nonsense. The merge is mechanical, not editorial. Talk to each other.
- No per-person history. Presence tells you who is here now. It does not record who wrote which sentence. Checkpoints record who saved them, and agent writes are marked, but ordinary co-writing is not attributed.
- Structural conflicts are not clever. Two people renaming the same scene at the same instant leaves one of the two names. Nothing warns you.
- Which branch you are on is private. The active branch is per-user
routing state carried in the
?branch=URL parameter. Someone else in the same project may be looking at a different draft entirely, and neither of you is told. - Tabs are not deduplicated. Two tabs on the same project are two sessions, and you will see yourself in your own roster.
When somebody's access changes
A role change is written to Postgres immediately, but an already-open collab session keeps the permissions its current token was minted with until that token expires (10 minutes by default). Demotion reaches a live socket within about that window. Details are in Roles and invites.
The other event that interrupts everyone is a checkpoint restore. It rewrites the documents on the server, and every connected client reloads onto the restored state rather than trying to reconcile what it had in memory.