Private lanes
A Space can give every participant their own private lane beside the shared room: a place to think with an agent that the other side never sees, from which nothing reaches the shared room without the human putting it there.
This is the Bridge's "prep room + co-signed crossing", generalized into a primitive any Space can have.
The structure
A lane is its own Space, not a scope inside the shared one. It has its own room id, its own key, its own ledger. Two rooms, linked on the device that holds both keys.
That matters for the privacy claim. A "private scope" inside one room would put both sides' confidential reasoning in a single sealed object, separated only by application logic — and the server would be the thing enforcing the separation. Two rooms means a lane's contents are sealed to a key the other participant simply does not have.
The server never joins the two rooms. The device does. It holds both keys, reads the shared room, and appends a
labelled copy into the lane (op: 'mirror', deduped by entry id, idempotent). To the platform these are two unrelated
Spaces.
What the lane agent can and cannot do
Inside the lane, the agent sees the shared room as an observer. It is told so explicitly:
THE SHARED ROOM — the live negotiation the other party sees. You OBSERVE it; you cannot post here.
To put something in the shared room it must call cross_to_shared, and that is a high-stakes tool: the agent
proposes, a human approves, and only then does it execute. Propose → approve → execute is the same delegated
authority rule the rest of the platform uses — see Delegated authority.
So the failure mode people actually fear — "my assistant said the quiet part out loud to the other side" — is not guarded by a prompt instruction. It is guarded by the agent having no path to the shared room that does not pass through a human decision.
What crosses is a message, not a transcript
cross_to_shared carries the text the human approved. The lane's reasoning, drafts, rejected phrasings and private
context stay in the lane. Crossing is an act of composition, not of forwarding.
The pending draft can be copied out as text before approving. Editing it in place was built and then removed: it made "what exactly am I approving?" ambiguous, which is the one question the approval step exists to answer.
In the room
- Lanes can be created for every participant at room creation, so the topology is the default rather than something to discover later.
- The lane opens as a docked panel beside the shared thread; the shared room's messages appear in it as compact, labelled, collapsible lines, so you can read one conversation without losing the other.
- A pending crossing renders as the message plus Approve / Not now.
Code map
| Concern | Where |
|---|---|
| The crossing capability + guidance | agent/spaceBridge.mjs (cross_to_shared, renderSharedForAgent) |
| Provisioning + linking lanes | agent/spaceProvision.mjs |
| Turn path (bridged context) | agent/spaceService.mjs, agent/asyncTurn.mjs |
| Mirror op (device-side join) | agent/spaceService.mjs (op: 'mirror') |
| Lane UI | spaces/public/privateLane.html, spaces/public/space.html (?panel=1) |
Status
Live. All four phases — crossing, provisioning, agent runtime, UI — are built and deployed.
Design notes, including the alternatives that were rejected, are in docs/spaces-private-lane.md.
Machine-readable source: private-lanes.md · every doc in one fetch: llms-full.txt (HTML) · ← delegated-authority · api-reference →