All guides
A Reply Across Two Machines
The journey of one operation stays on one machine on purpose: one verb, one log, one refold, so the four claims underneath it are visible without a second story running beside them. This is the same trip with the axis that one leaves out — two replicas, and an op that arrives from somewhere else.
The scene. An agent ran on the laptop and is owed an answer. You are at the desktop, so you answer there. Nothing joins the two machines but a relay and an append-only log.

You reply on whichever machine you are at
nxc reply --thread m-7f2 "ship it — default the flag to off"reply appends message ops to this machine's log, exactly as nxf close appended field ops in
the first journey, and the receipt comes back the moment they are durable. The CLI holds no model of
its own here either: it calls Engine::reply_thread on crates/chat, the same seam an embedding app
calls. Nothing has left the desktop yet.
The desktop cannot tell that anybody is waiting
The receipt says woke: null, and it is not reporting an attempt that failed — it reports that
no wake was ever owed.
A thread's return address names a session, and sessions live in session_map: a plain table the
reducer never touches and sync never carries. The reason is in that module's own first paragraph — a
runtime session id "names a live session on THIS machine", so it is meaningless to a peer. Asking the
desktop's map who is behind that address answers nobody, and the resume path reads that as the
ordinary case rather than as a skip.
So the boundary this page exists for is already here, one step in:
The log carries what was said. It does not carry who is standing by to hear it.
The relay moves ops, never views
The desktop's background service pushes on its next pass; the laptop's pulls on its own. That exchange is anti-entropy, not delivery: each side asks what the other holds that it lacks, and takes the ops themselves. No op is addressed to a machine and no server keeps a queue per recipient — the relay would have nowhere to put one, never having been told that a laptop is interested in this thread.
This is the first journey's property seen from the other side. The view is a cache of the log, so sync ships the log; and because it ships the log, a replica that was switched off for a week converges by asking rather than by having been remembered.
The laptop refolds, and says so
The pulled ops land in the laptop's ops table. A pass moves the log for every domain but folds
only flow's views, so the message sits there with the messages view not yet materialized; opening a
chat store runs the existing refold-when-behind, and the view catches up. Nothing in the daemon knows
how a message folds — the trigger is generic, the folding belongs to the reducer.
That commit bumps PRAGMA data_version, and that pragma is the whole of the change-notification
mechanism: a background thread polls it on its own read connection, and Engine::subscribe hands out
a coalesced "someone wrote — re-read" tick. No daemon of its own, no socket, no push.
What continues, and what does not
An app that is already alive — a desktop client, a TUI, anything holding the engine open with a
subscribe() — gets that tick, re-reads its inbox, and shows the answer. That is the mechanism
working exactly as designed, across two machines, with no network call between the human and the app.
An agent session that has ended its turn is resumed by none of it. The laptop's service knows exactly one chat job, and it is a deadline the laptop itself armed; an op arriving from elsewhere arms nothing. The wake in the second section did not fail to cross — there was never a wake to cross, because the fact that a session is waiting is not in the shared log and by construction cannot be.
If you are building on this, that is the sentence to keep:
Sync delivers your data, not your control flow.
Resuming the work on the machine where it was left is a decision your app makes, out of the message it has just read.