Command / RPC Message Plane
Editor and runtime integrations need to issue commands — Run Agent Doc,
sync, focus, save, session operations — with a single reusable admission,
dedupe, cancellation, generation-guard, progress, and reconnect story. Without
one, every caller reinvents in-flight/dedupe/supersede/retry/timeout logic, and
accepted / queued feedback gets mistaken for terminal success.
lazily’s command plane (command-plane-v1) is that shared substrate. It is an
additive sibling to Snapshot / Delta / CrdtSync, not a replacement:
command frames can ride the same transports and reflect into the normal state
graph, but they carry command traffic, not cell state.
The four frames
| Frame | Role |
|---|---|
CommandSubmit | Submit a command: envelope + domain payload (an IpcValue) |
CommandCancel | Preempt a still-non-terminal command by command_id |
CommandEvents | Progress/detail events (UX + diagnostics only, never proof) |
CommandProjection | Folded, queryable command state; also the reconnect resync image |
lazily owns the envelope; the namespace owns the payload. lazily never
decodes payload. Agent-doc publishes its own payload schemas
(agent-doc.editor_route.v1, agent-doc.sync_tmux_layout.v1, …) and only
references lazily’s envelope.
Progress is not proof
The single hard rule: terminal authority is the causal receipt. A command is
terminal only when a terminal CausalReceipt for its
command_id folds in (applied, or rejected — including the cancelled /
superseded / timed_out reasons). observed / accepted / started /
queued-admission events are non-terminal progress. A transport ACK is never
terminal.
This keeps command events from becoming a second proof system. Events may carry queue position, retry advice, or copied CLI output; the effect still folds through receipts and domain facts.
RPC is a facade
call / submit / cancel / observe / projection are implemented entirely
over the four frames:
await client.call("agent-doc.editor_route", payload, {
commandId,
idempotencyKey: "project-root:plan.md:run",
authorityGeneration: 42,
deadlineMs: 120000,
policy: { dedupe: "same_idempotency_key", supersede: false, cancelOnPreempt: true }
});
call resolves only on a terminal causal-receipt projection. A network ACK,
controller admission, or accepted / queued event never resolves a unary
call. submit returns the command_id for callers that manage events and
projection themselves. Reconnect uses CommandProjection; a call replays only
when the idempotency policy says replay is safe.
Rules
- Generation guards — events/receipts outside the command’s current authority generation are ignored (kept only as audit data).
- Idempotency — replaying a submit/event/receipt with a known id is a no-op.
- Cancel before terminal only — a cancel after
appliedis ignored. - Terminal conflict fails closed —
appliedvsrejectedat the same generation is not resolved by winner selection. - Reconnect equivalence — folding a
CommandProjectionequals folding the events and receipts it summarizes.
The normative field list and rules live in
protocol.md § Command / RPC Message Plane.
The schema is schemas/message-passing.json.
Conformance fixtures live in conformance/message-passing/; each binding
replays them through its CommandProjection reducer and RPC facade.
{
"protocol_version": 1,
"kind": "Command",
"model": "CommandProjection",
"description": "observed/accepted events are progress only; the command becomes terminal ONLY when the applied CausalReceipt folds in.",
"frames": [
{
"schema": "message-passing",
"wire": {
"CommandSubmit": {
"command_id": "cmd-run-1",
"causation_id": "cmd-run-1",
"source": "vscode-plugin",
"target": "project-controller",
"namespace": "agent-doc",
"name": "editor_route",
"authority_generation": 42,
"idempotency_key": "project-root:plan.md:run",
"deadline_ms": 120000,
"policy": {
"dedupe": "same_idempotency_key",
"supersede": false,
"cancel_on_preempt": true
},
"payload_type": "agent-doc.editor_route.v1",
"payload_hash": "sha256:f753816ec570dcaa98e80dafcf975b020a5ccc9db551c69e121567a48ee16346",
"payload": {
"Inline": [
123,
34,
102,
105,
108,
101,
34,
58,
34,
47,
104,
111,
109,
101,
47,
117,
115,
101,
114,
47,
112,
114,
111,
106,
101,
99,
116,
47,
112,
108,
97,
110,
46,
109,
100,
34,
44,
34,
114,
101,
108,
97,
116,
105,
118,
101,
95,
112,
97,
116,
104,
34,
58,
34,
112,
108,
97,
110,
46,
109,
100,
34,
44,
34,
100,
105,
115,
112,
97,
116,
99,
104,
95,
111,
110,
108,
121,
34,
58,
102,
97,
108,
115,
101,
44,
34,
112,
108,
97,
105,
110,
95,
116,
114,
105,
103,
103,
101,
114,
34,
58,
102,
97,
108,
115,
101,
44,
34,
119,
97,
105,
116,
95,
98,
117,
100,
103,
101,
116,
95,
109,
115,
34,
58,
49,
50,
48,
48,
48,
48,
44,
34,
108,
97,
121,
111,
117,
116,
95,
97,
114,
103,
115,
34,
58,
123,
34,
99,
111,
108,
117,
109,
110,
115,
34,
58,
50,
44,
34,
102,
111,
99,
117,
115,
34,
58,
116,
114,
117,
101,
125,
44,
34,
114,
111,
117,
116,
101,
95,
107,
101,
121,
34,
58,
34,
112,
114,
111,
106,
101,
99,
116,
45,
114,
111,
111,
116,
58,
112,
108,
97,
110,
46,
109,
100,
58,
114,
117,
110,
34,
44,
34,
101,
100,
105,
116,
111,
114,
95,
97,
116,
116,
101,
109,
112,
116,
95,
105,
100,
34,
58,
34,
97,
116,
116,
101,
109,
112,
116,
45,
55,
34,
125
]
},
"required_features": [
"causal-receipts",
"command-events"
]
}
}
},
{
"schema": "message-passing",
"wire": {
"CommandEvents": {
"events": [
{
"event_id": "ev-1",
"command_id": "cmd-run-1",
"kind": "observed",
"generation": 42,
"detail": null
},
{
"event_id": "ev-2",
"command_id": "cmd-run-1",
"kind": "accepted",
"generation": 42,
"detail": "queued at position 1"
},
{
"event_id": "ev-3",
"command_id": "cmd-run-1",
"kind": "started",
"generation": 42,
"detail": null
}
]
}
}
},
{
"schema": "receipts",
"wire": {
"CausalReceipts": {
"receipts": [
{
"receipt_id": "rcpt-1",
"causation_id": "cmd-run-1",
"observer": "project-controller",
"generation": 42,
"outcome": "applied",
"reason": null,
"payload_hash": "sha256:f753816ec570dcaa98e80dafcf975b020a5ccc9db551c69e121567a48ee16346"
}
]
}
}
}
],
"expect": {
"projection": {
"generation": 42,
"commands": [
{
"command_id": "cmd-run-1",
"status": "applied",
"terminal": true,
"generation": 42,
"reason": null,
"terminal_receipt_id": "rcpt-1",
"last_event_id": "ev-3"
}
]
},
"terminal_after_frame_index": 2
}
}