Browse documentation
Repositories and Changes
Live mode (preview)
Use real files on multiple machines with a central JJ store: clone, collaborate, recover pending edits, and understand live workspace state.
On this page
Live mode gives each agent an ordinary directory connected to one central JJ store. Accepted changes, bookmarks and workspace positions are shared across machines without push or pull. Your editor, shell and build tools use real local files; no VFS or FUSE mount is involved.
Before you start
This is an experimental engine preview, not a generally enabled production feature. It requires a matching preview CLI and backend, repository access, and a physical V2B repository explicitly enabled by its operator. Installing a newer CLI does not enroll a repository or convert an existing checkout.
The operator enables eligible repository IDs through JJ_LIVE_WORKSPACE_REPOS. First live enrollment changes the repository's authority contract: older V2B backends cannot reopen its live capsule, and ordinary clones or legacy operation-head publication are refused afterward. Use an isolated evaluation repository; this is not a reversible per-folder preference. Updated backends can still serve ordinary V2B repositories that have not been enrolled.
A physical repository is required. A federated Home view or a virtual repository rooted at a subdirectory is not supported by this preview. The checkout and its external recovery directory must be on the same filesystem, with Unix filesystem semantics.
Create a live checkout
Use the normal repository address and authentication flow. In these examples, acme/project is the eligible organization/repository address; agent-a and agent-b are distinct server workspace names.
com login
com clone --live acme/project ./agent-a --workspace agent-a
cd agent-a
com live status
--live creates a new server workspace, materializes its files and starts a detached watcher. Clone reports success after the watcher's first successful tick. Existing source files are tracked automatically. If you omit --workspace, Composal generates a unique machine-based name.
The starting point defaults to the repository's default branch. Use --trunk REVISION to start a new working change based on a bookmark, change ID, commit ID or workspace position such as agent-a@. An empty repository starts at root.
Run com live commands from the live checkout root. Ordinary commands such as com status, com push, com pull and com submit are not the live command surface. The CLI refuses legacy workspace commands inside live directories, including their subdirectories; a --repository override does not bypass that protection.
Edit files and create changes
Edit tracked files normally. The watcher captures their changes and sends them to the server automatically. New files require an explicit path; tracking a directory does not recursively add its contents.
# After creating a new source file in your editor:
com live track src/parser.rs
# Wait for an explicit snapshot boundary, then describe the current change.
com live snapshot
com live describe -m 'Implement the parser'
com live bookmark set parser-work
# Start the next working change above the current one.
com live new -m 'Use the parser'
com live log
snapshot publishes tracked file edits once; the watcher performs the same job automatically. describe changes the current change's description. new publishes current edits before creating the next change. These commands require the server. Accepted rewrites retain the JJ change ID while the immutable commit ID changes.
Live mode has no separate commit or push step. Description and file updates become accepted central operations. That does not submit a numbered Composal Change for review or land anything on trunk. Live review submission and landing integration remain planned. Published trunk ancestry is immutable; work starts in a new change above it.
com live log returns JSON containing workspace positions, bookmarks and a graph pinned to one central operation. It returns up to 1,000 reachable commits; check truncated before treating it as complete history.
Work across machines
On another machine, authenticate and create a separate workspace based on the first agent's accepted bookmark:
com clone --live acme/project ./agent-b \
--workspace agent-b --trunk parser-work
cd agent-b
com live log
This creates an independent working change above parser-work. Both agents can inspect the same accepted graph, within their repository permissions. Local edits that have not been accepted are still only on their originating machine.
To check out an existing accepted change instead of creating a child:
com live edit parser-work
# A workspace position or an unambiguous change/commit ID also works:
com live edit agent-a@
edit publishes current tracked edits before switching. Editing another workspace's accepted change can rewrite shared state and move affected workspace positions; use independent child changes for parallel tasks. The server rebases descendants when their ancestors change. Each watcher then updates its own clean local files. This is not character-by-character collaborative editing, and dirty or colliding files are protected rather than overwritten.
Bookmarks are shared names in the central graph and follow rewritten changes:
com live bookmark set parser-ready
com live bookmark list
com live rebase -r agent-b@ -d parser-work
com live bookmark delete parser-ready
bookmark set NAME -r REVISION chooses a specific target. rebase defaults to the current change when -r is omitted; immutable sources and cycles are rejected. A snapshot or graph command can fail if another operation makes its expected state stale; inspect the pending request before trying to recover it.
How synchronization works
Agent A: files + watcher + local journal
↕
Central JJ store and V2B state
↕
Agent B: files + watcher + local journal
The current implementation has one watcher per directory and uses polling. Its normal loop is:
- Read tracked files and hash changed content locally. Persist immutable objects and an exact pending request before contacting the server.
- Send the captured content as a deduplicated batch. The server validates hashes, permissions and expected writer state, then executes the JJ operation centrally.
- Record the operation head, workspace state and retry receipt together in the V2B SQLite transaction, subject to the server's configured durability acknowledgment.
- Receive the acknowledgment and check the desired workspace state. Apply changed files with recovery information and no-clobber writes. An unchanged cursor avoids transferring file bodies.
- Optionally warm verified content for nearby drafts and their direct dependencies. Later checkouts can reuse it without downloading the same bodies again.
An acknowledged operation is the authority for the graph. Clients do not invent operation heads or merge independent local operation histories. The current engine shares a repository operation history; separate working-repository and trunk histories are a planned architecture change.
Prefetch is bounded to four commits, 256 file entries and 4 MiB per pass. It does not walk historical operations or recursively traverse commit history. A two-second timeout and retry backoff keep optional warming from invalidating an accepted snapshot. Changed workspace reads still return complete bounded manifests, and the server still materializes the full tree internally.
A shared host daemon and persistent pubsub delivery are planned. The preview watcher is not that daemon, and polling does not promise instantaneous or continuously fresh local files.
Understand local and shared state
| State | Where it lives | What it means |
|---|---|---|
| Working files | Your checkout directory | Ordinary editable files; edits may not yet be captured. |
| Objects and pending intent | Private external client state | Hashed bytes and an exact retry request, durable locally. |
| Accepted commits, bookmarks and workspace positions | Central JJ store | Shared repository state visible to authorized clients. |
| Operation head and command receipt | V2B SQLite capsule | Server-owned operation state and retry identity under its durability policy. |
Local state defaults to $HOME/.vex/workspaces/<checkout-path-hash>/. Its live.json journal holds compact references; objects, locks, watcher state and recovery files are adjacent. The canonical checkout path selects this directory; the server workspace name is a separate identity. The state is external to the source tree, rather than inside .jj.
Set VEX_LIVE_STATE_HOME to an absolute directory on the checkout's filesystem if you need another location. Use the same value for clone, watcher and subsequent commands. The normal clone authentication flow retains its repository credential in private state so the watcher can continue after clone exits. Do not share or edit that state directory as source files.
com live status reports the last acknowledged IDs, pending work, watcher readiness/errors and content metrics. A content hash is not server acceptance. remotely_durable: false while tracked files differ or a request is pending means the local work is not fully acknowledged. A true value reflects the configured server acknowledgment for that state; it is not an independent multi-region replication guarantee or proof of continuous freshness.
Capture offline edits and recover safely
Once a server workspace has been opened and acknowledged, you can capture tracked edits without a network connection:
com live stage
com live pending
# Once connectivity returns:
com live retry
The running watcher also captures offline edits before attempting network work. stage hashes and fsyncs locally without connecting; pending reports queued-locally, content IDs and the preserved request identity. Only one request can be pending at a time. Further editor changes remain in your files until the pending request is acknowledged and the next capture occurs.
Retry sends the exact captured bytes and request ID, including after a CLI restart. If the server accepted the request but its response was lost, the receipt prevents duplicate execution. Retrying does not replace newer local edits with older captured bytes. The server may reject a stale or fenced request; the client does not silently rebase or discard it.
For a request that cannot be accepted, preserve both the current files and the pending snapshot:
com live stop
com live pending
com live recover ../recovered-agent-files
Recovery exports the pending snapshot to a separate directory and retains the original journal. The exported bytes may differ from edits made after capture. Do not delete state to clear an error. Dirty-file failures mean the client refused an unsafe overwrite; reconcile the preserved files before continuing.
Legacy inline pending requests replay before journal migration. New object batches require the updated backend; older servers reject them. This is not unrestricted forward/backward compatibility with every V2B binary.
Manage the watcher and move machines
com live stop
com live start
com live status
start reuses a running watcher; stop stops this directory's watcher without deleting local files or central state. After reboot, run start again: the preview does not install a system startup service. Foreground operation is also available:
com live watch --interval-ms 1000
Foreground mutations and the watcher coordinate through the same session lock. Stopping the watcher is not required for everyday live commands. To run a foreground watcher, stop the detached one first.
For an explicit backend connection, use com live open DIR --server URL --org ORG --repo REPO --workspace NAME, authenticate through VEX_LIVE_TOKEN, then start a watcher in that directory. This path does not start one automatically.
To transfer one existing logical workspace to a replacement machine, use a fresh directory and the explicit backend connection:
com live claim ./replacement \
--server https://backend.example.com \
--org acme --repo project --workspace agent-a
cd replacement
com live start
claim also authenticates through VEX_LIVE_TOKEN. It advances the writer generation, fencing the previous writer's future mutations while preserving its files. It does not recover unacknowledged bytes left on the old machine. Use separate workspace names for concurrent agents. Renaming or moving a checkout changes its local path identity; preserve the old journal rather than treating a moved directory as automatically reattached.
Preview boundaries
- Each workspace tree is limited to 4,096 paths and 64 MiB; each repository supports up to 1,024 workspace identities. Large-tree pagination is not implemented.
- New files require explicit tracking. File/directory type transitions, Git submodule materialization and non-file conflicts are refused. Regular files, symlinks, executable bits, deletions and text-conflict markers are supported.
- Materialization is protected per file, not an atomic whole-directory switch. A concurrent reader may see a mixture until checkout finishes.
- Recovery retains displaced original inodes, including files still open in an editor. Recovery data and baseline/pending objects do not yet have automatic garbage collection. A compact
live.jsondoes not represent total disk usage. - Optional cache failures appear in
content_metrics, includinglast_prefetch_error; they do not undo accepted state. A cached object never grants repository access. - The server currently records the
Composal agentauthor identity. Live mode does not yet replace every ordinary JJ command, numbered review submission, landing or shared undo workflow.
For an ordinary local checkout, use the separate source-control workflow. Live directories must continue using the explicit live command surface.