| register / registered | The first envelope frame must be register; the leader answers registered with ready: true and a leader_binary_version at least the client version, or the TUI evicts and respawns its own leader. A non-register first frame gets envelope error 1, a second registration error 2, and a 30 s registration timeout error 3. |
| ping / pong | Keepalive pair exchanged every 30 s. |
| initialize | Advertises protocol version 1 and the xai.api_key auth method (the pager fails closed on an empty list), plus the persisted model catalog in _meta.modelState. Remote catalog discovery runs afterward and broadcasts an update, so endpoint latency never blocks startup. |
| authenticate | No-op because credentials belong to the harness-side providers; the advertised compatibility method only satisfies the pager's auth gate. |
| session/new | Creates a fresh agent with an absolute cwd; mcpServers must be an empty array (any non-array or non-empty value rejects). _meta.sessionId pins the session id. Permission modes default, workspace-write, plan, bypassPermissions, and always-approve map to dsh's permission/plan services; an explicit mode wins over _meta.yoloMode. Modes or CLI metadata the bridge cannot enforce (auto, acceptEdits, dontAsk, confining sandbox/tool/rule overrides, --no-subagents, and similar) reject instead of silently weakening the launch. sandbox=off and its none alias are accepted because they match the external dsh leader's actual unconfined execution. _meta.agentProfile (a string preset id) or the dsh-native _meta.agentPreset resolves through the preset roster and is recorded as meta.agentPreset; absent either, the roster default composes. Inline JSON agent definitions reject. |
| session/prompt | Flattens text and resource-link blocks, permits one in-flight request per session, echoes a user_message_chunk for the accepted prompt, then settles at the correlated turn end with the grok stopReason vocabulary; a turnless admission settles cancelled. |
| session/cancel | Cancels the addressed agent and settles its pending prompt as cancelled; unknown ids are no-ops. |
| session/update | Streams user_message_chunk, agent_message_chunk, agent_thought_chunk, tool_call, and tool_call_update notifications with per-session eventSeq and promptId stamps. |
| session/load | Validates cwd/mcpServers and CLI metadata like session/new, then resumes the durable session. Interactive loads replay the transcript as isReplay updates; _meta.noReplay: true rebuilds state without emitting prior text for headless output. Only the owning client may reload a live session. The latest durable preset and model selections win; a preset may change only before model-visible history exists. |
| session/list | Lists persisted session headers. |
| session/set_model | Switches the live selection, appends a durable session event, and saves the default for new sessions through agentDefaultModel. Provider and effort memory are keyed by the exact provider/model route. A modelId outside the catalog rejects; unsupported saved efforts are dropped instead of reaching the provider. |
| session/set_mode | Maps plan to the selected preset's plan-mode service and all other ids to leaving plan mode; rejects when that service is not present. |
| session/close | Cancels, flushes through ctx.sessions, and disposes the session. |
| session/request_permission | Offers one-shot allow/reject choices for bridge-owned approval requests; YOLO sessions pre-approve without a roundtrip. |
| x.ai/models/list | Returns the current provider catalog as grok SessionModelState and schedules non-blocking discovery for compatible custom routes. Recognized /models reasoning extensions are persisted as pi-ai reasoningEfforts; selectors then expose only the exact model's declared levels. |
| x.ai/providers/add | Writes one provider route into the dsh settings document through the official settings seam (ctx.settings.mutate on the llm-pi-ai namespace); refuses duplicate ids; fills a non-catalog route's models from gateway discovery. Returns the refreshed roster and broadcasts the new catalog. |
| x.ai/providers/update | Merges the form fields over one route's user profile (empty fields unset, models preserved) through the same settings seam. Returns the refreshed roster and broadcasts the new catalog. |
| x.ai/providers/remove | Unsets one provider route through the settings seam; refuses the provider that owns the current model. Returns the refreshed roster and broadcasts the new catalog. |
| x.ai/commands/list | Returns the built-in bridge commands plus commands registered by the live session's plugin composition. A supplied session id must belong to the caller. |
| x.ai/session/list | Session-picker and dashboard list over persisted headers and logs (cwd/query/limit filters, durable title and firstPrompt projection, latest-event ordering, rows tagged chat-kind so the TUI bypasses its local-store gate and loads via session/load). |
| notification wire form | Every extension notification (x.ai/) rides the wire with the ACP '_' prefix (_x.ai/queue/changed, _x.ai/session/prompt_complete, …): the pager's agent-client-protocol decode strips the prefix before dispatching to its x.ai/ handlers and silently drops unprefixed unknown methods as method_not_found. session/update is the sole typed (unprefixed) notification. |
| x.ai/queue/changed | Broadcast on every queue mutation: pending rows (id, version, kind, text, position) plus the running prompt (runningPromptId/runningText/runningKind). Each snapshot carries a strictly increasing seq (epoch-seeded, so a restarted leader outranks its predecessor); the TUI drops any snapshot whose seq is not strictly newer for the session and adopts current_prompt_id from the applied ones. |
| x.ai/queue/interject, /remove, /reorder, /clear | Queue edit notifications. interject is grok send-now: the row jumps to front, the running turn is cancelled (prompt_complete carries cancelTrigger=send_now) and the row runs next. remove (running row falls back to cancel), reorder by orderedIds, clear. |
| x.ai/queue/steer | Queue-row steering: atomically removes a still-pending queued row and merges its text into the running turn WITHOUT cancelling it. The row's RPC settles with the host turn's stop reason; the authoritative x.ai/queue/changed rebroadcast is the source of truth. If no turn is running, the row stays queued (benign no-op + resync). |
| x.ai/session/prompt_complete | Terminal signal per settled turn (stopReason, promptId, optional cancelTrigger/cancellationCategory); emitted before the queue broadcast so the pager finalizes and reconciles the turn. The session/prompt RPC result carries the same attribution in _meta (sessionId, promptId), so the pager never has to infer which queue row a settle response belongs to. |
| combine | grok ui.combine_queued_prompts parity: with 2+ plain queued prompts, followers fold into the front (text joined with blank lines, runningCombinedTexts broadcast, followers settle cancelled). Config combineQueuedPrompts or env DSCODE_COMBINE_QUEUED=1; default off. |
| follow-up steer | With followUpBehavior=steer (default queue) — or per prompt via session/prompt _meta.followUp: 'steer' | 'queue' — a prompt arriving while a turn is in flight is folded into that turn at the harness's next step boundary: its queue row is broadcast once (the pager's optimistic echo retires by id) and then leaves the queue, its text streams as a user echo inside the live turn, and its RPC settles with the host turn's stop reason (own promptId in _meta, no separate prompt_complete). An idle session runs the prompt as its own turn as usual. |
| x.ai/interject | Mid-turn interjection (the pager's Alt+Enter steer chord and plan review comments): merges the text into the running turn at the harness's next step boundary WITHOUT cancelling it, then broadcasts x.ai/session/interjection (sessionId, text, interjectionId) — the originator dedups by id, other panes render the block. An idle session's steering wakes a turn of its own. |
| send now | session/prompt with _meta.sendNow: true (the pager's Ctrl+Enter chord) cancels the running turn (prompt_complete carries cancelTrigger=send_now, suppressing the cancelled marker) and runs this prompt next, ahead of the queue — the composer twin of x.ai/queue/interject. |
| other methods | Unknown requests get JSON-RPC -32601; unknown notifications are dropped with a warning. |