The zidane-server wire protocol, with the WebSocket upgrade, the ipc.hello handshake, every JSON-RPC method and ipc.signal kind, errors, resume and paging, and captured examples.
Protocol version 16 is JSON-RPC 2.0 over one WebSocket, with one message per text frame. The client sends ipc.hello first, then requests. The server answers them and pushes ipc.signal notifications.
The tables come from src/ipc/protocol.ts and src/chat/host/signals.ts. The JSON examples come from a real server run with a scripted provider. The local daemon speaks the same protocol over a unix socket. zidane/ipc and zidane/ipc/remote type it for TypeScript clients.
POST /zidane/pair trades a pairing code for a token (pairing). GET /zidane/media serves a workspace's images, videos and audio to a page that plays them by address, under the ticket its connection registered (files.mediaTicket, below). GET /zidane/oauth/callback takes a browser client's MCP sign-in back (auth.oauth.begin, below). With the web app on, every other plain GET serves the app; upgrades on any path still reach the WebSocket, so the app connects to wss://<host>/.
DescriptionThe oldest version the client can speak down to (IPC_MIN_PROTOCOL_VERSION). A zidane-server accepts when the ranges overlap. Absent: protocolVersion only. Additive.
appVersion
Typestring
DescriptionClient's zidane version; surfaced in daemon diagnostics.
pid
Typenumber
DescriptionProcess id of the client.
buildId?
Typestring
DescriptionBuild fingerprint (module mtime; 'unknown' in compiled binaries). When BOTH sides report a real id and they differ, the daemon rejects the handshake like a protocol-version mismatch; the client drains it and respawns. Closes same-version code drift during development.
codeVersion?
Typestring
DescriptionVersion of the zidane code the client runs (ZIDANE_VERSION, inlined at build). Unlike buildId this survives compiled binaries, so it closes the gap released builds had: same protocol version, older code. A client STRICTLY NEWER than the daemon is rejected like a build mismatch and the stale daemon is drained; an older client is accepted and degrades via optional().
DescriptionThe oldest version the host still speaks (IPC_MIN_PROTOCOL_VERSION). Additive.
negotiatedProtocolVersion?
Typenumber
DescriptionThe version this connection speaks: the lower of the client's and the host's. Additive: absent, the connection speaks protocolVersion.
scope?
TypeClientScope
DescriptionThe client scope this connection's token grants (./scopes): calls above it are refused. Absent: every method (a local window). Additive.
methods?
TypeIpcMethodName[]
DescriptionThe methods this connection may call on this host: the ones it handles, within scope. Clients show what is offered instead of failing on what isn't. Additive.
appVersion
Typestring
Descriptionzidane version of the host.
pid
Typenumber
DescriptionProcess id of the host.
startedAt
Typenumber
DescriptionStart time of the host process, epoch ms.
buildId?
Typestring
DescriptionBuild fingerprint of the host code. 'unknown' in compiled binaries.
codeVersion?
Typestring
DescriptionVersion of the zidane code the host runs.
hostId?
Typestring
DescriptionHost identity (additive). hostId is a UUID persisted once in the host's data dir, so it survives restarts; the in-process host and the local daemon share the data dir, and so the id: they are the same computer.
hostKind?
TypeHostKind
DescriptionWhat kind of host this is.
hostName?
Typestring
DescriptionDisplay name of the host.
retiring?
Typeboolean
DescriptionThe daemon is older than a client that attached while it had active work: it accepted the handshake instead of draining (which would abort those runs) and exits once idle. Clients attach normally; their reconnect path lands on a fresh daemon after the exit.
signalEpoch?
Typestring
DescriptionNames this host process's signal numbering (SIGNAL_SEQ_FIELD): a position from another epoch cannot be resumed. Additive.
machineServe?
Typeboolean
DescriptionThis server lends itself as a machine to the hosts of its clients (machine.attach, allowAsMachine on). Absent: it doesn't. Additive.
adminCommands?
Type{ token: string, pair: string }
DescriptionHow to get an admin token on this zidane-server: the commands to run on its machine, with its own binary, user and data dir (<device> is the name to fill in). token prints a token to paste into an app; pair prints a code for a browser. Absent: not a zidane-server. Additive.
remoteInstalls?
Typeboolean
DescriptionThis server takes installs and removals from its clients (catalog.install / remove / update, mcp.upsert / remove; allowRemoteInstalls on). Absent: it doesn't (or predates them). Additive.
clone?
Typeboolean
DescriptionClients may clone repositories into its workspace roots (git.clone). A zidane-server's allowClone; a local host always does. Absent: an older host, where git.clone needs an admin token. Additive.
createFolders?
Typeboolean
DescriptionClients may create folders in its workspace roots (fs.mkdir). A zidane-server's allowCreateFolders; a local host always does. Absent: an older host, without fs.mkdir. Additive.
homeDir?
Typestring
DescriptionThe host process's home folder (os.homedir()). Clients show it as ~ in the paths they display; nothing else reads it. Absent: an older host. Additive.
sync?
Typeboolean
DescriptionThis server takes settings sync from a client's computer (sync.*). Absent: it doesn't. Additive.
syncCategories?
TypeSyncCategory[]
DescriptionThe sync categories it takes. Absent with sync: the ones before environments. Additive.
projectTerminals?
Typetrue
DescriptionThis host runs terminals without a session (terminal.openInProject and the other project / draft terminal methods). Absent: sessions only. Additive.
activeWork?
Typeboolean
Descriptiondaemon.info only: a run, compaction, / command or background task is in flight on this host (open terminals do not count). zidane server wait-idle waits for false before a restart. Additive.
remoteInstalls, sync, machineServe and projectTerminals say what this server offers. An absent field means no. clone and createFolders say whether clients may clone into the workspace roots and create folders there (allowClone, allowCreateFolders); an older server leaves them out. methods lists what this connection may call: the server's methods within the token's scope (Scopes). A client shows what it lists instead of failing on the rest. hostId stays the same across restarts. A client that saved the server checks it on every connect and refuses another server at the same URL. signalEpoch names this server process for resume. adminCommands ({ token, pair }) are the commands that mint an admin token or an admin pairing code, run on the server's machine with its binary, its user and its data dir. The apps show them to a chat token.
Each side speaks a range of versions, from its minProtocolVersion to its protocolVersion. A server accepts a client whose range overlaps its own, and the connection speaks the higher version both share (negotiatedProtocolVersion in the result). A client that sends no minProtocolVersion speaks its protocolVersion only. A release keeps the previous version in its range when it raises the current one, so apps built against one release keep working against the next. Ranges that don't overlap get VersionMismatch, with the server's hello fields in data.daemon and the side to upgrade in the message:
JSON
{"jsonrpc": "2.0","id": 2,"error": {"code": -32010,"message": "Protocol version mismatch: the server speaks v13, the client v12. Upgrade the client.","data": {"daemon": {"protocolVersion": 13,"appVersion": "docs","pid": 28973,"startedAt": 1791968973803,"buildId": "1791968503753","codeVersion": "8.0.4","hostId": "08b260f9-090c-445b-957a-1b6f4822f245","hostKind": "server","hostName": "docs-box"} } }}
Within a shared version, the server ignores buildId and codeVersion, so older and newer clients attach. Only breaking changes to the method map or the signal union bump the version.
New methods and fields arrive without a bump. A client treats MethodNotFound (-32601) as "not offered". daemon.shutdown does nothing on a server. No client can drain or restart one.
Before the handshake, the server answers only ipc.hello, $/ping, daemon.info and daemon.shutdown:
Every method takes an object as params and answers with a result or an error. A call without an id runs as a notification. The server sends no answer and drops errors. Drafts use notifications for every keystroke.
The server pushes host events as ipc.signal notifications whose params are the signal, kind first. A session signal also carries $seq, its number in that session (from 1, without gaps, within one server process). Signals without a session, such as presence:changed, have none.
The run above, in order: run:start, plans:snapshot, prompt-turns, one event per streamed piece, stream:progress, turn:end, run:end.
Most signals reach every connection. Streamed command output (workspace:exec:data, workspace:exec:exit) goes only to the connection that started the command. A client ignores unknown kinds, because new kinds arrive without a version bump.
Signal kinds
Kind
Description
run:start
DescriptionA run started in the session.Params { kind: 'run:start', sessionId: string, runId: string, startedAt?: number }
run:end
DescriptiontakenOver: another process claimed the run, which goes on there (error says so). Optional: older clients show error.Params { kind: 'run:end', sessionId: string, runId: string, ok: boolean, error?: string, detail?: RunErrorDetail, background?: true, takenOver?: true }
turn:end
DescriptionA turn finished. usage carries the loop-reported token/cost figures that drive footer gauges (context size = prompt-side tokens of the LAST parent turn; cost accrues across parent + child turns). A parent turn's runOutputTokens is its run's output so far, this turn included: a run readout takes it as is instead of adding turns up, so a window that read the count mid-run never counts a turn twice.Params { kind: 'turn:end', sessionId: string, turnId: string, childId?: string, depth?: number, usage?: TurnUsage, runOutputTokens?: number }
event
Descriptionecho: true marks host-generated SEND/STEER echoes of the user's own message. Clients that already render the prompt locally (the GUI's enriched append) drop echo-tagged signals; command-module user-prompts are never echoes and always render.Params { kind: 'event', sessionId: string, event: StreamEvent, echo?: boolean }
compacting:start
DescriptionCompaction of the session's history started.Params { kind: 'compacting:start', sessionId: string }
compacting:progress
DescriptionLive token estimate for an in-flight compaction summary. Throttled by the loop, so this is a low-rate progress tick rather than a stream. Without it a daemon-mode window shows a static "Compacting…" with no indication of progress; a compaction of a large transcript can run for minutes, which is indistinguishable from a hang.Params { kind: 'compacting:progress', sessionId: string, estOutputTokens: number }
stream:progress
DescriptionLive counters for the parent turn currently streaming; the loop's stream:progress (throttled ~4/s, one final tick before stream:end). outputTokens is provider-counted unless estimated; estCostUsd is the running catalog-rate estimate for THIS turn (absent for unpriced models and flat-rate subscription traffic). Clients add it to the settled session figure while streaming and drop it when the matching turn:end brings the real usage.cost.Params ({ kind: 'stream:progress', sessionId: string } & StreamProgressInfo)
prompt-turns
DescriptionPrompt turns that just persisted, reduced to the fields needed to bind a live user-prompt event to its turn id (see PromptTurnRef). Deliberately NOT the full SessionTurn: those carry every content block, including base64 image/document payloads, which would be megabytes per prompt to ship for the sake of an id. Without this a prompt sent from a daemon-attached window is unselectable; no hover, edit, or delete; until the run-end transcript replace.Params { kind: 'prompt-turns', sessionId: string, refs: readonly PromptTurnRef[] }
compacting:end
DescriptioneffectiveTokens (success only) is the loop's post-compact context estimate; windows drop their footer ctx gauge to it immediately instead of waiting for the next turn's usage.Params { kind: 'compacting:end', sessionId: string, ok: boolean, effectiveTokens?: number }
model:fallback
DescriptionThe run moved from one model to the next in the session's fallback chain.Params { kind: 'model:fallback', sessionId: string, from: { provider: string, model: string }, to: { provider: string, model: string }, discardTurnId?: string }
work:snapshot
DescriptionThe session's running work, as chat.listWork returns it, in full.Params { kind: 'work:snapshot', sessionId: string, items: RunningWorkItem[] }
plans:snapshot
DescriptionThe session's plans, in full, and the one worth a glance.Params { kind: 'plans:snapshot', sessionId: string, snapshot: PlansSnapshot }
artifact:recorded
DescriptionThe session recorded an artifact (PR, branch, commit, file, extension kind; see session/artifacts.ts). Carries the stored row so a window can badge / list without a round-trip; sessions.artifacts is the authoritative query. Additive; older clients ignore unknown kinds.Params { kind: 'artifact:recorded', sessionId: string, artifact: SessionArtifact }
artifact:changed
DescriptionAn artifact was removed or refreshed through the host (artifacts.delete / artifacts.upsert); windows re-query. Carries the row for upsert.Params { kind: 'artifact:changed', sessionId: string, op: 'delete' | 'upsert', artifactId: string, artifact?: SessionArtifact }
interaction:request
DescriptionThe agent asked a question or proposed a plan and waits for an answer.Params { kind: 'interaction:request', sessionId: string, request: InteractionRequest, live: boolean }
interaction:resolved
DescriptionA pending question or plan was answered or withdrawn.Params { kind: 'interaction:resolved', sessionId: string, requestId: string, answeredBy?: InteractionAnswerer }
secrets:changed
DescriptionA project's secret store changed (a secret saved, revoked or expired in this process). Carries no names or values: a client lists again.Params { kind: 'secrets:changed', projectKey: string }Not numbered: no session.
browser:request
DescriptionDev browser (browser.ts hub): a tool call for the page, addressed to the registered browser host (hostId); other clients ignore it. The host answers through browser.respond. browser:cancel withdraws it.Params { kind: 'browser:request', sessionId: string, hostId: string, request: BrowserRequest }
DescriptionTerminals (terminal/ manager). changed carries the session's full list; output is a batch starting at offset (clients drop what they already have and terminal.ack what they wrote); reset replaces a view's content with history after a client fell too far behind.Params { kind: 'terminal:changed', sessionId: string, terminals: TerminalInfo[] }
terminal:output
DescriptionOutput of a session terminal, from offset.Params { kind: 'terminal:output', sessionId: string, terminalId: string, offset: number, data: string }
terminal:reset
DescriptionA terminal's whole view with its history, for a client that fell too far behind.Params { kind: 'terminal:reset', sessionId: string, terminalId: string, offset: number, data: string }
terminal:project-changed
DescriptionThe full list of a project's terminals (draftId absent) or of one draft's. No sessionId: these belong to no session (session signals are numbered and replayed per session). Output of these terminals still arrives as terminal:output / terminal:reset with sessionId: '', sent only to the views attached to them.Params { kind: 'terminal:project-changed', root: string, draftId?: string, terminals: TerminalInfo[] }Not numbered: no session.
workspace:exec:data
DescriptionA streamed workspace command (sessions.workspaceExecStream): its output in arrival order, then exactly one exit. Sent to the connection that started it only, never fanned out or replayed. code is null and signal set when the host killed it (cancelled: the client asked; truncated: the output cap was reached).Params { kind: 'workspace:exec:data', execId: string, stream: 'stdout' | 'stderr', chunk: string }Not numbered: no session.
workspace:exec:exit
DescriptionA streamed workspace command ended: its exit code or signal; truncated when the output cap was reached.Params { kind: 'workspace:exec:exit', execId: string, code: number | null, signal: string | null, truncated?: true, cancelled?: true }Not numbered: no session.
block-run:data
DescriptionA chunk of a Run here's output (sessions.runBlock), to the connection that started it only.Params { kind: 'block-run:data', runId: string, stream: 'stdout' | 'stderr', chunk: string }Not numbered: no session.
block-run:end
DescriptionA Run here ended: the saved run, or why it could not run. To the connection that started it only.Params { kind: 'block-run:end', runId: string, run?: BlockRun, error?: string }Not numbered: no session.
git:clone:progress
DescriptionGit's progress on the connection's git.clone, to that connection only.Params { kind: 'git:clone:progress', phase: string, percent: number }Not numbered: no session.
git:refs
DescriptionA checkout's refs moved (git.watch), to the connections watching cwd only.Params { kind: 'git:refs', cwd: string }Not numbered: no session.
panel:changed
DescriptionAn extension panel's content changed (panels.watch), to the connections watching it only.Params { kind: 'panel:changed', cwd: string, panelId: string }Not numbered: no session.
palette:changed
Descriptioncwd's extension palette items may have changed (palette.watch), to the connections watching only.Params { kind: 'palette:changed', cwd: string }Not numbered: no session.
logs:record
DescriptionA new record in a zidane-server's log (logs.watch), to the connections following it only.Params { kind: 'logs:record', record: LogRecord }Not numbered: no session.
perf:sample
DescriptionThe host's performance sample (perf.watch), to the connections watching it only.Params { kind: 'perf:sample', sample: PerfSample }Not numbered: no session.
catalog:changed
DescriptionA client installed, updated or removed something on the host (catalog.install / remove / update, mcp.upsert / remove): every window re-reads that catalog. models: what models.list answers changed (an extension's provider or account model list).Params { kind: 'catalog:changed', catalog: 'skills' | 'mcps' | 'extensions' | 'plugins' | 'models' }Not numbered: no session.
sync:changed
DescriptionA server's settings-sync record changed (a claim, a push, an override, a reset): settings UIs re-read sync.status.Params { kind: 'sync:changed' }Not numbered: no session.
tokens:changed
DescriptionA zidane-server's tokens changed (one created, revoked, paired, or the token file edited): token lists re-read tokens.list.Params { kind: 'tokens:changed' }Not numbered: no session.
approval:request
DescriptionA tool call waits for approval (safe mode).Params { kind: 'approval:request', request: WireApprovalRequest }Not numbered: no session.
approval:resolved
DescriptionAn approval left the pending queue (answered or denied in bulk); every OTHER window clears its surface. The window that resolved it already knows; the signal makes the queue converge everywhere else.Params { kind: 'approval:resolved', sessionId: string, requestId: string, decision: ApprovalDecision, answeredBy?: InteractionAnswerer }
sessions:changed
DescriptionA session was created, updated or deleted.Params { kind: 'sessions:changed', op: 'create' | 'update' | 'delete', sessionId: string }
block-runs:changed
DescriptionA session's saved block runs changed (a Run here ended, a run was removed): windows read them again.Params { kind: 'block-runs:changed', sessionId: string }
sessions:facets
DescriptionA session's facet values changed (ctx.sessions.facets): every facet it holds now, keyed <extensionId>.<key>, the same as SessionRow.facets. Not a sessions:changed: the row's other fields stand.Params { kind: 'sessions:facets', sessionId: string, facets: Record<string, JsonValue> }
settings:changed
DescriptionSettings were written through the host (settings.set); every window applies the new state so settings UIs converge without a restart. Windows that persist settings themselves must treat this as authoritative for the delivered snapshot.Params { kind: 'settings:changed', settings: HostSettings }Not numbered: no session.
draft:changed
DescriptionAnother window edited the session's shared prompt draft. The daemon EXCLUDES the originating peer from this fan-out, so applying it can never fight the local cursor; clients apply unconditionally (last-writer-wins whole-text replacement). Empty text clears the draft (broadcast when any window submits the prompt).Params { kind: 'draft:changed', sessionId: string, text: string, shell?: boolean }
draft:attachments
DescriptionThe shared draft's composing ATTACHMENTS changed (paste/drop/remove in any window). Payloads ride along so a remote window can submit the shared draft attachments-and-all. Same origin-exclusion as text.Params { kind: 'draft:attachments', sessionId: string, attachments: PromptAttachment[] }
search:changed
DescriptionThe session's shared transcript-search state changed (mode entered / exited, query edited) in another window. Same origin-exclusion and last-writer-wins contract as the draft; every window on the session shows the same filtered transcript.Params { kind: 'search:changed', sessionId: string, active: boolean, query: string }
suggest:changed
DescriptionThe daemon resolved another window's inline-autocomplete query (suggest.resolve). Excludes the requesting peer (it already has the result from its RPC reply). Receivers mirror the ghost ONLY when their live buffer still equals basis; the standard staleness guard; otherwise discard.Params { kind: 'suggest:changed', sessionId: string, seq: number, basis: string, caret: number, suggestion: string | null, candidates?: string[] }
suggestion:ready
DescriptionThe text model's guess at the user's next prompt after run runId (Settings.promptSuggestions). Windows offer it in the empty composer and drop it on the next run:start, a send, an edit or a compaction.Params { kind: 'suggestion:ready', sessionId: string, runId: string, text: string }
run:estimate
DescriptionA run of the session was estimated, or its wait on the user started or ended (Settings.runEstimates): the session's own run (depth 0) or a subagent's (label, callId). Saved on the run record too, so a window that missed it reads it from the session row's runEstimates.Params { kind: 'run:estimate', sessionId: string, estimate: RunEstimateView }
skills:snapshot
DescriptionThe daemon-side agent's active-skill set changed (skills_use / run-end deactivation). Windows mirror it into their skill chips.Params { kind: 'skills:snapshot', sessionId: string, active: string[] }
mcp:auth
DescriptionA daemon-side MCP server needs (re-)authentication. Windows surface the badge; the interactive login flow itself runs in whichever window the user triggers it from (tokens land in the shared credential store; the daemon reconnects on the next agent rebuild).Params { kind: 'mcp:auth', sessionId: string, name: string, reason: string }
mcp:settled
DescriptionThe session agent's MCP bootstrap finished: every server has its outcome (mcp:status / mcp:auth came first). A window's deadline for the one-shot auto-login it arms when the user adds a server.Params { kind: 'mcp:settled', sessionId: string }
mcp:status
DescriptionA host-side MCP server connected, or failed to. Windows feed it to the same status reducer the in-process path uses (badges: connected, signed in, needs sign-in, key refused, couldn't connect). error is the failure's message and code its HTTP-ish code when it had one, enough for the shared classifier (classifyMcpTest) to read it the same way.Params { kind: 'mcp:status', sessionId: string, name: string, status: 'connected' } | { kind: 'mcp:status', sessionId: string, name: string, status: 'failed', transport: string, error: string, code?: number }
stream:retry
DescriptionProvider retry in progress (rate-limit / overload / silent stall / dropped connection); drives the footer's "retrying n/m" indicator. source is 'parent' or the retrying child's id; the indicator clears when that source streams again or the run ends. discardTurnId: the failed attempt had streamed reasoning, or text before its connection dropped, for that turn; windows drop it (discardThinking), since the retry streams its own and the saved turn never holds it.Params { kind: 'stream:retry', sessionId: string, attempt: number, max: number, source: string, discardTurnId?: string }
stream:retry:cleared
DescriptionA retried stream reached a terminal state for source ('parent' or a child id); clear that source's retry indicator. Distinct kind rather than a nullable attempt so the two states stay unambiguous on the wire. Consumers also clear at run end as a backstop; this exists for the mid-run case, where a subagent's stream fails while the parent run continues and the indicator would otherwise stick.Params { kind: 'stream:retry:cleared', sessionId: string, source: string }
system-md
DescriptionWhich SYSTEM.md override (if any) the host folded into this session's system prompt, emitted at agent-build time. The prompt is composed where the agent is built; in the daemon, not in the window; so a window cannot derive this by probing its own disk: it may have a different cwd, and userInstructionsScope is the daemon's. Windows need it to tell "no override on disk" apart from "override in force", which is the difference between doctrine the user wrote and doctrine they think they replaced. shadowed carries precedence losers so the Instructions surface can mark them inactive.Params { kind: 'system-md', sessionId: string, file: SystemMdFile | null, shadowed: readonly SystemMdFile[] }
cache:break
DescriptionA cache-prefix break was detected for this session's last request; the footer chip names the culprit dimension and the re-billed prefix size. Detection is per-agent closure state inside the loop, so in daemon mode only the daemon can observe it. Cost pricing stays window-side (it needs only the provider key and the token count).Params { kind: 'cache:break', sessionId: string, info: CacheBreakInfo }
provider:diagnostic
DescriptionA provider reported a diagnostic for the session.Params { kind: 'provider:diagnostic', sessionId: string, diagnostic: ProviderDiagnostic }
presence:changed
DescriptionPresence snapshot; recomputed and fanned out whenever a window attaches/detaches or any tracked session's run/HITL state changes. Full snapshot (the set is small: only live sessions appear).Params { kind: 'presence:changed', sessions: SessionPresence[] }Not numbered: no session.
integrations:changed
DescriptionThe host's integrations changed (integrations.register / update, or the client that registered one disconnected). Full list, like presence.Params { kind: 'integrations:changed', integrations: IntegrationInfo[] }Not numbered: no session.
schedules:changed
DescriptionA schedule was created, changed, fired or removed (scheduleId), or several were. Clients read schedules.list again.Params { kind: 'schedules:changed', scheduleId?: string }Not numbered: no session.
machine:status
DescriptionA machine of this host came online or went offline (docs/MACHINES.md).Params ({ kind: 'machine:status' } & MachineStatusChange)Not numbered: no session.
machine:links
DescriptionThis local host's machine links changed (machines.links.status): shares of this computer, servers used as machines.Params { kind: 'machine:links', links: MachineLinksStatus }Not numbered: no session.
machine:notification
DescriptionA server lending itself as a machine to the local host on this connection (machine.attach): one of its machine notifications (terminal.data, task.exit, exec.stream.*). Sent to that connection only, never broadcast.Params { kind: 'machine:notification', method: string, params: JsonValue }Not numbered: no session.
queue:changed
DescriptionThe session's type-ahead queue changed (message queued while a run is in flight, drained by the host on run end, pushed early, or dropped). Broadcast to EVERY peer including the origin; the queue box is shared state and all windows render the same list.Params { kind: 'queue:changed', sessionId: string, items: QueuedItem[] }
delivery:changed
DescriptionA message sent with a clientMessageId changed state (DeliveryState). runId: the run that started with it, took it, or ended with it. For integrations; windows ignore it.Params { kind: 'delivery:changed', sessionId: string, clientMessageId: string, state: DeliveryState, runId?: string }
DescriptionA UI item changed in cwd's runtime. reset: the runtime was rebuilt, list again.Params { kind: 'extensions:ui', cwd: string, change: UiChange | { type: 'reset' } }Not numbered: no session.
extensions:commands
DescriptionThe commands of cwd's runtime changed (registered, retitled, rebound): list again.Params { kind: 'extensions:commands', cwd: string }Not numbered: no session.
extensions:keymap
DescriptionA keymap mode was pushed or popped. mode: the global mode on top now.Params { kind: 'extensions:keymap', cwd: string, mode?: string }Not numbered: no session.
extensions:integrations
DescriptionAn integration of cwd's runtime registered, connected or disconnected.Params { kind: 'extensions:integrations', cwd: string }Not numbered: no session.
extensions:integration-flow
DescriptionA step of a sign-in flow, to the client running it.Params { kind: 'extensions:integration-flow', flowId: string, integrationId: string, step: IntegrationFlowStep }Not numbered: no session.
extensions:storage
DescriptionA storage entry changed. projectRoot set for project and session scope. value absent: deleted. version counts the entry's writes on this host (see WireStorageSetResult).Params { kind: 'extensions:storage', extensionId: string, scope: StorageScope, sessionId?: string, projectRoot?: string, area: StorageArea, key: string, value?: Json, version?: number }Not numbered: no session.
extensions:entries
DescriptionThe extensions of cwd changed (loaded, reloaded, failed, unloaded): list extensions.entries again.Params { kind: 'extensions:entries', cwd: string }Not numbered: no session.
extensions:panel
DescriptionA panel of cwd's runtime would load something new: its subscribe emitted, or its handle was updated. panelId is <extension>/<id>; sessionId set: only that session's content changed. Reload the panel where it is visible. Also sent as an extensions:uipanel-changed change, for clients that follow that one.Params { kind: 'extensions:panel', cwd: string, extensionId: string, panelId: string, sessionId?: string }Not numbered: no session.
ui:dialog
DescriptionShow a dialog. Sent to the routed client only; answer with ui.dialog.answer.Params { kind: 'ui:dialog', dialogId: string, extensionId: string, sessionId?: string, request: DialogRequest }Not numbered: no session.
ui:dialog:close
DescriptionClose a dialog the host gave up on (timeout, abort, unload).Params { kind: 'ui:dialog:close', dialogId: string }Not numbered: no session.
ui:client
DescriptionA UI request for the routed client. requestId absent for notify.Params { kind: 'ui:client', requestId?: string, request: UiClientRequest }Not numbered: no session.
The server keeps the latest signals of each session (2000 signals or 4 MiB per session, 32 MiB in total). Past the total, it drops the least recently written session first. A client that kept its last handshake's signalEpoch and the last $seq it applied asks for what it missed:
The answer is { ok: false, reason } when the log cannot fill the gap. The reason is epoch (another server process, after a restart) or gap (the log dropped those signals). The client then reloads the transcript with sessions.loadEvents.
Hold the live signals of the session while sessions.resume runs.
Apply the replay.
Apply the held signals that the replay did not carry.
The apps reconnect with a backoff from 1 to 30 seconds. createServerHost uses 0.5 to 15 seconds. A refused token or another server at the URL stops the retries.
sessions.loadEvents without before or limit returns the whole transcript as an array. With either, it returns the last limit turns (default 200, at most 1000) before turn position before. Pass the cursor of the page as the next before. A page without cursor holds the first turn. A page starts on an exchange boundary, so a tool call always comes with its result. start counts the events of the transcript before the page.
A page over the message size comes back as ResponseTooLarge. If that happens, ask again with a smaller limit. sessions.getTurns pages the raw turns the same way (from, limit).
{"jsonrpc": "2.0","id": 12,"error": {"code": -32602,"message": "params must be an object."}}
JSON
{"jsonrpc": "2.0","id": 15,"error": {"code": -32040,"message": "\"machine.register\" needs a machine connection (a machine-scoped token); this is a client connection."}}
Error codes
Code
Name
Kind
Description
-32700
NameParseError
KindJSON-RPC
DescriptionThe received text is not valid JSON.
-32600
NameInvalidRequest
KindJSON-RPC
DescriptionThe message is not a valid JSON-RPC request.
-32601
NameMethodNotFound
KindJSON-RPC
DescriptionThe method does not exist.
-32602
NameInvalidParams
KindJSON-RPC
DescriptionThe method params are invalid.
-32603
NameInternalError
KindJSON-RPC
DescriptionThe handler failed with an unexpected error.
-32010
NameVersionMismatch
KindIPC
DescriptionThe ipc.hello protocol versions differ. The message names both and the side to upgrade; data.daemon carries the host's hello fields.
-32011
NameNotHandshaken
KindIPC
DescriptionA method other than $/ping, daemon.info or daemon.shutdown before ipc.hello.
-32012
NameRateLimited
KindIPC
DescriptionA network transport's per-connection request budget is spent; retry later.
-32013
NameResponseTooLarge
KindIPC
DescriptionThe reply would exceed the transport's message size: nothing was sent but this error (the connection stays). Ask for less (a transcript: a smaller page, see loadAllEvents).
-32014
NameHandlerFailed
KindIPC
DescriptionThe handler threw: the host refused or failed the call (message says why). Hosts before it answered -32000, which ACP uses for AuthenticationRequired; clients treat both as a plain remote error.
-32015
NameForbidden
KindIPC
DescriptionThe connection's token doesn't reach this method (./scopes: a chat token calling an admin method). data.required names the scope it needs. Additive: hosts before scopes never refuse this way.
-32040
NameMethodNotAllowed
KindMachine
DescriptionA machine connection called a client method, or a client a machine one.
-32041
NameVersionSkew
KindMachine
Descriptionmachine.register with a protocolVersion other than this host's MACHINE_PROTOCOL_VERSION.
-32042
NameNameTaken
KindMachine
DescriptionThe name is held by another machine on this host.
-32043
NameOutsideRoots
KindMachine
DescriptionA path or cwd outside the machine's roots, or in its data dir.
-32044
NameIdBound
KindMachine
DescriptionThe machine id is bound to another (live) token, or this token was used by the machine before the host forgot it.
-32045
NameBusy
KindMachine
DescriptionNo room now (a capacity limit): try again later, unlike a refusal.
Descriptionwake is host-internal (see SendOptions.wake); not accepted over the wire. requestId: see SendRequestId. The prompt goes through the extensions' prompt transforms and prompt interceptors of the session's folder first, once per submission, on the host (clients never run them). consumed says one took it instead of a run (runId is then ''): handled (an extension consumed it), steer / followUp (delivered to the live run). Additive.Params Omit<SendOptions, 'wake'> & SendRequestIdResult { runId: string, consumed?: 'handled' | 'steer' | 'followUp' }
chat.interrupt
Scopechat
DescriptionAborts the session's live run. Does nothing when no run is live.Params { sessionId: string }Result void
chat.pushQueued
Scopechat
DescriptionDelivers a queued message. Steers a live run, otherwise starts a run or runs it as a command. delivered says which path it took. keepDraft keeps the shared composer draft instead of clearing it on the other clients. The message goes through the prompt interceptors first, as chat.send; consumed says one took it (delivered is then send for handled, steer otherwise). Additive.Params { sessionId: string, message: string, activatedSkills?: string[], keepDraft?: boolean, origin?: SendOptions['origin'], literal?: boolean, clientMessageId?: string, metadata?: SendOptions['metadata'] } & SendRequestIdResult { delivered: 'steer' | 'send' | 'command' | 'queued', consumed?: 'handled' | 'steer' | 'followUp' }
chat.isRunning
Scopechat
DescriptionResolves true while the session has a live run.Params { sessionId: string }Result boolean
chat.rebuildAgent
Scopechat
DescriptionRetire the session's live agent so the next run rebuilds against fresh config/credentials (MCP login, extension reload). Run-end deferred when a run is in flight; HITL/queue state survives.Params { sessionId: string }Result void
chat.listWork
Scopechat
DescriptionLists the tool calls and background tasks the session's live run tracks and can cancel. Empty when no run is live. children: true adds the subagents' running calls (childId set), for their starts: a transcript read from disk times them too. Older hosts ignore it.Params { sessionId: string, children?: boolean }Result RunningWorkItem[]
chat.cancelWork
Scopechat
DescriptionCancels one tracked work item by id, or every visible item with "all". Resolves true when something was cancelled. reason is passed to a cancelled tool call.Params { sessionId: string, id: string | 'all', reason?: string }Result boolean
chat.deliveryState
Scopechat
DescriptionWhat became of a send, by its requestId, its clientMessageId, or both: the send request record, then the last announced delivery:changed state, then the queue and the transcript (origin.messageId). Resolves a send answered "already accepted" (SendRequestPendingError). state: the last known DeliveryState, or unknown when the host holds no trace. runId: the run that took it, when known. settled: nothing more will happen to it: a final state (answered, failed, interrupted, dropped), or, with unknown, it is in neither the queue nor the transcript and the send request record says no send of it runs (it never landed: send it again with a new requestId); without a requestId an unknown is never settled. Additive.Params { sessionId: string, requestId?: string, clientMessageId?: string }Result { state: DeliveryState | 'unknown', runId?: string, settled: boolean }
Descriptionzidane run --system / --mcp for a host-backed window: launch overrides for the session's agent (ChatHost.setLaunchOverrides), owned by the calling client and dropped when it disconnects. A call with neither field clears them.Params { sessionId: string } & SessionLaunchOverridesResult void
sessions.list
Scopechat
DescriptionLists session rows. projectRoot filters by project, archive picks active, archived or all sessions.Params { projectRoot?: string | null, archive?: 'active' | 'archived' | 'all' }Result SessionRow[]
sessions.listMeta
Scopechat
DescriptionThe session list as a window renders it (SessionMeta: title, turn / message / run counts, project, cwd, environment, artifact count, the orchestration main flag), newest first. projectRoot: omitted = every project, null = untagged sessions.Params { projectRoot?: string | null }Result SessionMeta[]
sessions.getMeta
Scopechat
DescriptionOne SessionMeta by id (rows a filtered list can't return, e.g. the main); null when unknown.Params { sessionId: string }Result SessionMeta | null
sessions.get
Scopechat
DescriptionThe whole session document as the host holds it: the live copy when an agent is live (turns persisted mid-run, todos kept in memory), else the stored one, a stale running marker demoted. null when unknown.Params { sessionId: string, turns?: boolean }Result SessionDocumentHead | null
sessions.getTurns
Scopechat
DescriptionA slice of a session's turns, [from, from + limit) (default from 0, SESSION_TURNS_PAGE turns, at most SESSION_TURNS_MAX_PAGE), from the same copy sessions.get reads, and how many turns it has: a client reads a long session's document a page at a time (loadSessionDocument) instead of in one reply. With sessions.getturns: false (the document without its turns), what an export needs. Pages and that head come from one snapshot of the document per content version (read once, not per page), and name it (version): a client that sees it change mid-load starts over rather than mix two versions (loadSessionDocument). null when unknown. Additive: an older host answers "method not found", ignores turns: false, and names no version.Params { sessionId: string, from?: number, limit?: number }Result { turns: SessionTurn[], total: number, version?: string } | null
sessions.getToolResult
Scopechat
DescriptionThe full text of one tool result (callId; turnId, when known, the turn that holds it): what a clipped tool row shows on expand, without the session crossing the wire. null when no such result. Additive.Params { sessionId: string, callId: string, turnId?: string }Result string | null
sessions.getHeader
Scopechat
DescriptionOne session's header: its list row plus metadata, profile and status, without turns or runs (the live copy when an agent holds it). What a window re-reads on sessions:changed. Additive. usage: true adds the footer's numbers, computed host-side from the turns and runs (contextTokens, costUsd, and while the host runs the session runStartedAt / runOutputTokens): a client needs no document for its context gauge, cost pill or run readout. Older hosts ignore it.Params { sessionId: string, usage?: boolean }Result SessionHeader | null
sessions.setExtensionState
Scopechat
DescriptionOne key of an extension's per-session state (metadata.extensions, the bag ctx.session and renderer useSessionState share), written by the host into its copy of the session. value omitted deletes the key.Params { sessionId: string, extension: string, key: string, value?: JsonValue }Result void
sessions.create
Scopechat
DescriptionCreates a session and resolves with its row.Params CreateSessionParamsResult SessionRow
sessions.delete
Scopechat
DescriptionResolves with what happened to the session's environment (a provider may keep it).Params { sessionId: string }Result { environment?: EnvironmentTeardownResult }
sessions.sideSession
Scopechat
DescriptionA session's /side session (sessions.create with sideOf; hidden from sessions.list), the newest when there are several, with the session's own row (null: unknown). Additive.Params { sessionId: string }Result SideSessionLookup
DescriptionMove an idle session to another environment (local, worktree, local@M, worktree@M, any direction), in cwd on the target; provisioning continues in the background.Params { sessionId: string, environment: EnvironmentRequest, cwd?: string, removeOldWorktree?: boolean }Result { oldWorktree?: EnvironmentTeardownResult }
sessions.environmentActions
Scopechat
DescriptionThe per-session commands the session's environment offers right now (push, open PR, …).Params { sessionId: string }Result EnvironmentActionSummary[]
sessions.runEnvironmentAction
Scopeadmin
DescriptionRun one of them in the session's environment (resumed when suspended).Params { sessionId: string, actionId: string }Result EnvironmentActionResult
sessions.workspaceExec
Scopeadmin
DescriptionThe session's workspace (ChatHost.workspace*): its execution context, rooted inside the environment when the files live there, else at the session's cwd. Paths and exec cwd resolve against the root as the execution context resolves them; containment is the context's own. cwd / env on exec and the list / size methods are additive: an older daemon ignores the former and answers "method not found" to the latter (active clients are build-fenced, so this is a transient case).Params { sessionId: string, command: string, cwd?: string, env?: Record<string, string>, timeoutSeconds?: number }Result ExecResult
sessions.workspaceExecStream
Scopeadmin
DescriptionThe same command, streamed (! on a remote host): the reply names the exec, its output follows as workspace:exec:data signals and ends with one workspace:exec:exit, all to this connection only (signals may precede the reply). Bounded per connection (concurrent commands, chunk size, total output: past it the process is stopped and the exit says truncated). A dropped connection kills what it started. Additive: an older host answers "method not found" and clients use workspaceExec.Params { sessionId: string, command: string, cwd?: string }Result { execId: string }
sessions.workspaceExecCancel
Scopeadmin
DescriptionKill a streamed command's process group (this connection's only; cancelled: false otherwise or when it already ended).Params { execId: string }Result { cancelled: boolean }
sessions.runBlock
Scopeadmin
DescriptionRuns a shell block of a reply (Run here) in the session's folder, with no input. The reply names the run; its output follows as block-run:data signals and ends with one block-run:end carrying the saved run, to this connection only. Nothing enters the conversation; the run becomes the block's last (sessions.blockRuns), announced to every window by block-runs:changed. A dropped connection stops what it started.Params { sessionId: string, turnId: string, code: string, language: string }Result { runId: string }
sessions.runBlockCancel
Scopeadmin
DescriptionStops a Run here this connection started (cancelled: false when it is not running).Params { runId: string }Result { cancelled: boolean }
DescriptionReads a text file from the session's workspace.Params { sessionId: string, path: string }Result string
sessions.workspaceWriteFile
Scopeadmin
DescriptionWrites a text file in the session's workspace.Params { sessionId: string, path: string, content: string }Result void
sessions.workspaceListFiles
Scopechat
DescriptionLists the entries under path in the session's workspace.Params { sessionId: string, path: string, options?: WorkspaceListFilesOptions }Result ListFilesEntry[]
sessions.workspaceFileSize
Scopechat
DescriptionSize in bytes of a file in the session's workspace, or null when it does not exist.Params { sessionId: string, path: string }Result number | null
sessions.workspaceCreate
Scopeadmin
DescriptionCreates a file (content: base64 bytes, default empty) or a folder; freeName takes the next free name instead of refusing a taken one.Params { sessionId: string, path: string, kind: 'file' | 'dir', content?: string, freeName?: boolean }Result EntryResult
sessions.workspaceMove
Scopeadmin
DescriptionMoves (renames) from to to.Params { sessionId: string, from: string, to: string }Result EntryResult
sessions.workspaceCopy
Scopeadmin
DescriptionCopies from into folder toDir ('': the root) under a free name.Params { sessionId: string, from: string, toDir: string }Result EntryResult
sessions.workspaceRemove
Scopeadmin
DescriptionRemoves path (a folder whole), for good.Params { sessionId: string, path: string }Result EntryResult
sessions.workspaceEmptyDirs
Scopechat
DescriptionThe workspace's empty folders, relative to its root (a file listing leaves them out), capped.Params { sessionId: string }Result string[]
sessions.setTitle
Scopechat
DescriptionRenames a session.Params { sessionId: string, title: string }Result void
sessions.generateTitle
Scopechat
DescriptionTitle the session ON the host: its providers and credentials (a server session's transcript never goes to the window's provider), the same generator (generateSessionTitle), written as sessions.setTitle does. providerKey / model: the window's pick, used when the host has that provider; otherwise the session's own provider and model. The Main session is refused (it keeps its name). Additive: an older host answers "method not found".Params { sessionId: string, providerKey?: string, model?: string }Result { title: string }
sessions.titleStatus
Scopechat
DescriptionHow the session's title came about, as the session details dialog words it (describeTitleStatus): where it came from (auto, typed by you, untitled, …), then the last automatic titling attempt when there was one (generated 2h ago, check failed 5m ago (…)). Additive.Params { sessionId: string }Result string[]
sessions.setArchived
Scopechat
DescriptionArchives or restores a session.Params { sessionId: string, archived: boolean }Result void
sessions.setFavorite
Scopechat
DescriptionKeep the session at the top of lists (metadata.favorite). Not activity: no recency bump. Additive.Params { sessionId: string, favorite: boolean }Result void
sessions.setPolicy
Scopechat
DescriptionReplaces the session's rules (metadata.policy, SessionPolicy); {} clears them. Loosening the current rules (a looser approvalMode, 'ask' > 'decide' > 'off', removing a rule, raising a ceiling) needs an approve token. Additive.Params { sessionId: string, policy: SessionPolicy }Result void
sessions.setSpace
Scopechat
DescriptionMove the session to a space (metadata.spaceId); the Default space id clears it. See chat/spaces.Params { sessionId: string, spaceId: string }Result void
sessions.setAgentId
Scopechat
DescriptionSwitches the agent the session runs as.Params { sessionId: string, agentId: string }Result void
sessions.setEffort
Scopechat
DescriptionSets the thinking effort of the session.Params { sessionId: string, effort: ThinkingLevel }Result void
sessions.setModel
Scopechat
DescriptionThe one model-swap contract (ChatHost.setSessionModel). A pick is a whole: fallbacks (ordered, primary excluded) REPLACES the persisted metadata.modelChain (omitted/empty clears it); effort and modelOptions are reset to the supplied values (omitted clears them; per-model knobs never leak onto the new model). The live agent is retired so the next run rebuilds on the new pick (run-end deferred while a run is in flight).Params { sessionId: string, providerKey: ProviderKey, modelId: string, account?: string, fallbacks?: ModelFallbackRef[], effort?: ThinkingLevel, modelOptions?: Record<string, boolean> }Result void
sessions.setModelOptions
Scopechat
DescriptionReplaces the model-specific boolean options of the session.Params { sessionId: string, options: Record<string, boolean> }Result void
sessions.loadEvents
Scopechat
DescriptionThe session's transcript as canonical events. Without before / limit: every turn, as a plain array (the shape every client predating paging reads). With either: one page, { events, cursor? }, the last limit turns (default LOAD_EVENTS_PAGE_TURNS, at most LOAD_EVENTS_MAX_PAGE_TURNS) before turn position before (default: the end), its start moved back to an exchange boundary when one is near so a tool call is never cut from its result. cursor: the before of the previous page, absent at the first turn. Typed here as the unpaged call every client makes; a paged call goes through loadEventsPage. Paging is additive: an older host ignores the fields and answers the whole array.Params { sessionId: string }Result StreamEvent[]
sessions.resume
Scopechat
DescriptionReattach without a reload: the session's signals numbered after afterSeq (see SIGNAL_SEQ_FIELD), in order, as long as this host process (epoch, from HelloResult.signalEpoch) still holds them all. Otherwise refused, and the client reloads with sessions.loadEvents. Additive: an older host answers "method not found", same fallback.Params { sessionId: string, epoch: string, afterSeq: number }Result SessionResumeResult
sessions.getTurn
Scopechat
DescriptionOne turn of a session by id, or null when unknown.Params { sessionId: string, turnId: string }Result SessionTurn | null
sessions.contextBreakdown
Scopechat
DescriptionThe session's context usage broken down by category, or null when unknown.Params { sessionId: string }Result ContextBreakdown | null
sessions.artifacts
Scopechat
DescriptionArtifacts one session recorded (PRs, branches, commits, files, extension kinds; see session/artifacts.ts), newest first. Empty on stores without artifact support. Additive; pre-artifact daemons reject the method and clients treat that as empty.Params { sessionId: string, kind?: string, limit?: number }Result SessionArtifact[]
sessions.touch
Scopechat
DescriptionA window appended transcript content OUT-OF-BAND (local / command output, ! shell turns; written straight to the shared store, not through a host run). The daemon fans out sessions:changed so every window (issuer included) re-converges on the canonical replay NOW instead of at the next run end. Sent as a notification.Params { sessionId: string }Result void
sessions.fork
Scopechat
DescriptionFork at turnId into a new session (ChatHost.forkSession); announced as a sessions:changed create.Params { sessionId: string, turnId: string, title?: string }Result { id: string }
sessions.deleteTurn
Scopechat
DescriptionHistory edits (ChatHost.deleteTurn / editTurnText): refused while the session runs.Params { sessionId: string, turnId: string }Result void
sessions.editTurnText
Scopechat
DescriptionReplaces the text of one turn. Refused while the session runs.Params { sessionId: string, turnId: string, text: string }Result void
sessions.rewind
Scopechat
DescriptionCut the history at turnId in place (ChatHost.rewindSession); inclusive keeps the turn. Refused while the session runs.Params { sessionId: string, turnId: string, inclusive: boolean }Result void
sessions.setFolder
Scopechat
DescriptionBind to a folder, or back to a plain chat with cwd: '' (ChatHost.setSessionFolder).Params { sessionId: string, cwd: string }Result void
sessions.appendTurns
Scopechat
DescriptionTurns written outside a run, e.g. ! shell output (ChatHost.appendTurns). whenIdle: refused while a run is live or an interrupted run waits (a channel's context messages).Params { sessionId: string, turns: SessionTurn[], whenIdle?: boolean }Result void
sessions.appendNote
Scopechat
Descriptionctx.appendNote outside a run: a display-only note, rendered live and persisted (ChatHost.appendNote). False for an unknown session or no blocks.Params { sessionId: string, blocks: CommandOutputBlock[] }Result boolean
sessions.compact
Scopechat
DescriptionCompact now (ChatHost.compactSessionNow): what was done, null when nothing was. Older daemons resolve null.Params { sessionId: string }Result CompactionReport | null
sessions.systemMd
Scopechat
DescriptionWhich SYSTEM.md override composes this session's prompt, for windows attaching to an already-warm agent. The system-md signal fires once per agent BUILD and the daemon caches agents, so the normal multi-window case (daemon already running, open a second terminal or the GUI) would otherwise never learn that the built-in safety and git doctrine has been replaced. null = no live agent yet, in which case the next build broadcasts it.Params { sessionId: string }Result { file: SystemMdFile | null, shadowed: readonly SystemMdFile[] } | null
sessions.contextSegments
Scopechat
DescriptionEvery chunk of the session's system prompt with provenance; the Instructions tab. Built from the live agent's assembly, so it reflects MCP instructions, extension fragments and the resolved SYSTEM.md.Params { sessionId: string }Result ContextSegmentsReport | null
sessions.cacheImpact
Scopechat
DescriptionWhat a switch would cost the session's prompt cache, as the host applies it (ChatHost.cacheImpact): what pickers show next to each option. null without a live agent or for an empty change. Additive: an older host answers "method not found", and clients show no estimate.Params { sessionId: string, change: CacheImpactChange }Result CacheImpact | null
sessions.cacheReport
Scopechat
DescriptionThe session's last requests and what the cache did for each (ChatHost.cacheReport): what /cache prints, for the GUI's session details. null for an unknown session. Additive: an older host answers "method not found".Params { sessionId: string, limit?: number }Result CacheReport | null
sessions.export
Scopechat
DescriptionThe session's transcript rendered as a file to hand to the user: Markdown (title, metadata, every turn) or the session's JSON. Nothing is written on the host. Additive (no version bump).Params { sessionId: string, format: SessionExportFormat }Result SessionExportFile
sessions.createSystemOverride
Scopeadmin
DescriptionSeed a user-scope SYSTEM.md from the session's doctrine; throws when an override could not apply.Params { sessionId: string }Result { path: string, created: boolean }
DescriptionDrop the daemon's cached runtime configs (extension registries, per cwd) and retire every live agent so the next command or run rebuilds against what is on disk now. Sent by a window after it reloaded its own extensions (install, update, remove, /reload): extension / commands execute daemon-side, so without this the daemon keeps running the code it loaded at boot. Busy sessions rebuild at run end.Params Record<string, never>Result void
DescriptionEvery environment kind the host can create, described for a new session in cwd (availability, default, branch suggestion, options; secrets only as "configured"). What pickers and the Environments settings render. kind: a machine kind (local@laptop) says cwd is that machine's folder, checked against its roots instead of this host's (docs/MACHINES.md § Folders); the same on commands.*, catalog.* and models.list. Additive.Params { cwd?: string, kind?: string }Result EnvironmentDescriptor[]
environments.update
Scopeadmin
DescriptionApply one Environments-settings edit (enable, default, options, secrets), validated against the kind's schema. Settings changes fan out as settings:changed; secrets are stored host-side and never returned.Params EnvironmentSettingsChangeResult void
environments.verify
Scopechat
Description"Test connection" for a kind with its current options.Params { kind: string }Result EnvironmentVerifyResult
DescriptionArtifacts across sessions, filtered by project root (null = untagged sessions, omitted = every project) and/or kind/uri (reverse lookup).Params { projectRoot?: string | null, kind?: string, uri?: string, since?: number, limit?: number }Result SessionArtifact[]
artifacts.delete
Scopechat
DescriptionRemove one artifact. false when the store has no artifact support. Fans out artifact:changed.Params { sessionId: string, artifactId: string }Result boolean
artifacts.upsert
Scopechat
DescriptionUpsert an artifact; the lazy resolve() write-back (refreshed label / meta). Same merge semantics as SessionStore.upsertArtifact; null when the session is unknown or the store lacks support.Params { artifact: SessionArtifact }Result SessionArtifact | null
artifacts.refresh
Scopechat
DescriptionRe-resolves one stored artifact (is the pull request merged?): its kind's resolve() runs on the host, with the extensions of the folder the artifact landed in. A change is stored and fans out artifact:changed. force asks past the kind's own freshness window. null when nothing changed (no resolver, nothing new, an unknown artifact). Additive.Params { sessionId: string, artifactId: string, force?: boolean }Result SessionArtifact | null
artifacts.badges
Scopechat
DescriptionThe badges under sessions' titles (commits, pull requests, extension kinds with a badge), for up to ARTIFACT_BADGES_MAX sessions at once, keyed by session id. Each session's badges come from the extensions of the folder its newest artifact landed in. They change with the session's artifact:recorded / artifact:changed and with catalog:changed (extensions): read them again then. Additive.Params { sessionIds: string[] }Result Record<string, SessionBadgeEntry[]>
DescriptionTranscript search over ONE session, daemon-side. The daemon owns the authoritative turns (live wrapper when an agent is active; fresh mid-run, which a window's load-time snapshot is not) and an LRU index cache shared by every window, so repeat queries pay match cost only. Results come back in TURN ORDER (search is a transcript filter).Params { sessionId: string, query: string, limit?: number }Result SearchTurnResult[]
history.searchAll
Scopechat
DescriptionCross-session content search, daemon-side. One RPC replaces a window's per-session index/build/search round-trips; indexes are built once in the daemon and shared by every window.Params { query: string, sessionIds: string[], excerptLimit?: number }Result Record<string, SessionHistoryMatch>
DescriptionThe session's plans (from its live agent, else the store), or null for an unknown session.Params { sessionId: string }Result PlansSnapshot | null
plans.edit
Scopechat
DescriptionA user edit to a plan's steps: rename, add or cancel (a step is never deleted). Through the live agent's session, else the store; refused while another process runs the session. The host fans plans:snapshot out to every window; the result is that snapshot. A refused edit is an error carrying the gate's reason.Params { sessionId: string, planId: string, op: PlanEditOp }Result PlansSnapshot
plans.control
Scopechat
DescriptionStop or drop a plan. Stopping or dropping the plan a live run applies interrupts that run. Resume is a message (buildPlanResumeMessage), not a call.Params { sessionId: string, planId: string, action: 'stop' | 'drop' }Result PlansSnapshot
DescriptionThe main session id, creating it (directory-less) when the setting is on and none exists.Params Record<string, never>Result string | null
orchestration.createWorker
Scopechat
DescriptionCreates a session (optionally holding orchestration tools and a subscription) and resolves with its id.Params OrchestrationCreateParamsResult string
orchestration.list
Scopechat
DescriptionLists sessions with their live status, newest first, up to limit. The list can be partial.Params { limit?: number }Result OrchestrationWorkerRow[]
orchestration.read
Scopechat
DescriptionSummary of one session (with its link); rejects when unknown. lastMessage is cut at 600 characters; full: true returns it whole.Params { sessionId: string, full?: boolean }Result OrchestrationWorkerSummary
orchestration.send
Scopechat
DescriptionQueues a prompt as the session's next turn; false when declined (the person stopped the session, or their queued prompts go first).Params { sessionId: string, prompt: string }Result boolean
orchestration.steer
Scopechat
DescriptionSends a steering message, with optional attachments, to a session's live run.Params { sessionId: string, message: string, attachments?: PromptAttachment[] }Result void
orchestration.cancel
Scopechat
DescriptionCancels a session's run.Params { sessionId: string }Result void
orchestration.transcript
Scopechat
DescriptionThe last limit turns of a session as plain text, each cut at 1200 characters; full: true returns them whole.Params { sessionId: string, limit?: number, full?: boolean }Result string
orchestration.wait
Scopechat
DescriptionResolves once the session is idle or blocked, or after timeoutSec (default 30, at most 50).Params { sessionId: string, timeoutSec?: number }Result OrchestrationWaitResult
DescriptionThe prompts waiting for an answer (questions, plans, tool approvals), of one session or all.Params { sessionId?: string }Result OrchestrationPendingRequest[]
orchestration.answer
Scopechat
DescriptionAnswers a question or a plan, recording the connection as answeredBy. false when it was answered first.Params { requestId: string, response: InteractionResponse }Result boolean
orchestration.approve
Scopechat
DescriptionDecides a tool approval (an approve token), recording the connection as answeredBy. false when it was decided first.Params { requestId: string, decision: ApprovalDecision }Result boolean
DescriptionThe agent profiles cwd offers ('': no folder), as the agent picker lists them: a profile a setting turns off (Codemode) is left out. Additive.Params { cwd: string }Result HostAgentProfile[]
The extensions' composer completions, run on the server: the triggers a folder offers, a provider's items, and the submit hooks on a prompt about to be sent.
completions.* methods
Method
Scope
Description
completions.providers
Scopechat
DescriptionThe extension completion providers (ctx.registerCompletionProvider) of cwd a composer can render: a one-character trigger each, @/# left to the built-in completers, first wins on id and trigger. Additive.Params { cwd: string }Result ExtensionCompletionProviderSummary[]
completions.suggest
Scopechat
DescriptionOne provider's items for query (the text after its trigger), at most 8. A newer call for the same provider on the connection aborts this one; [] past 5 s or when the provider throws. Additive.Params { cwd: string, providerId: string, query: string, text: string, cursor: number }Result ExtensionCompletionItemSummary[]
completions.submit
Scopechat
DescriptionRuns the providers' submit hooks (resolveReferences, onSubmit) on a prompt about to be sent; resolves after them, or after 5 s. Additive.Params { cwd: string, text: string, cursor: number }Result void
DescriptionLists pending interactions (questions and prompts the agent asked the user), optionally for one session.Params { sessionId?: string }Result PendingInteraction[]
DescriptionCancels a pending interaction. reason is passed back to the agent.Params { requestId: string, reason?: string }Result { ok: boolean }
interactions.rehydrate
Scopechat
DescriptionRe-sends the session's pending interactions, for a client that connected after they were raised.Params { sessionId: string }Result PendingInteraction[]
interactions.rehydrateSessions
Scopechat
Descriptioninteractions.rehydrate for each of sessionIds not running on this host, loading only those whose run waits to be resumed or whose last turns hold an unanswered question or plan (a channel start, over every conversation it had).Params { sessionIds: string[] }Result PendingInteraction[]
DescriptionDev browser: a window offers to host the pages the agent's browser_* tools drive (the GUI's main process). Released when the connection drops. It then answers each browser:request signal addressed to it.Params { hostId: string }Result { ok: boolean }
browser.unregisterHost
Scopechat
DescriptionWithdraws a window as dev browser host.Params { hostId: string }Result { ok: boolean }
browser.respond
Scopechat
DescriptionAnswers a browser:request signal with the host's result.Params { requestId: string, response: BrowserResponse }Result { ok: boolean }
DescriptionTerminals, run by the host in the session's environment. clientId names one view (a window's drawer or panel); views attached through a connection are detached when it drops. Output arrives as terminal:output signals; ack what was written to keep it flowing.Params { sessionId: string }Result TerminalSessionState
terminal.open
Scopeadmin
DescriptionOpens a terminal in a session's environment.Params TerminalOpenInputResult TerminalInfo
terminal.attach
Scopeadmin
DescriptionmaxLines caps the history snapshot to the last lines a view can show (0 or absent: no cap).Params { terminalId: string, clientId: string, maxLines?: number }Result TerminalAttachResult
terminal.detach
Scopeadmin
DescriptionDetaches a view from a terminal.Params { terminalId: string, clientId: string }Result void
terminal.write
Scopeadmin
DescriptionclientId + response: bytes the view's emulator generated (DSR/DA replies), dropped unless that view owns the size.Params { terminalId: string, data: string, clientId?: string, response?: boolean }Result void
terminal.resize
Scopeadmin
DescriptionResizes the terminal to a view's size. claim makes this view own the size.Params { terminalId: string, clientId: string, cols: number, rows: number, claim?: boolean }Result void
terminal.ack
Scopeadmin
DescriptionAcknowledges terminal output up to offset, so the host keeps it flowing.Params { terminalId: string, clientId: string, offset: number }Result void
terminal.restart
Scopeadmin
DescriptionRestarts a terminal's process and resolves with its info.Params { terminalId: string }Result TerminalInfo
terminal.close
Scopeadmin
DescriptionCloses a terminal.Params { terminalId: string }Result void
terminal.setHidden
Scopeadmin
DescriptionHides a terminal from the agent, or shows it again.Params { terminalId: string, hidden: boolean }Result void
terminal.registerViewer
Scopeadmin
DescriptionThis connection can show terminals (the desktop app). While at least one viewer is attached, agents get the terminal tools; the registration is dropped with the connection.Params { viewerId: string }Result { ok: boolean }
terminal.unregisterViewer
Scopeadmin
DescriptionWithdraws a viewer registered with terminal.registerViewer.Params { viewerId: string }Result { ok: boolean }
terminal.projectState
Scopeadmin
DescriptionTerminals without a session: a shell on the host's machine in a project's folder, or in a new-chat draft's (draftId). Agents never see them. terminal:project-changed carries a scope's full list.Params TerminalProjectStateInputResult TerminalProjectState
terminal.openInProject
Scopeadmin
DescriptionOpens a terminal bound to a project rather than a session.Params TerminalProjectOpenInputResult TerminalInfo
terminal.adopt
Scopeadmin
DescriptionThe draft became sessionId: its terminals move there in one pass (over the cap: back to the project).Params { draftId: string, sessionId: string }Result TerminalAdoptResult
terminal.releaseDraft
Scopeadmin
DescriptionThe draft was discarded (or became a server session): its terminals go back to the project.Params { draftId: string }Result void
The "Always allow" entries approvals saved, per project. A chat token can revoke one.
safelist.* methods
Method
Scope
Description
safelist.list
Scopechat
DescriptionThe host's "Always allow" entries, per project (its projects.json): what approving with accept-safelist added. Additive.Params Record<string, never>Result { projects: SafelistProject[] }
safelist.remove
Scopechat
DescriptionRevoke one "Always allow" entry of a project; removed: false when it was not there. Additive.Params { project: string, entry: string }Result { removed: boolean }
DescriptionType-ahead queue, host-owned so every window sees and can manipulate the same list. queue.add queues when a run is in flight and sends immediately otherwise; the host auto-drains the queue FIFO at run end.Params { sessionId: string }Result QueuedItem[]
queue.add
Scopechat
DescriptionSends a message: right away when the session is idle; while a run works, into the run or into the queue (delivery). delivered says which: sent, steer (the run took it, as a steer or a follow-up) or queued. The message goes through the prompt interceptors first, as chat.send; consumed says one took it (delivered is then sent for handled, steer otherwise).Params { sessionId: string, text: string, activatedSkills?: string[], attachments?: PromptAttachment[], asCommand?: string, keepDraft?: boolean, origin?: SendOptions['origin'], literal?: boolean, clientMessageId?: string, metadata?: SendOptions['metadata'], delivery?: QueueDelivery } & SendRequestIdResult { delivered: 'queued' | 'sent' | 'steer', consumed?: 'handled' | 'steer' | 'followUp' }
queue.remove
Scopechat
DescriptionRemoves a queued entry by id. Resolves true when it was removed.Params { sessionId: string, id: string }Result boolean
queue.update
Scopechat
DescriptionEdit a queued entry in place; order is kept. attachments replaces the entry's list when given. false when already sent / dropped.Params { sessionId: string, id: string, text: string, attachments?: PromptAttachment[] }Result boolean
queue.attachments
Scopechat
DescriptionA queued entry's attachments with their bytes; null when already sent / dropped.Params { sessionId: string, id: string }Result PromptAttachment[] | null
queue.pushNow
Scopechat
DescriptionSteer a queued entry, attachments included, into the live run now (falls back to send when idle).Params { sessionId: string, id: string }Result { delivered: 'steer' | 'send' | 'queued' | 'missing' }
DescriptionCurrent shared draft for a session; backfill on window attach.Params { sessionId: string }Result { text: string, shell?: boolean, attachments?: PromptAttachment[], search?: { active: boolean, query: string } }
drafts.set
Scopechat
DescriptionReplace the session's shared draft. Fans out draft:changed to every OTHER peer. Ephemeral daemon state; drafts don't survive a daemon restart and are cleared when any window submits the prompt. shell carries the prompt's shell mode OUT OF BAND; never encoded into the text, so a literal leading ! in a normal draft can't flip other windows into shell-execution semantics.Params { sessionId: string, text: string, shell?: boolean }Result void
What a folder's extensions declare in Settings: their options and action rows (extensions.actions), the actions' status probes (extensions.actionStatuses) and a run (extensions.runAction: the token needs the action's own scope, admin unless the extension lowers it; the config patch it returns is the client's to save with settings.set), and a new extension's scaffold (admin, behind allowRemoteInstalls).
extensions.* methods
Method
Scope
Description
extensions.configSchema
Scopechat
DescriptionThe options the enabled extensions declare for cwd (registerConfigItem), without the action items or the callbacks; the values live on the settings' extensionConfig. Additive.Params { cwd: string }Result WireExtensionConfigSchema
extensions.actions
Scopechat
DescriptionThe action rows (registerConfigItem type 'action') the enabled extensions declare for cwd. Additive.Params { cwd: string }Result ExtensionActionSummary[]
extensions.actionStatuses
Scopechat
DescriptionThe actions' passive status() probes, keyed extension:key; a probe that throws or takes over 3 s is left out. Additive.Params { cwd: string }Result Record<string, ExtensionConfigActionStatus>
extensions.runAction
Scopechat
DescriptionRuns an action on the host. The config patch it returns comes back sanitized, not written: the client saves it (settings.set). One run of an action at a time. A token needs the action's scope (the action row's scope; default, and for config-declared actions, admin). Additive.Params { cwd: string, extension: string, key: string }Result ExtensionActionRunResult
extensions.create
Scopeadmin
DescriptionScaffolds a new extension and reloads the registries: in the host user's extensions folder (scope: 'user', the default), or in a project (scope: 'project': cwd's checkout, which must lie in the workspace roots; it loads once the project is trusted). Sessions stay in the roots: one may open in a project extension's folder, never in a user extension's. It writes code the host will run: a zidane-server's allowRemoteInstalls gates it, every attempt is audited. Every window gets catalog:changed. Additive.Params CreateExtensionInputResult CreateExtensionResult
extensions.ui.list
Scopechat
DescriptionEvery UI item of cwd's extensions, per token, in wire form, and each active extension's compiled ui bundle (bundles, by extension id). extensions:ui pushes each change after it. Additive.Params { cwd: string }Result WireUiList
extensions.entries
Scopechat
DescriptionThe extensions of cwd: status, folder, tui entry and compiled ui bundle. What a window draws extensions from in daemon mode, without running their setup. extensions:entries says when to list again. Additive.Params { cwd: string }Result WireExtensionEntry[]
extensions.ui.invoke
Scopechat
DescriptionRuns one callback of a UI item by its id (a panel's load / onAction, a reference resolve, a badge menu or action, a settings page action, status or check). Callbacks run on the host under their extension's guard. Additive.Params { cwd: string } & UiInvokeRequestResult unknown
extensions.links.open
Scopechat
DescriptionOffers a link the user opened to cwd's extensions' link handlers (LinkHandler), higher priority first; a handler that returns false, throws or times out passes it on. handled: false: open it the app's own way. Apps call it for every link they open, except with Alt held. Additive.Params LinkOpenParamsResult { handled: boolean }
extensions.storage.load
Scopechat
DescriptionEverything stored at a location of cwd's extension storage, and the project root its project/session files live under. Additive.Params { cwd: string } & WireStorageLocationResult StorageSnapshot & { projectRoot?: string }
extensions.storage.set
Scopechat
DescriptionWrites (or, value absent, deletes) one storage entry. The extensions holding it see the change at once; every other connection gets extensions:storage. A stores write must be a { v, value } record of the store's version whose value passes its schema (checked against every runtime of the folder holding the store); otherwise it is refused and nothing changes. The result says which, with the entry as the host holds it now, for the client to reconcile. Additive (the result was void).Params { cwd: string, area: StorageArea, key: string, value?: Json } & WireStorageLocationResult WireStorageSetResult
extensions.settings
Scopechat
DescriptionThe extensions' settings of cwd with values, locks and the layer each value comes from. sessionId adds that session's layer. Additive.Params { cwd: string, sessionId?: string }Result WireExtensionSettings
extensions.settings.set
Scopeadmin
DescriptionWrites one extension setting at a scope: user in the settings file, project in the project's extension-settings.json, session in memory; a secret goes to the credentials file, never a settings file. Refused for a locked, unknown or action key, a scope the setting doesn't allow, or a value that fails its checks. Additive.Params SettingsSetParamsResult void
extensions.commands
Scopechat
DescriptionThe extension commands of cwd with their effective bindings, scopes and modes, and the keymap mode on top for sessionId. Additive.Params { cwd: string, sessionId?: string }Result WireExtensionCommands
extensions.command.run
Scopechat
DescriptionRuns a command by its published id (an extension command or a built-in). false when nothing ran. Additive.Params CommandRunParamsResult boolean
extensions.keymap.push
Scopechat
DescriptionActivates a keymap mode on the host for cwd (as ctx.keymap.mode.push) until extensions.keymap.pop or this connection closes. Returns its handle. Additive.Params { cwd: string, mode: string, priority?: number, sessionId?: string }Result string
extensions.keymap.pop
Scopechat
DescriptionPops a mode this connection pushed. Additive.Params { handle: string }Result boolean
extensions.keymap.list
Scopechat
DescriptionEvery command of cwd with its effective bindings, scope and mode (ctx.keymap.list), and the active mode stack for sessionId (ctx.keymap.active). Additive.Params { cwd: string, sessionId?: string }Result WireKeymap
extensions.integrations.list
Scopechat
DescriptionThe extension integrations of cwd (ctx.integrations.register) and their connections. Additive.Params { cwd: string }Result WireIntegration[]
extensions.integrations.connectKey
Scopeadmin
DescriptionConnects with an API key: verified by the extension, then kept in the credentials file. Additive.Params { cwd: string, integrationId: string, key: string, methodId?: string }Result WireIntegration
extensions.integrations.start
Scopeadmin
DescriptionRuns an OAuth or command method. Its steps (open this URL, enter this code, paste the redirect) come to this connection as extensions:integration-flow with the returned flowId; the call resolves when the flow ends. Additive.Params { cwd: string, integrationId: string, methodId: string, flowId?: string }Result WireIntegration
extensions.integrations.flowInput
Scopeadmin
DescriptionAnswers a flow step that asked for input (inputId). value absent cancels the flow. Additive.Params { flowId: string, inputId: string, value?: string }Result boolean
extensions.integrations.disconnect
Scopeadmin
DescriptionRemoves the connection of account, or every connection of the integration when it is absent. Additive.Params { cwd: string, integrationId: string, account?: string }Result void
extensions.integrations.setDefault
Scopeadmin
DescriptionMakes the connection of account the integration's default. Additive.Params { cwd: string, integrationId: string, account: string }Result void
extensions.catalogs.provenance
Scopechat
DescriptionWhich catalog items of cwd extensions added, changed or removed, with the extension that did it (Settings shows it). Additive.Params { cwd: string, kind: CatalogKind }Result CatalogItemProvenance[]
extensions.browse
Scopeadmin
DescriptionThe extensions of a source (owner/repo[#ref][:dir], a GitHub URL, an npm package, or a folder on the host), read from their manifests by the host with its GitHub login; nothing runs. Never fails for an unreadable source: the listing carries error (the default source Tahul/zidane then lists the native catalog, builtin: true). Each row's install is what catalog.install takes (spec, extension). Additive.Params { source: string }Result ExtensionSourceListing
extensions.changeOrigin
Scopeadmin
DescriptionInstall an installed extension again from another source (GitHub or npm): the source must hold an extension of the same name (else the name-mismatch install error, its data an ExtensionInstallErrorData with the names found); the folder is replaced only once the new copy validated, and .install.json records the new source, which catalog.update then follows. A zidane-server takes scope: 'user' only, gated and audited as catalog.install. Additive.Params { name: string, scope: 'user' | 'project', source: string }Result { name: string, origin: ExtensionInstallOrigin, message: string, progress: string[] }
Methods of the RPC contracts that extensions register, called by protocol clients. A client's token must reach the method's scope (default chat). Events arrive on the rpc.event signal. RPC and contracts explains the contracts.
rpc.* methods
Method
Scope
Description
rpc.call
Scopechat
DescriptionCalls an extension's RPC method as this connection. Never throws for a failed call: a declared error, invalid input, a missing provider or a method whose scope this connection's token does not reach (rpc.forbidden; a local connection is not limited) comes back as ok: false with its type. directory (or cwd) picks the runtime; without it, the newest runtime that has the contract. callId lets rpc.cancel abort it. Also served as POST /rpc/<contract>/<method> on a zidane-server, with the same token. Additive.Params RpcCallParams & { cwd?: string }Result RpcResponseEnvelope
rpc.cancel
Scopechat
DescriptionAborts this connection's rpc.call of callId; it answers rpc.aborted. false when none is in flight. Additive.Params { callId: string }Result boolean
Dialogs and UI requests from extensions, routed to the client that views the session. A client answers a dialog with ui.dialog.answer and reports what it views through presence. Placements explains the routing.
ui.* methods
Method
Scope
Description
ui.client.announce
Scopechat
DescriptionWhat this connection shows and whether it shows dialogs: dialogs (ui:dialog) and UI requests (ui:client) go to the client viewing the session, else the last active one. Only announced clients get them. Send again on focus or session change. Additive.Params UiClientAnnounceResult void
ui.client.reply
Scopechat
DescriptionAnswers a ui:client request sent to this connection. false when it is no longer pending. Additive.Params { requestId: string, result: unknown }Result boolean
ui.dialog.answer
Scopechat
DescriptionAnswers a ui:dialog shown on this connection (answer absent: cancelled). false when it is no longer pending. Additive.Params { dialogId: string, answer?: unknown }Result boolean
ui.dialog.validate
Scopechat
DescriptionChecks one value of a form dialog shown on this connection: the field's error message, or null when it is valid (or the dialog is no longer pending here). Clients call it as the user edits a field and before they answer, and show the message under the field. The host checks the answer again: an answer with an invalid value makes the extension's ctx.ui.form reject, so a client must not answer until every field validates. Additive.Params { dialogId: string, key: string, value: unknown }Result string | null
The extensions' text references in prose: the patterns, then the views of the keys a client found.
references.* methods
Method
Scope
Description
references.providers
Scopechat
DescriptionThe extension text reference providers (ctx.registerReferences) of cwd: the patterns a client matches prose with. peek: only from a registry already built for cwd (null when none is), so a list of titles across projects never builds one per project. Additive.Params { cwd: string, peek?: boolean }Result ReferenceProviderWire[] | null
references.resolve
Scopechat
DescriptionThe views of the keys a client found, in order: null for one that names nothing. At most 50 keys per call. Additive.Params { cwd: string, items: { providerId: string, key: string }[] }Result (ExtensionReferenceView | null)[]
DescriptionThe extensions' items (ctx.registerBadgeActions) of a badge's menu in cwd; the built-in ones are the client's. Additive.Params { cwd: string, target: BadgeTarget }Result BadgeMenuItem[]
badges.run
Scopechat
DescriptionRuns an extension's badge item; the effect (copy, open, a notice) is the client's to apply. Additive.Params { cwd: string, source: string, id: string, target: BadgeTarget }Result BadgeActionEffect
A folder's extension side panels, run on the server. A failing panel answers its error as content, never as a JSON-RPC error. panels.watch is counted per connection: a client calls it when it shows a panel and panels.unwatch when it hides it, and a dropped connection releases its own; panel:changed goes to the watching connections only.
panels.* methods
Method
Scope
Description
panels.list
Scopechat
DescriptionThe side panels cwd's extensions register. A panel's load and onAction run on the host, bound to cwd and the session ctx names, with a hard timeout: a failing panel answers an empty content naming why (load) or ok: false (action), never an error. Additive.Params { cwd: string }Result PanelSummary[]
panels.load
Scopechat
DescriptionOne panel's content for ctx (the session it shows beside, what opened it). Additive.Params { cwd: string, panelId: string, ctx?: PanelLoadContextInput }Result PanelContent
panels.action
Scopechat
DescriptionRun one of a panel's actions (a row's or the footer's actionId, its payload). Additive.Params { cwd: string, panelId: string, actionId: string, payload?: unknown, ctx?: PanelLoadContextInput }Result { ok: true } | { ok: false, error: string }
panels.watch
Scopechat
DescriptionKeep a panel's live updates on: this connection gets panel:changed when its content changes. Calls count; a dropped connection releases its own. Additive.Params { cwd: string, panelId: string }Result void
panels.unwatch
Scopechat
DescriptionRelease one panels.watch of this connection.Params { cwd: string, panelId: string }Result void
A folder's extension command palette items, run on the server, watched like panels: palette.watch while the palette is open, palette.unwatch once it closes, palette:changed in between.
palette.* methods
Method
Scope
Description
palette.list
Scopechat
DescriptionThe command palette items cwd's extensions contribute (each item's source is its provider), and running one. A provider that fails lists one disabled row naming why; a failed run answers ok: false. Additive.Params { cwd: string, ctx: PaletteContext }Result PaletteItem[]
palette.run
Scopechat
DescriptionRun itemId on its provider (source); a nested list, a prompt or a draft comes back as result. Additive.Params { cwd: string, source: string, itemId: string, ctx: PaletteContext }Result { ok: true, result: PaletteRunResult } | { ok: false, error: string }
palette.watch
Scopechat
DescriptionAs panels.watch, for every provider of cwd: palette:changed. Additive.Params { cwd: string }Result void
palette.unwatch
Scopechat
DescriptionRelease one palette.watch of this connection.Params { cwd: string }Result void
DescriptionResolve inline ghost-text autocomplete daemon-side (the typing window's request IS the single computation): canonical resolver against the session cwd's extension registry. Latest-wins per session; a seq older than the newest seen returns { suggestion: null } without computing, and a newer request aborts an in-flight compute. The result additionally fans out as suggest:changed to every OTHER peer.Params { sessionId: string, text: string, caret: number, seq: number }Result { suggestion: string | null, seq: number, candidates?: string[] }
The picks a client remembers across apps, in the server's state.json.
prefs.* methods
Method
Scope
Description
prefs.get
Scopechat
DescriptionThe picks remembered across apps (state.json): effort and options per model, the next chat's model chain. null when none is. Additive.Params Record<string, never>Result HostComposerPrefs | null
The sidebar's views per space and the space on show, in the server's state.json: a web app finds them again in any browser. A client reads them (sidebar.getViews, sidebar.getSpace) and saves one when it changes (sidebar.setView, sidebar.setSpace); every client of the server shares them. The kit's view record also carries session, the id of the conversation last open in that space, which a client reopens when it switches back to the space; the server stores the record as given.
sidebar.* methods
Method
Scope
Description
sidebar.getViews
Scopechat
DescriptionThe sidebar views a client saved on this host, by space id (state.json's sidebarViews): each client checks what it reads. Additive.Params Record<string, never>Result Record<string, unknown>
sidebar.setView
Scopechat
DescriptionSaves one space's sidebar view (at most 4 KiB of JSON), stored as given: the kit's record is the filter axes plus session, the conversation last open in that space. Additive.Params { spaceId: string, view: Record<string, unknown> }Result void
sidebar.getSpace
Scopechat
DescriptionThe space a client's sidebar showed last, null when none was saved. Additive.Params Record<string, never>Result string | null
sidebar.setSpace
Scopechat
DescriptionSaves the space the sidebar shows. Additive.Params { spaceId: string }Result void
DescriptionCurrent presence snapshot; backfill for a freshly opened session list.Params Record<string, never>Result SessionPresence[]
presence.watch
Scopechat
DescriptionTag the calling peer as watching a session (one per connection; the TUI opens one connection per activated session). Sent as a notification right after the handshake. Detach is implicit; the daemon recomputes presence when the socket drops.Params { sessionId: string }Result void
Clients that run beside the host, such as the channels runner, register their state here. Every window gets integrations:changed when the list changes.
integrations.* methods
Method
Scope
Description
integrations.register
Scopechat
DescriptionReport an integration this client runs (a channel). Registering a name again from the same connection replaces it; a name another live connection registered is refused. It goes away when this connection closes. Every window gets integrations:changed. Additive.Params { name: string, kind: string, state: IntegrationState, detail?: string }Result void
integrations.update
Scopechat
DescriptionChange the state of an integration this connection registered; detail replaces the previous one (absent clears it). Additive.Params { name: string, state: IntegrationState, detail?: string }Result void
integrations.list
Scopechat
DescriptionThe integrations registered on this host, in registration order. Additive.Params Record<string, never>Result IntegrationInfo[]
What the server's machine can do: its OS, the tools on its PATH, the sandbox, the environment kinds and what it allows. The answer is cached for a minute; refresh: true probes again.
host.* methods
Method
Scope
Description
host.capabilities
Scopechat
DescriptionWhat this host can do: OS, tools on PATH, sandbox, environment kinds, what it allows. Cached a minute; refresh probes again.Params { refresh?: boolean }Result HostCapabilities
host.installTool
Scopeadmin
DescriptionInstall a missing tool on this host, as the host's user, when it can without root (toolInstall says run). Then probes again: capabilities is the new answer.Params { name: string }Result { ok: boolean, output: string, capabilities: HostCapabilities }
The server's self-update: its state, the setting and the newest release seen. Any token reads it (server.update.status); turning it on or off, checking now and installing now need admin. With it off, server.update.check downloads and verifies a newer release and reports state: 'ready'; server.update.install installs it.
server.* methods
Method
Scope
Description
server.update.status
Scopechat
DescriptionA zidane-server's self-update: its state, the setting, the newest release seen.Params Record<string, never>Result ServerUpdateStatus
server.update.configure
Scopeadmin
DescriptionTurn the zidane-server's self-update on or off.Params { enabled: boolean }Result ServerUpdateStatus
server.update.check
Scopeadmin
DescriptionCheck for a newer zidane-server release now. With auto-update on, a newer one installs; off, it is downloaded and verified, and the state turns ready.Params Record<string, never>Result ServerUpdateStatus
server.update.install
Scopeadmin
DescriptionInstall the release that is ready or waiting now, without waiting for background work to finish.Params Record<string, never>Result ServerUpdateStatus
The folders of the server's workspace roots, for a folder picker: list them, search them by name (bounded), and create one (allowCreateFolders). Each takes a chat token. A path outside the roots is refused.
fs.* methods
Method
Scope
Description
fs.roots
Scopechat
DescriptionWhere this host lets a session's folder be: a server's workspace roots (confined: sessions.create / setFolder refuse anything outside), or the user's home on a local host (unconfined). Additive.Params Record<string, never>Result FsRoots
fs.listDirs
Scopechat
DescriptionThe folders in path (default: the first root), for a folder picker on the host's machine. Only inside the roots (real paths: .. and symlinks out are refused), no dotfiles. Additive.Params { path?: string }Result FsDirListing
fs.mkdir
Scopechat
DescriptionCreates folder name in parent (inside the roots, real paths: .. and symlinks out are refused). name is one path segment and does not start with a dot. Refused when the host turns it off (a zidane-server's allowCreateFolders, the hello's createFolders). Additive.Params { parent: string, name: string }Result FsDirEntry
fs.searchDirs
Scopechat
DescriptionThe folders whose name holds query (case-insensitive), in path and below it (default: every root). Bounded: four levels down, 200 results, no dot folders, no node_modules, symlinks not followed. truncated: the result or read bound cut the search short. Additive.Params { query: string, path?: string }Result FsDirSearch
A folder's git checkout, inside the server's workspace roots. The writes git.checkout, git.createBranch and git.sync need an admin token. git.clone needs a chat token, and the server refuses it while allowClone is off. A clone's progress comes as git:clone:progress signals to the connection that started it. A connection that calls git.watch gets git:refs for that folder once its refs move (a commit, a fetch, a branch switch, from any process on the server), until it calls git.unwatch or drops. git.commit reads one commit's facts, for a transcript's SHA chip.
DescriptionThe local branches, most recently committed first, each against the default branch.Params { cwd: string }Result GitBranchRow[]
git.pullRequests
Scopechat
DescriptionOpen pull requests (gh): waiting on you, yours, then recent others; search searches every open one. null without gh (or signed out); rateLimited while GitHub refuses and nothing is cached.Params { cwd: string, search?: string, fresh?: boolean }Result GitPrListResult
git.branchPullRequest
Scopechat
Descriptionbranch's open (or draft) pull request, or null. fresh: past the cache.Params { cwd: string, branch: string, fresh?: boolean }Result GitPr | null
git.commit
Scopechat
DescriptionOne commit's facts, for a sha chip; null when the repository has no such commit.Params { cwd: string, sha: string }Result GitCommitInfo | null
git.fileStatus
Scopechat
DescriptionEach changed path's status against HEAD, untracked files included.Params { cwd: string }Result GitStatusEntry[]
git.diff
Scopechat
DescriptionThe working tree against HEAD as a unified patch (untracked files as new files), the whole checkout or one path, with context lines (absent: 3; null: whole files).Params { cwd: string, path?: string, context?: number | null }Result string
git.checkout
Scopeadmin
DescriptionSwitches the checkout to a branch or a pull request ({ pr }, through gh). Never forced; refused while an agent runs in the checkout (sessionId: the asking session, counted too). A branch another worktree holds is git's refusal plus that worktree and its sessions (sessionId left out).Params { cwd: string, target: GitSwitchTarget, sessionId?: string }Result GitCheckoutResult
git.createBranch
Scopeadmin
DescriptionStarts branch name from the current checkout and switches to it; refused while an agent runs in it.Params { cwd: string, name: string, sessionId?: string }Result GitCheckoutResult
git.sync
Scopeadmin
DescriptionPulls (merging) then pushes the current branch, or publishes it without an upstream; refused while an agent runs in it.Params { cwd: string, sessionId?: string }Result GitSyncResult
git.clone
Scopechat
DescriptionClones input (a git or forge URL, or owner/repo) into a new folder of parent (inside the roots). A folder already holding that repository is answered as existed. One clone per connection; git's progress comes as git:clone:progress signals to the caller only. A dropped connection cancels it. Refused when the host turns cloning off (a zidane-server's allowClone, the hello's clone).Params { input: string, parent: string }Result RepoCloneResult
git.cloneCancel
Scopechat
DescriptionCancels this connection's clone: the half-cloned folder is removed and git.clone answers cancelled.Params Record<string, never>Result void
git.watch
Scopechat
DescriptionFollows cwd's checkout: once its refs move (a commit, a fetch, a push, a branch switch, from this host or any other process), this connection gets git:refs for cwd. false: not a repository, nothing watched. Calls count: each git.watch takes one git.unwatch; a dropped connection releases its own. Additive.Params { cwd: string }Result boolean
git.unwatch
Scopechat
DescriptionReleases one git.watch of cwd by this connection.Params { cwd: string }Result void
A folder's files beyond a session's workspace: search in files, what names in prose point at (files.resolvePaths, for a transcript's path chips), the project's own diagnostics (files.diagnostics runs project tools: admin), and its media. Diagnostics are cached until the files move; files.diagnosticsInvalidate drops a folder's cache so the next run checks again, and files.diagnosticsTools lists the tools and whether each runs there, for a settings list.
An <img> or <video> can't send a token, so media go over HTTP under a ticket: the client picks a random one (at least 32 URL-safe characters) and registers it with files.mediaTicket on each connection; it is good while that connection is open. GET /zidane/media?ticket=…&cwd=…&path=… serves a file of a folder in the workspace roots, &side=old or &side=new one side of its git change (the repository must lie in the roots too). Only image, video and audio types are served, with byte ranges, at most 64 MiB per response (a longer range is cut short, a larger whole file refused with 413), never sniffed into another type (X-Content-Type-Options: nosniff) and sandboxed if opened as a document. A missing or dropped ticket is 401, anything outside the roots 404.
files.* methods
Method
Scope
Description
files.search
Scopechat
DescriptionLines containing query (fixed string, at most 500 characters) under cwd: ripgrep, else git grep, else a walk. A later search with the same searchId on the connection cancels this one.Params { cwd: string, query: string, caseSensitive?: boolean, searchId?: string }Result ContentSearchResult
files.resolvePaths
Scopechat
DescriptionWhat names in prose point at (files, folders, else branches), in order: what a transcript's path chips open.Params { cwd: string, texts: string[] }Result ResolvedPath[]
files.list
Scopechat
DescriptionThe files under cwd and the folders holding them, as @ completes them: git's list (ignore rules kept), else a walk; capped.Params { cwd: string }Result FileEntry[]
files.location
Scopechat
DescriptionWhere cwd sits: its git checkout (the folder itself outside git) and its project (the main checkout for a worktree).Params { cwd: string }Result FolderLocation
files.diagnostics
Scopeadmin
DescriptionRuns the project's own linters and typecheckers on paths (relative to cwd), cached until the files move. disabled: tool ids switched off; timeoutMs: per tool.Params { cwd: string, paths: string[], disabled?: string[], timeoutMs?: number }Result DiagnosticsResult
files.diagnosticsInvalidate
Scopechat
DescriptionDrops the cached diagnostics of cwd: the next run checks again.Params { cwd: string }Result void
files.diagnosticsTools
Scopechat
DescriptionThe diagnostics tools and whether each runs for cwd (configured, missing its binary, not used).Params { cwd: string }Result DiagnosticsToolInfo[]
files.mediaTicket
Scopechat
DescriptionLets this connection's media play from GET /zidane/media (SERVER_MEDIA_PATH): ?ticket&cwd&path serves a file of a folder in the workspace roots, &side=old|new one side of its git change, with byte ranges, for an image, a video or audio only. The client picks the ticket (at least 32 random URL-safe characters) so an address is known before the call lands; it is good while this connection is open and carries its token's scope. One per connection: a new one replaces it. Only a zidane-server serves media. Additive.Params { ticket: string }Result void
The welcome screen's numbers over the server's session store, as the desktop app sums its own. Days are the server's local days.
usage.* methods
Method
Scope
Description
usage.summary
Scopechat
DescriptionToken spend, models, streaks and activity over range, from the host's session store, as the desktop app's welcome screen shows its own (summarizeUsage). Days are the host's local days; userName is null (the host's user is not the reader). Refused by a store that keeps no usage history (not a SQLite file). Additive.Params { range: UsageRange }Result UsageSummary
usage.providers
Scopechat
DescriptionThe plan and subscription windows of each provider the host holds a credential for (every account), probed with the host's credentials and cached a few minutes; refresh probes past the cache. A provider that can't be read reports status: 'unavailable'. Additive.Params { refresh?: boolean }Result readonly ProviderUsageSnapshot[]
usage.github
Scopechat
DescriptionGitHub's API limits as the host's GitHub client last saw them, per GitHub host; probe asks GitHub (/rate_limit, which costs no call). Additive.Params { probe?: boolean }Result ProviderUsageSnapshot[]
auth.remove is also a sign-out: it drops one stored credential, or all of them.
A browser can't listen on a loopback port for an OAuth redirect, so a browser client signs in to an MCP server through the server: it passes redirectUri as <origin>/zidane/oauth/callback, the origin it reaches the server by. The server registers that redirect, takes the code at that address itself, and answers begin with mode: 'browser'. The client opens url and calls auth.oauth.complete with no code; it resolves once the token exchange is done. A server whose pre-registered client pins its redirect stays 'loopback': the user pastes the address of the page that failed to load (complete with input). The code is matched to the flow by its state, which is random and single-use. An MCP server's stored client registered for another redirect registers again.
auth.* methods
Method
Scope
Description
auth.status
Scopechat
DescriptionThe host's provider credentials, as the host's agents use them (its data dir's credentials.json and environment): per provider, whether something is configured, its stored API key / OAuth accounts (labels, which is active) and an env var it reads. Never a secret. Additive.Params Record<string, never>Result { providers: HostProviderAuth[] }
auth.setApiKey
Scopeadmin
DescriptionStore an API key for one of the host's providers as its active credential, apply it to the host's environment, and rebuild agents (idle now, busy ones at run end). Returns the provider's new status. OAuth sign-in goes through auth.oauth.*. Additive.Params { provider: string, key: string }Result HostProviderAuth
auth.remove
Scopeadmin
DescriptionRemove one stored credential (account: its key from auth.status) or, without one, every stored credential of the provider; then as auth.setApiKey. A key the host only has from its own environment is left alone. Additive.Params { provider: string, account?: string }Result { removed: boolean, provider: HostProviderAuth }
auth.configure
Scopeadmin
DescriptionStores a provider's API key and its custom fields (a local server's URL, a cloud's region; onboarding.providers lists them), merged into the stored credential: a field left out keeps its value, an empty one is removed (a blank secret keeps the stored one), a required one may not be emptied, no value keeps the stored key. Additive.Params { provider: string, value?: string, customFields?: Record<string, string> }Result HostProviderAuth
auth.setPreferred
Scopeadmin
DescriptionMake one of a provider's stored credentials the active one (target: an account key from auth.status, or the first stored one of a source), then as auth.setApiKey. A credential no longer stored is refused. Additive.Params { provider: string, target: 'apikey' | 'oauth' | { key: string } }Result HostProviderAuth
auth.rename
Scopeadmin
DescriptionRename a stored OAuth account (account: its key from auth.status). Presentation only: nothing is rebuilt. Additive.Params { provider: string, account: string, label: string }Result HostProviderAuth
auth.oauth.begin
Scopeadmin
DescriptionOAuth sign-in with the browser on the CLIENT and the tokens on the host: the host starts a provider's login (provider) or an MCP server's (mcpServer, found in cwd's catalog, as catalog.mcps), keeping the PKCE verifier and state, and answers with the authorization URL. mode: 'loopback': the client listens at redirectUri (a provider's fixed port; for an MCP server the loopback URI the client passed) and forwards the code; 'browser': the client opens url (pasting a code if the page shows one); 'device': shows userCode. The flow belongs to this connection, is single-use and expires (expiresAt). Additive. A client that can't listen (a browser) signs in to an MCP server through a zidane-server's own redirect: redirectUri is the server's /zidane/oauth/callback (SERVER_OAUTH_CALLBACK_PATH) at the origin the client reaches it by. The server takes the code there and the flow is 'browser' (the client opens url, then completes without a code). A server whose pre-registered client pins its redirect stays 'loopback': its page fails to load and the user pastes that page's address (complete with input). account (a provider's only): the stable id of a stored OAuth account (AuthFailure.accountId) this sign-in re-authenticates. Its tokens replace that account's in place (same slot, id and name), instead of becoming a new active account. An id the host does not store is refused. Additive.Params { provider?: string, account?: string, mcpServer?: string, cwd?: string, kind?: string, redirectUri?: string }Result HostOAuthBegin
auth.oauth.complete
Scopeadmin
DescriptionDeliver the code (code + state from the loopback, or input: what the user pasted) once, then wait for the host's token exchange; without either, just wait (device and polling flows). A wrong state or another connection's flow is refused. Tokens stay on the host: the result says what changed, never a secret.Params { flowId: string, code?: string, state?: string, input?: string }Result HostOAuthComplete
auth.oauth.respond
Scopeadmin
DescriptionAnswer the step a flow is waiting on (HostOAuthBegin.step before its URL, HostOAuthComplete.step after): a select's option id (none: cancel), a prompt's text. Answers with where the flow is now: its URL, or the next step. Then complete as before. Additive.Params { flowId: string, stepId: string, value?: string }Result HostOAuthBegin
auth.oauth.cancel
Scopeadmin
DescriptionAbandon a flow of this connection.Params { flowId: string }Result { cancelled: boolean }
DescriptionWhat the host discovered for the settings tabs, each entry with whether the host's settings enable it (an unset allowlist enables everything). cwd adds the project scope of that folder (inside the workspace roots on a server); without it, the user scope (the host user's home). The enabled lists are written with settings.set. Installing, removing and MCP sign-in stay on the host's machine. Additive.Params { cwd?: string, kind?: string }Result { skills: HostCatalogSkill[] }
catalog.mcps
Scopechat
DescriptionMCP servers: env and headers values, URL credentials and query values are redacted.Params { cwd?: string, kind?: string }Result { servers: HostCatalogMcp[], errors: HostCatalogError[] }
DescriptionPlugins installed for cwd, with what each contributes.Params { cwd?: string, kind?: string }Result { plugins: HostCatalogPlugin[] }
catalog.install
Scopeadmin
DescriptionInstall a skill or an extension on the host, in its user's scope only (scope may only be 'user'): a GitHub (owner/repo[#ref][:dir], a GitHub URL, a skills.sh URL) or npm spec; paths are refused. skills / all pick from a multi-skill source (the multiple-candidates error lists them), extension from a multi-extension one (an extension's multiple-candidates or no-extension error carries the names found as ExtensionInstallErrorData). Runs the host's package managers and fetches code there: a zidane-server's allowRemoteInstalls gates it, every attempt is audited. Bounded in time; the progress lines come back with the result. Every window gets catalog:changed. Additive (remoteInstalls on ipc.hello).Params { kind: HostInstallKind, spec: string, scope?: 'user', skills?: string[], all?: boolean, extension?: string, overwrite?: boolean }Result { installed: string[], message: string, progress: string[] }
catalog.remove
Scopeadmin
DescriptionRemove a user-scope skill or extension of the host by name (its directory). As catalog.install.Params { kind: HostInstallKind, name: string }Result { removed: string, message: string }
catalog.update
Scopeadmin
DescriptionUpdate a user-scope extension installed from a source. As catalog.install.Params { kind: HostInstallKind, name: string }Result { updated: string, upToDate: boolean, message: string }
DescriptionThe skills of a source (owner/repo[#ref][:dir], a GitHub or skills.sh URL), fetched by the host with its GitHub login; catalog.install with skills installs picked ones. Additive.Params { source: string }Result SkillSourceListing
What the setup wizard finds on the server's machine and the providers it lists, with their custom fields (stored with auth.configure).
onboarding.* methods
Method
Scope
Description
onboarding.detect
Scopechat
DescriptionWhat the setup wizard finds on the host's machine for cwd (default: the host user's home): the providers and their credentials, other agents to import from, local model servers and the install signals. Additive.Params { cwd?: string }Result OnboardingDetection
onboarding.providers
Scopechat
DescriptionThe providers as the wizard's Connect step lists them, with their custom fields and the model each runs when none is picked. Additive.Params { cwd?: string }Result HostOnboardingProvider[]
onboarding.complete
Scopeadmin
DescriptionThe setup wizard's write: settings.set sets (settings.reset back to their defaults, unless also set), as settings.set applies them, and records (the run finished, its steps) merged into the host's stored ones. Returns the settings in effect. Additive.Params { settings: OnboardingSettingsChange, records: OnboardingState }Result HostSettings
A Claude Code setup in the server user's ~/.claude: claudeImport.detect says whether there is one, claudeImport.preview what each piece would copy and skip, and claudeImport.run imports it. The import copies commands the server will run: admin, behind allowRemoteInstalls.
claudeImport.* methods
Method
Scope
Description
claudeImport.detect
Scopeadmin
DescriptionWhat ~/.claude on the host holds: whether there is a setup, and its transcripts for cwd and in every project. Additive.Params { cwd?: string }Result ClaudeImportDetection
claudeImport.preview
Scopeadmin
DescriptionWhat each piece of the Claude Code import would copy and skip. Additive.Params { cwd?: string }Result OnboardingImportPreview
claudeImport.run
Scopeadmin
DescriptionImports a Claude Code setup into the host's own places: conversations into its session store, MCP servers, skills, commands and subagents into the host user's files. Idempotent (what is there is skipped, never overwritten). It copies commands the host will run: a zidane-server's allowRemoteInstalls gates it, every attempt is audited. Every window gets catalog:changed. Additive.Params { cwd?: string } & ClaudeImportSelectionResult ClaudeImportSummary
catalog.mcps rows carry each server's status: its sign-in state, its tools as last listed and its last Test. A stdio row always says where it runs (scope: host or context), and shared comes from its config. An absent shared means shared, and the mcpSharing setting wins over it. mcp.upsert writes the server user's mcps.json, or with scope: 'project' the project of cwd. An Advanced OAuth client secret goes in clientSecret. The server keeps it in its MCP credential store, never in mcps.json.
mcp.* methods
Method
Scope
Description
mcp.upsert
Scopeadmin
DescriptionAdd or replace an MCP server in the host user's mcps.json, or with scope: 'project' in cwd's project (a folder inside the workspace roots on a server). Its env / headers values are stored there and never come back (catalog.mcps redacts them, the reply names the server only). clientSecret, the secret of its oauth client, goes to the host's MCP credential store, never to mcps.json; an entry without an oauth client drops a stored one. As catalog.install.Params { config: McpServerConfig, scope?: 'user' | 'project', cwd?: string, clientSecret?: string }Result { name: string, created: boolean }
mcp.remove
Scopeadmin
DescriptionRemove an MCP server from the host user's mcps.json; removed: false when it has none. As catalog.install.Params { name: string }Result { removed: boolean }
mcp.test
Scopechat
DescriptionConnect to one of cwd's MCP servers (as catalog.mcps), list its tools into the host's tools cache and record how it went: the server's new status. Every window gets catalog:changed. Additive.Params { name: string, cwd?: string, kind?: string }Result McpServerStatus
mcp.signOut
Scopeadmin
DescriptionForget an MCP server's sign-in on the host (its tokens). Every window gets catalog:changed. Additive.Params { name: string }Result void
mcp.instances
Scopechat
DescriptionThe host's shared MCP server processes (src/mcp/server-pool.ts), cwd's only when given: name, folder, shared or per session, how many sessions hold it, its pid, whether it is retired. Remote servers and scope: 'context' ones are never listed (they are per session). Additive.Params { cwd?: string }Result McpServerInstance[]
mcp.restart
Scopeadmin
DescriptionEnd name's process now (in cwd only, when given) for every session holding it. Calls in flight fail with "<name> restarted" and are not retried; the next call starts a fresh process. Answers how many processes were restarted (0: none was running). Additive.Params { name: string, cwd?: string }Result { restarted: number }
DescriptionThe host's credentialed providers (what its agents can run) and their models, for a model picker of a session on that host. cwd adds the providers its extensions contribute there. Additive.Params { cwd?: string, kind?: string }Result { providers: HostModelProvider[] }
models.test
Scopechat
DescriptionSend one tiny prompt with this host's credentials, to check a chat model answers. model is "providerKey[@account]/modelId", tested exactly. Never fails: a broken model comes back as ok: false with a reason. Additive.Params { cwd?: string, kind?: string, model: string }Result HostModelTestResult
DescriptionSend one tiny decision with this host's credentials, to check a decision model works. model is "providerKey/modelId", tested exactly; omitted = the host's Settings.decisionModel (or the first available). Never fails: a broken model comes back as ok: false with a reason. Additive.Params { cwd?: string, kind?: string, model?: string }Result HostDecisionTestResult
DescriptionThe machines this host knows (docs/MACHINES.md), online or not, and forgetting one (it disconnects; its local@ / worktree@ kinds stop resolving). Additive.Params Record<string, never>Result MachineInfo[]
machines.forget
Scopeadmin
DescriptionForgets a machine. It disconnects and its kinds stop resolving.Params { machineId: string }Result { forgotten: boolean }
machines.listDirs
Scopechat
DescriptionFolders of a machine, for a client's folder picker: the host proxies a listing to the machine (fs.list, confined to its roots there): the folders in path (absent: its first root), and every root. Additive.Params { machineId: string, path?: string }Result { path: string, dirs: string[], roots: string[] }
machines.share.start
Scopeadmin
DescriptionA local host's machine links (docs/MACHINES.md § Client UI), behind remote hosts: share this computer with a saved server (the machine agent runs in this host's process, with the machine token token or the one already stored for that server), stop sharing, use a saved server as a machine (reverse direction), and read their state. Refused while remote hosts are off. Additive.Params { hostId: string, name: string, roots: string[], token?: string }Result MachineLinksStatus
machines.share.stop
Scopeadmin
DescriptionStops sharing this computer with a server.Params { hostId: string }Result MachineLinksStatus
machines.useServer
Scopeadmin
DescriptionTurns on or off using a server as this computer's linked server.Params { hostId: string, enabled: boolean }Result MachineLinksStatus
machines.links.status
Scopechat
DescriptionState of this host's machine links: the shares it offers and the servers it uses.Params Record<string, never>Result MachineLinksStatus
DescriptionReverse direction (docs/MACHINES.md § Reverse direction): a client asks this server to lend itself as a machine over this very connection (allowAsMachine on, else refused). hostId names the asking host, so a reconnect finds its tasks and terminals again. Then machine.call carries each host→machine request (MachineMethods), answered by the server's confined executor; machine notifications come back as machine:notification signals on this connection only.Params { hostId: string }Result MachineRegisterParams
machine.call
Scopeadmin
DescriptionRuns one machine-protocol method on this server's executor and resolves with its JSON result. Refused when the server does not lend itself as a machine.Params { method: string, params?: JsonValue }Result JsonValue
machine.detach
Scopeadmin
DescriptionEnds this connection's machine attachment. detached is false when it had none.Params Record<string, never>Result { detached: boolean }
DescriptionMint a machine-scoped token on this server (a zidane-server only), so a window can share its computer in one step. An admin token may (./scopes). Audited.Params { name: string }Result { id: string, name: string, token: string }
tokens.list
Scopeadmin
DescriptionThis server's tokens, revoked ones included, never their secrets (a zidane-server only). Additive.Params Record<string, never>Result ServerTokenInfo[]
tokens.create
Scopeadmin
DescriptionCreate a token with a scope (./scopes; machine lends a computer). The secret is in the result only: show it once. Bound to the calling token (createdBy), so revoking that one revokes this one too. Audited. Additive.Params { name: string, scope: ServerTokenScope }Result ServerTokenInfo & { token: string }
tokens.revoke
Scopeadmin
DescriptionRevoke a live token by id, with the live tokens it minted; their connections drop and the runs and terminals they started stop. Audited. Additive.Params { id: string }Result { revoked: ServerTokenInfo[] }
tokens.revokeSelf
Scopechat
DescriptionRevoke the token this connection authenticated with, and the live tokens it minted (a browser's sign out). Any client scope may: it only gives up its own access. Audited. Additive.Params Record<string, never>Result { revoked: ServerTokenInfo[] }
tokens.pair
Scopeadmin
DescriptionIssue a one-time pairing code (XXXX-XXXX, a zidane-server only): a browser posts it to POST /zidane/pair and gets a token of scope, named browser: <name> and bound to the calling token (createdBy). ttlMs: 30000 to 3600000, default 600000. Single use; five wrong secrets burn it. Audited. Additive.Params { scope: ClientScope, ttlMs?: number, name?: string }Result { code: string, expiresAt: number }
tokens.machineInvite
Scopeadmin
DescriptionIssue a one-time machine join code (a zidane-server only): a machine posts it to POST /zidane/pair and gets a machine token named name. A public server caps ttlMs at 10 minutes. Audited as pair.create with scope machine. Additive.Params { name?: string, ttlMs?: number }Result { code: string, expiresAt: number }
A zidane-server's recent log records: its own lines and its extensions' (setup, runtime warnings), from a bounded in-memory buffer. Admin only. logs.watch follows the log (logs:record for each new record) until the client calls logs.unwatch or drops; calls count per connection.
logs.* methods
Method
Scope
Description
logs.list
Scopeadmin
DescriptionA zidane-server's recent log records, oldest first: its own lines and its extensions' (setup, runtime warnings), from a bounded in-memory buffer. Other hosts refuse it. Additive.Params Record<string, never>Result { records: LogRecord[] }
logs.watch
Scopeadmin
DescriptionFollow the log: this connection gets logs:record for each new record. Calls count; a dropped connection releases its own. Additive.Params Record<string, never>Result void
logs.unwatch
Scopeadmin
DescriptionRelease one logs.watch of this connection.Params Record<string, never>Result void
The host's own performance, for a client's Settings › Performance on it: the host process as the root of its tree, what its sessions launched, its event loop and, on macOS, the GPU. Admin only. perf.watch sends perf:sample every 2 s until the client calls perf.unwatch or drops; calls count per connection, and the host samples only while a connection watches. perf.threads answers only for a process the host lists.
perf.* methods
Method
Scope
Description
perf.watch
Scopeadmin
DescriptionFollow the host's own performance (Settings › Performance on a server): this connection gets perf:sample every 2 s. The host samples only while a connection watches. Calls count; a dropped connection releases its own. Additive.Params Record<string, never>Result void
perf.unwatch
Scopeadmin
DescriptionRelease one perf.watch of this connection. Additive.Params Record<string, never>Result void
perf.history
Scopeadmin
DescriptionThe samples the host holds (the last 5 minutes of watching), oldest first. Additive.Params Record<string, never>Result { samples: PerfSample[] }
perf.threads
Scopeadmin
DescriptionThe OS threads of one of the processes the host lists (its own tree), busiest first. Refuses any other pid. Additive.Params { pid: number }Result { threads: PerfOsThread[] }
DescriptionSettings sync, a client's computer → this server (docs/SERVER.md § Settings sync). A zidane-server only; other hosts refuse. One source device per server: sync.claim makes the caller it (or says who is, unless takeover), sync.push applies one category's snapshot through the host's own setters, skipping fields edited here since (overrides), sync.reset drops an override, sync.release stops the source. Every call is audited with its token. Additive.Params Record<string, never>Result SyncStatus
sync.claim
Scopeadmin
DescriptionMakes the caller the settings source device. When another device is the source, the result says which, unless takeover is set. categories and keys narrow what it syncs.Params { deviceId: string, deviceName: string, takeover?: boolean, categories?: SyncCategory[], keys?: string[] }Result SyncClaimResult
sync.push
Scopeadmin
DescriptionApplies one category's snapshot from the source device.Params { deviceId: string, category: SyncCategory, payload: SyncPayload }Result SyncPushResult
sync.reset
Scopeadmin
DescriptionDrops the local override of one field so sync applies to it again.Params { field: string }Result { reset: boolean }
DescriptionDaemon identity and version: protocolVersion, appVersion, pid, startedAt and the host identity fields of the hello result.Params Record<string, never>Result HelloResult
daemon.ownedProcesses
Scopechat
DescriptionThe processes the daemon started for its own work (MCP servers, bounded tool runs such as git and linters), which lead their own process group like a session's command does. The desktop app's performance monitor counts them as the app's. Additive: an older daemon answers "method not found", read as none.Params Record<string, never>Result OwnedProcess[]
daemon.sessionProcesses
Scopechat
DescriptionThe processes the daemon started for a session (its shell tool's commands and background tasks, its terminals, its own MCP servers), by session id. The desktop app's performance monitor shows what each session uses. Additive: an older daemon answers "method not found", read as none.Params Record<string, never>Result SessionProcess[]
daemon.shutdown
Scopeadmin
DescriptionGraceful drain: deny pending approvals, abort live runs, close the socket. Used by clients that detect a protocol-version mismatch and need the stale daemon gone before respawning. whenIdle (version-skew retirement): a daemon with active work does NOT abort it. It answers { deferred: true } and exits once idle. Explicit stops (zidane daemon stop) omit it and drain immediately. Daemons predating the flag ignore it and drain immediately.Params { whenIdle?: boolean }Result { deferred?: boolean } | void