Reference·RPCIndexClose
RPC
Drive Nodecode from a program: one command a line on stdin, one frame a line on stdout.
A program spawns nodecode rpc and keeps its stdin open. Nothing here is a second protocol: a line in is the gateway's own command, and a line out is the gateway's own frame.
Start it
nodecode rpc [SESSION-ID [--cursor N]] [--store PATH | --ephemeral]
It finds the organism serving your home, or starts one. It presents the operator token and subscribes to a session: the one you name, or a fresh one. Your program never handles a port, a token or a handshake. The first line out is . Then come , and .
{"sequence":2,…"event":{"type":"session.created"…"type":"session_stream_event"},"cursor":2,"durable":true}{"sequence":2,"session_id":"s-GW3YSGSZ","payload":{"frame":{"seq":2,"session_id":"s-GW3YSGSZ","turn_id":false,"event":{"type":"session.created","payload":{"id":"s-GW3YSGSZ","cwd":"/home/you/project","parent":false,"created-at":"2026-10-09T02:53:33.203Z"},"metadata":{"event_id":"event-1U5SO19-6ME7O12TOP","log_position":2,"turn_id":false,"command_id":"command-1U5SO19-DVTNEZ5SG4","occurred_at":"2026-10-09T02:53:33.203Z"}}},"type":"session_stream_event"},"cursor":2,"durable":true}
{"sequence":3,…"event":{"type":"turn.input_committed"…"type":"session_stream_event"},"cursor":3,"durable":true}{"sequence":3,"session_id":"s-GW3YSGSZ","payload":{"frame":{"seq":3,"session_id":"s-GW3YSGSZ","turn_id":"turn-1U5SO19-KHY4SY503B","event":{"type":"turn.input_committed","payload":{"role":"user","message":"say pong","prompt-id":"command-1U5SO19-DFKDHVX7KL","sequence":1,"disposition":"started"},"metadata":{"event_id":"event-1U5SO19-QZP020Q1FF","log_position":3,"turn_id":"turn-1U5SO19-KHY4SY503B","command_id":"command-1U5SO19-DFKDHVX7KL","occurred_at":"2026-10-09T02:53:33.207Z"}}},"type":"session_stream_event"},"cursor":3,"durable":true}
{"sequence":4,…"event":{"type":"turn.started"…"type":"session_stream_event"},"cursor":4,"durable":true}{"sequence":4,"session_id":"s-GW3YSGSZ","payload":{"frame":{"seq":4,"session_id":"s-GW3YSGSZ","turn_id":"turn-1U5SO19-KHY4SY503B","event":{"type":"turn.started","payload":{"input":"say pong"},"metadata":{"event_id":"event-1U5SO19-OOOH5SCVD9","log_position":4,"turn_id":"turn-1U5SO19-KHY4SY503B","command_id":"command-1U5SO19-DFKDHVX7KL","occurred_at":"2026-10-09T02:53:33.208Z"}}},"type":"session_stream_event"},"cursor":4,"durable":true}
{"sequence":0,"payload":{"type":"gateway_turn_command_result"…"command":"start_turn","status":"accepted","message":"turn admitted"…{"sequence":0,"payload":{"type":"gateway_turn_command_result","result":{"command_id":"command-1U5SO19-DFKDHVX7KL","correlation_id":"command-1U5SO19-DFKDHVX7KL","session_id":"s-GW3YSGSZ","command":"start_turn","status":"accepted","message":"turn admitted","response":{"turn_id":"turn-1U5SO19-KHY4SY503B","queue_depth":0},"message_id":"command-1U5SO19-DFKDHVX7KL","sequence":1}},"session_id":"s-GW3YSGSZ"}
{"sequence":7,…"event":{"type":"turn.assistant_message_completed"…"type":"session_stream_event"},"cursor":9,"durable":true}{"sequence":7,"session_id":"s-GW3YSGSZ","payload":{"frame":{"seq":9,"session_id":"s-GW3YSGSZ","turn_id":"turn-1U5SO19-KHY4SY503B","event":{"type":"turn.assistant_message_completed","payload":{"role":"assistant","message":{"role":"assistant","content":"pong"}},"metadata":{"event_id":"event-1U5SO19-8SQB2KSYCH","log_position":9,"turn_id":"turn-1U5SO19-KHY4SY503B","command_id":"command-1U5SO19-DFKDHVX7KL","occurred_at":"2026-10-09T02:53:33.950Z"}}},"type":"session_stream_event"},"cursor":9,"durable":true}
{"sequence":8,…"event":{"type":"turn.usage"…"type":"session_stream_event"},"cursor":10,"durable":true}{"sequence":8,"session_id":"s-GW3YSGSZ","payload":{"frame":{"seq":10,"session_id":"s-GW3YSGSZ","turn_id":"turn-1U5SO19-KHY4SY503B","event":{"type":"turn.usage","payload":{"input-tokens":0,"output-tokens":8,"cached-input-tokens":940,"total-tokens":948,"cost_known":false,"cost_usd":0.0,"finish-reason"…192 characters…t-1U5SO19-2LCDPPIEOV","log_position":10,"turn_id":"turn-1U5SO19-KHY4SY503B","command_id":"command-1U5SO19-DFKDHVX7KL","occurred_at":"2026-10-09T02:53:33.952Z"}}},"type":"session_stream_event"},"cursor":10,"durable":true}
{"sequence":9,…"event":{"type":"turn.completed"…"type":"session_stream_event"},"cursor":11,"durable":true}{"sequence":9,"session_id":"s-GW3YSGSZ","payload":{"frame":{"seq":11,"session_id":"s-GW3YSGSZ","turn_id":"turn-1U5SO19-KHY4SY503B","event":{"type":"turn.completed","payload":{"turn-number":1,"message-count":2},"metadata":{"event_id":"event-1U5SO19-VFATPLPM63","log_position":11,"turn_id":"turn-1U5SO19-KHY4SY503B","command_id":"command-1U5SO19-DFKDHVX7KL","occurred_at":"2026-10-09T02:53:33.954Z"}}},"type":"session_stream_event"},"cursor":11,"durable":true}
One line in, thirteen lines out. The command's result came at 0.12 s, the turn's text at 0.81 s.
Reading the port from the store's .owner file and doing the WebSocket handshake yourself
The challenge, the operator token, the session and the subscription are what rpc does for you.
Instead: Spawn nodecode rpc and write commands.
nodecode rpc serve
Exit 2: rpc is a command of its own: nodecode [-p NAME] rpc [SESSION-ID [--cursor N]] [--store PATH | --ephemeral]
Instead: Run nodecode serve, or nodecode gateway on, by itself. nodecode rpc attaches to it.
Spawning one nodecode rpc per prompt
With no organism running, each one starts an organism and stops it when its stdin ends. Every start after a stop sends the model a "running again" note: 6 of the 20 model calls in the runs on this page.
Instead: Keep one nodecode rpc open for your program's life, or run nodecode gateway on so each one attaches.
Lines in
Each line is one command object. A line that names no command_id gets one, and a command that names no session_id goes to rpc's session. A line that is not a command gets , and the next line is read.
| Type | Takes | Does |
|---|---|---|
start_turn | request.prompt | Starts a turn. One already running queues it. |
steer_turn | request.prompt, request.expected_turn_id | The prompt runs at the running turn's next round boundary. |
cancel_turn | turn_id, retract | Stops the running turn. retract also takes it back when it produced nothing. |
withdraw_prompt | prompt_id | Takes a queued prompt back. |
interrupt_exec | exec_id | Stops a background evaluation. |
navigate_checkpoint | target_turn_id or direction | Moves the session's head. Every client is told to subscribe again. |
get_state | nothing | The session as it stands, in the result. |
set_session_subscriptions | subscriptions | The sessions this client follows. |
{"sequence":2,…"event":{"type":"session.created"…"type":"session_stream_event"},"cursor":43,"durable":true}{"sequence":2,"session_id":"s-LINES","payload":{"frame":{"seq":43,"session_id":"s-LINES","turn_id":false,"event":{"type":"session.created","payload":{"id":"s-LINES","cwd":"/home/you/project","parent":false,"created-at":"2026-10-09T02:53:40.704Z"},"metadata":{"event_id":"event-1U5SO1G-KBPC0G11T5","log_position":43,"turn_id":false,"command_id":"command-1U5SO1G-HG053PED2F","occurred_at":"2026-10-09T02:53:40.704Z"}}},"type":"session_stream_event"},"cursor":43,"durable":true}
{"sequence":3,…"event":{"type":"turn.input_committed"…"type":"session_stream_event"},"cursor":44,"durable":true}{"sequence":3,"session_id":"s-LINES","payload":{"frame":{"seq":44,"session_id":"s-LINES","turn_id":"turn-1U5SO1G-4W89TJM6HX","event":{"type":"turn.input_committed","payload":{"role":"user","message":"say pong","prompt-id":"command-1U5SO1G-D5YKUGNF62","sequence":1,"disposition":"started"},"metadata":{"event_id":"event-1U5SO1G-DQDU9HH7V3","log_position":44,"turn_id":"turn-1U5SO1G-4W89TJM6HX","command_id":"command-1U5SO1G-D5YKUGNF62","occurred_at":"2026-10-09T02:53:40.705Z"}}},"type":"session_stream_event"},"cursor":44,"durable":true}
{"sequence":4,…"event":{"type":"turn.started"…"type":"session_stream_event"},"cursor":45,"durable":true}{"sequence":4,"session_id":"s-LINES","payload":{"frame":{"seq":45,"session_id":"s-LINES","turn_id":"turn-1U5SO1G-4W89TJM6HX","event":{"type":"turn.started","payload":{"input":"say pong"},"metadata":{"event_id":"event-1U5SO1G-KXBB7XVR6V","log_position":45,"turn_id":"turn-1U5SO1G-4W89TJM6HX","command_id":"command-1U5SO1G-D5YKUGNF62","occurred_at":"2026-10-09T02:53:40.705Z"}}},"type":"session_stream_event"},"cursor":45,"durable":true}
{"sequence":0,"payload":{"type":"gateway_turn_command_result"…"command":"start_turn","status":"accepted","message":"turn admitted"…{"sequence":0,"payload":{"type":"gateway_turn_command_result","result":{"command_id":"command-1U5SO1G-D5YKUGNF62","correlation_id":"command-1U5SO1G-D5YKUGNF62","session_id":"s-LINES","command":"start_turn","status":"accepted","message":"turn admitted","response":{"turn_id":"turn-1U5SO1G-4W89TJM6HX","queue_depth":0},"message_id":"command-1U5SO1G-D5YKUGNF62","sequence":1}},"session_id":"s-LINES"}
{"sequence":7,…"event":{"type":"turn.assistant_message_completed"…"type":"session_stream_event"},"cursor":50,"durable":true}{"sequence":7,"session_id":"s-LINES","payload":{"frame":{"seq":50,"session_id":"s-LINES","turn_id":"turn-1U5SO1G-4W89TJM6HX","event":{"type":"turn.assistant_message_completed","payload":{"role":"assistant","message":{"role":"assistant","content":"pong"}},"metadata":{"event_id":"event-1U5SO1H-CULFDF3HVM","log_position":50,"turn_id":"turn-1U5SO1G-4W89TJM6HX","command_id":"command-1U5SO1G-D5YKUGNF62","occurred_at":"2026-10-09T02:53:41.399Z"}}},"type":"session_stream_event"},"cursor":50,"durable":true}
{"sequence":8,…"event":{"type":"turn.usage"…"type":"session_stream_event"},"cursor":51,"durable":true}{"sequence":8,"session_id":"s-LINES","payload":{"frame":{"seq":51,"session_id":"s-LINES","turn_id":"turn-1U5SO1G-4W89TJM6HX","event":{"type":"turn.usage","payload":{"input-tokens":0,"output-tokens":8,"cached-input-tokens":940,"total-tokens":948,"cost_known":false,"cost_usd":0.0,"finish-reason":"stop…186 characters…t-1U5SO1H-YIUWCGCZ8E","log_position":51,"turn_id":"turn-1U5SO1G-4W89TJM6HX","command_id":"command-1U5SO1G-D5YKUGNF62","occurred_at":"2026-10-09T02:53:41.401Z"}}},"type":"session_stream_event"},"cursor":51,"durable":true}
{"sequence":9,…"event":{"type":"turn.completed"…"type":"session_stream_event"},"cursor":52,"durable":true}{"sequence":9,"session_id":"s-LINES","payload":{"frame":{"seq":52,"session_id":"s-LINES","turn_id":"turn-1U5SO1G-4W89TJM6HX","event":{"type":"turn.completed","payload":{"turn-number":1,"message-count":2},"metadata":{"event_id":"event-1U5SO1H-JYVW3AHNT","log_position":52,"turn_id":"turn-1U5SO1G-4W89TJM6HX","command_id":"command-1U5SO1G-D5YKUGNF62","occurred_at":"2026-10-09T02:53:41.404Z"}}},"type":"session_stream_event"},"cursor":52,"durable":true}
Three wrong lines, three refusals, and the fourth line ran.
cancel_turn takes turn_id beside type. Under request it is refused, and the turn keeps streaming.
A second start_turn waits behind the first. steer_turn reaches the running turn at its next round boundary.
Writing the prompt as text
invalid JSON: malformed JSON at byte 0: #\s begins no value
Instead: {"type":"start_turn","request":{"prompt":"say pong"}}
Putting prompt beside type
request must be an object
Instead: The prompt goes under request.
Leaving out type
type must be a non-empty string
Instead: Every line names its type.
Steering without expected_turn_id
Rejected: session_id, expected_turn_id, and non-empty prompt are required
Instead: Send the turn_id from your start_turn result.
Lines out
Each line is one frame, exactly as the gateway sent it. A turn ends with , turn.failed or turn.cancelled.
| Frame | Is |
|---|---|
Always first. The session's replay, in accumulated_frames. | |
A fact as it lands. It carries "durable":true and a cursor, its place in the log. | |
| Text or a tool call while it streams. No cursor. | |
A command's answer: accepted, queued or rejected, with the turn_id. | |
The organism's own frames. sequence 0 and no session. | |
sync_protocol_error | A line that is not a command. |
{"sequence":3,…"event":{"type":"turn.input_committed"…"type":"session_stream_event"},"cursor":24,"durable":true}{"sequence":3,"session_id":"s-DOCS","payload":{"frame":{"seq":24,"session_id":"s-DOCS","turn_id":"turn-1U5SO1A-E37X7WSI6","event":{"type":"turn.input_committed","payload":{"role":"user","message":"how many lisp files","prompt-id":"command-1U5SO1A-INEOFW90L2","sequence":1,"disposition":"started"},"metadata":{"event_id":"event-1U5SO1A-3Y4MN9JLPB","log_position":24,"turn_id":"turn-1U5SO1A-E37X7WSI6","command_id":"command-1U5SO1A-INEOFW90L2","occurred_at":"2026-10-09T02:53:34.915Z"}}},"type":"session_stream_event"},"cursor":24,"durable":true}
{"sequence":4,…"event":{"type":"turn.started"…"type":"session_stream_event"},"cursor":25,"durable":true}{"sequence":4,"session_id":"s-DOCS","payload":{"frame":{"seq":25,"session_id":"s-DOCS","turn_id":"turn-1U5SO1A-E37X7WSI6","event":{"type":"turn.started","payload":{"input":"how many lisp files","parent-turn-id":"turn-1U5SO1A-2HJ0FRDIE2"},"metadata":{"event_id":"event-1U5SO1A-D49127X4RP","log_position":25,"turn_id":"turn-1U5SO1A-E37X7WSI6","command_id":"command-1U5SO1A-INEOFW90L2","occurred_at":"2026-10-09T02:53:34.916Z"}}},"type":"session_stream_event"},"cursor":25,"durable":true}
{"sequence":0,"payload":{"type":"gateway_turn_command_result"…"command":"start_turn","status":"accepted","message":"turn admitted"…{"sequence":0,"payload":{"type":"gateway_turn_command_result","result":{"command_id":"command-1U5SO1A-INEOFW90L2","correlation_id":"command-1U5SO1A-INEOFW90L2","session_id":"s-DOCS","command":"start_turn","status":"accepted","message":"turn admitted","response":{"turn_id":"turn-1U5SO1A-E37X7WSI6","queue_depth":0},"message_id":"command-1U5SO1A-INEOFW90L2","sequence":1}},"session_id":"s-DOCS"}
{"sequence":16,…"event":{"type":"turn.assistant_message_completed"…"type":"function"…"type":"session_stream_event"},"cursor":28,"durable":true}{"sequence":16,"session_id":"s-DOCS","payload":{"frame":{"seq":28,"session_id":"s-DOCS","turn_id":"turn-1U5SO1A-E37X7WSI6","event":{"type":"turn.assistant_message_completed","payload":{"role":"assistant","message":{"role":"assistant","content":null,"tool_calls":[{"id":"call_ec27431c907f415a8c40","ty…146 characters…nt-1U5SO1B-2G2BBRJOZP","log_position":28,"turn_id":"turn-1U5SO1A-E37X7WSI6","command_id":"command-1U5SO1A-INEOFW90L2","occurred_at":"2026-10-09T02:53:35.959Z"}}},"type":"session_stream_event"},"cursor":28,"durable":true}
{"sequence":17,…"event":{"type":"turn.usage"…"type":"session_stream_event"},"cursor":29,"durable":true}{"sequence":17,"session_id":"s-DOCS","payload":{"frame":{"seq":29,"session_id":"s-DOCS","turn_id":"turn-1U5SO1A-E37X7WSI6","event":{"type":"turn.usage","payload":{"input-tokens":740,"output-tokens":14,"cached-input-tokens":226,"total-tokens":980,"cost_known":false,"cost_usd":0.0,"finish-reason":"too…192 characters…nt-1U5SO1B-X4RWS89GB3","log_position":29,"turn_id":"turn-1U5SO1A-E37X7WSI6","command_id":"command-1U5SO1A-INEOFW90L2","occurred_at":"2026-10-09T02:53:35.960Z"}}},"type":"session_stream_event"},"cursor":29,"durable":true}
{"sequence":18,…"event":{"type":"turn.tool_call_started"…"type":"session_stream_event"},"cursor":30,"durable":true}{"sequence":18,"session_id":"s-DOCS","payload":{"frame":{"seq":30,"session_id":"s-DOCS","turn_id":"turn-1U5SO1A-E37X7WSI6","event":{"type":"turn.tool_call_started","payload":{"call-id":"call_ec27431c907f415a8c40","tool-name":"eval","arguments":"{\"form\": \"(length (directory \\\"src/**/*.lisp\\\"))\"}"},"metadata":{"event_id":"event-1U5SO1B-Y4B15O9AQZ","log_position":30,"turn_id":"turn-1U5SO1A-E37X7WSI6","command_id":"command-1U5SO1A-INEOFW90L2","occurred_at":"2026-10-09T02:53:35.962Z"}}},"type":"session_stream_event"},"cursor":30,"durable":true}
{"sequence":19,…"event":{"type":"turn.tool_result"…"type":"session_stream_event"},"cursor":31,"durable":true}{"sequence":19,"session_id":"s-DOCS","payload":{"frame":{"seq":31,"session_id":"s-DOCS","turn_id":"turn-1U5SO1A-E37X7WSI6","event":{"type":"turn.tool_result","payload":{"call-id":"call_ec27431c907f415a8c40","tool-name":"eval","result":"3","duration-ms":37,"failed":false},"metadata":{"event_id":"event-1U5SO1C-8NX8NVLEJ6","log_position":31,"turn_id":"turn-1U5SO1A-E37X7WSI6","command_id":"command-1U5SO1A-INEOFW90L2","occurred_at":"2026-10-09T02:53:36.007Z"}}},"type":"session_stream_event"},"cursor":31,"durable":true}
{"sequence":20,…"exit_code":0},"type":"session_background_process_updated"}}{"sequence":20,"session_id":"s-DOCS","payload":{"session_id":"s-DOCS","process":{"shell_session_id":1000,"tool_call_id":"call_ec27431c907f415a8c40","command":"(length (directory \"src/**/*.lisp\"))","status":"exited","output_b64":"","offset":0,"exit_code":0},"type":"session_background_process_updated"}}
{"sequence":33,…"event":{"type":"turn.assistant_message_completed"…"type":"session_stream_event"},"cursor":34,"durable":true}{"sequence":33,"session_id":"s-DOCS","payload":{"frame":{"seq":34,"session_id":"s-DOCS","turn_id":"turn-1U5SO1A-E37X7WSI6","event":{"type":"turn.assistant_message_completed","payload":{"role":"assistant","message":{"role":"assistant","content":"There are 3 Lisp files under src/."}},"metadata":{"event_id":"event-1U5SO1C-SRRGVGMD65","log_position":34,"turn_id":"turn-1U5SO1A-E37X7WSI6","command_id":"command-1U5SO1A-INEOFW90L2","occurred_at":"2026-10-09T02:53:36.568Z"}}},"type":"session_stream_event"},"cursor":34,"durable":true}
{"sequence":34,…"event":{"type":"turn.usage"…"type":"session_stream_event"},"cursor":35,"durable":true}{"sequence":34,"session_id":"s-DOCS","payload":{"frame":{"seq":35,"session_id":"s-DOCS","turn_id":"turn-1U5SO1A-E37X7WSI6","event":{"type":"turn.usage","payload":{"input-tokens":87,"output-tokens":10,"cached-input-tokens":966,"total-tokens":1063,"cost_known":false,"cost_usd":0.0,"finish-reason":"sto…186 characters…nt-1U5SO1C-FSPCTWEG8I","log_position":35,"turn_id":"turn-1U5SO1A-E37X7WSI6","command_id":"command-1U5SO1A-INEOFW90L2","occurred_at":"2026-10-09T02:53:36.568Z"}}},"type":"session_stream_event"},"cursor":35,"durable":true}
{"sequence":35,…"event":{"type":"turn.completed"…"type":"session_stream_event"},"cursor":36,"durable":true}{"sequence":35,"session_id":"s-DOCS","payload":{"frame":{"seq":36,"session_id":"s-DOCS","turn_id":"turn-1U5SO1A-E37X7WSI6","event":{"type":"turn.completed","payload":{"turn-number":2,"message-count":6},"metadata":{"event_id":"event-1U5SO1C-9KUUK9H47E","log_position":36,"turn_id":"turn-1U5SO1A-E37X7WSI6","command_id":"command-1U5SO1A-INEOFW90L2","occurred_at":"2026-10-09T02:53:36.569Z"}}},"type":"session_stream_event"},"cursor":36,"durable":true}
A second turn on a named session, with one evaluation. The replay holds the first turn, its turn.completed included.
The replay carries the last turn's turn.completed. Wait for the end whose turn_id is the one your start_turn result carried.
Taking accepted for the answer
turn admitted came at 0.11 s. The answer's first word came at 1.50 s.
Instead: Read on to the turn's own turn.completed.
Keeping item_delta text as the answer
Deltas are not facts. They have no cursor, and a resume does not send them again.
Instead: The answer is in turn.assistant_message_completed.
Reading sequence as a place in the log
sequence counts the frames sent to this client, and it is 0 on the organism's own frames.
Instead: The place in the log is cursor.
Ending
| When | rpc | The organism |
|---|---|---|
| stdin ends | Exits 0 | Stops if rpc started it, and a running turn stops with it. Keeps running if it was already serving. |
| The gateway ends | Exits 1, why on stderr | Gone. |
| A bad argument | Exits 2 | Never started. |
Closing stdin stops the organism rpc started, and the turn with it. The next start picks the turn up. Close stdin after your turn's end.
Attached to a nodecode serve, which was then stopped.
Reading exit 0 as "the turn finished"
Exit 0 means stdin ended. It says nothing about any turn.
Instead: The turn's end is a frame: turn.completed, turn.failed or turn.cancelled.
Expecting rpc's exit to stop a nodecode serve it attached to
An organism that was already serving keeps running, and so does its turn.
Instead: Stop it where you started it, or with nodecode gateway off.
Resume
Name the session and the newest you read. The replay then carries only what landed past it, and says .
nodecode rpc s-DOCS --cursor 22
{"sequence":0,"payload":{"type":"gateway_turn_command_result"…"command":"get_state","status":"accepted","message":"session state"…{"sequence":0,"payload":{"type":"gateway_turn_command_result","result":{"command_id":"command-1U5SO1D-9721LB40BB","correlation_id":"command-1U5SO1D-9721LB40BB","session_id":"s-DOCS","command":"get_state","status":"accepted","message":"session state","response":{"queue_depth":0,"session":{"session_id…287 characters…axolotl-cyber"},"pin":{"provider":"nodecode","model":"nodecode-axolotl-cyber"},"effort":"max","efforts":["off","minimal","low","medium","high","xhigh","max"],"refusal":null},"pending_prompts":[]}}},"session_id":"s-DOCS"}
Nine facts past 22: the second turn alone. Without --cursor, the same session replays all fifteen.
| You run | You get |
|---|---|
rpc SESSION-ID --cursor N | resumed_after N and the facts past N. Add them to what you hold. |
rpc SESSION-ID | The whole replay, no resumed_after. Replace what you hold. |
--cursor past the log, or the head moved since | The whole replay, no resumed_after. |
rpc | A fresh session and an empty replay. |
--cursor takes a frame's cursor. A sequence number resumes from far back and sends what you already hold.
With no session id you get a new, empty session. Pass the session_id from the first frame.
Adding every replay to what you hold
With no resumed_after, the replay is whole: --cursor 9999 got all fifteen facts.
Instead: Replace your copy when resumed_after is absent.
nodecode rpc --cursor 5
Exit 2: --cursor resumes a session past a log position: nodecode rpc SESSION-ID --cursor N
Instead: Name the session first.
--cursor five
Exit 2: --cursor takes a log position, not "five"
Instead: A whole number, from a frame's cursor.
get_state
{"type":"get_state"} answers with the session as it stands. It needs no subscription.
{
"queue_depth": 0,
"session": {
"session_id": "s-DOCS",
"cwd": "/home/you/project",
"parent": false,
"created_at": "2026-10-09T02:53:34.076Z"
},
"title": "say pong",
"admission_state": "ready",
"cursor": 36,
"target": {
"provider": "nodecode",
"model": "nodecode-axolotl-cyber",
"unconfigured": false,
"default": {
"provider": "nodecode",
"model": "nodecode-axolotl-cyber"
},
"pin": {
"provider": "nodecode",
"model": "nodecode-axolotl-cyber"
},
"effort": "max",
"efforts": [
"off",
"minimal",
"low",
"medium",
"high",
"xhigh",
"max"
],
"refusal": null
},
"pending_prompts": []
}
| Field | Is |
|---|---|
turn_id | The running turn. Absent when none runs. |
queue_depth | Prompts waiting behind it. |
admission_state | ready or active. |
cursor | The newest place in the log: the one to resume from. |
target | The provider, model and effort the next turn uses. |
pending_prompts | The queued prompts. |
The schema
Every command and every frame, both ways, is src/src/wire/protocol.schema.json, JSON Schema 2020-12. Of the 596 JSON lines the runs behind this page sent and got back, 591 check against it. The other five are wrong commands sent on purpose. Check yours before you send them.
See Troubleshooting for a line you got, and The gateway for keeping an organism running.