# zidane/ipc/browser

> zidane/ipc/browser — a zidane-server client that runs wherever a `WebSocket` does: browsers, workers, Node, Bun. No `node:*`, no `process`: the kit's server adapter (`zidane-ui/adapters`) and any web app build on it. Node and Bun clients that keep saved hosts, trust a CA or share a machine use `zidane/ipc/remote`, which adds those on top.

Import: `import { … } from 'zidane/ipc/browser'`. Source: [src/ipc/browser.ts](https://github.com/Tahul/zidane/blob/main/src/ipc/browser.ts).

## Functions

### `createExtensionsClient`

Function.

Wraps a connected client.

```ts
function createExtensionsClient(client: ExtensionsTransport): ExtensionsClient
```

**Parameters**

- `client` (`ExtensionsTransport`): A connected client.

**Returns** `ExtensionsClient`: The typed extension API client.

Source: [src/ipc/extensions-client.ts:177](https://github.com/Tahul/zidane/blob/main/src/ipc/extensions-client.ts#L177)

### `createServerClient`

Function.

Creates a client for a zidane-server and starts connecting. See the module docs for what it
handles; [`ServerClient`](https://zidane.si/docs/reference/ipc-browser.md#ServerClient) for what it offers.

```ts
function createServerClient(options: ServerClientOptions): ServerClient
```

**Parameters**

- `options` (`ServerClientOptions`): The server's `url`, the `token`, and optional transport and retry settings.

**Returns** `ServerClient`: The client, connecting.

**Example**

```ts
import { createServerClient } from 'zidane/ipc/browser'

const server = createServerClient({ url: 'wss://zidane.example.com', token })
const hello = await server.ready
if (server.can('sessions.list'))
  console.log(await server.call('sessions.list', {}), hello.scope)
```

Source: [src/ipc/browser.ts:262](https://github.com/Tahul/zidane/blob/main/src/ipc/browser.ts#L262)

### `extensionInstallErrorData`

Function.

The [`ExtensionInstallErrorData`](https://zidane.si/docs/reference/ipc-browser.md#ExtensionInstallErrorData) of a call's error `data`, or
`undefined` when it carries none.

```ts
function extensionInstallErrorData(data: unknown): ExtensionInstallErrorData | undefined
```

**Parameters**

- `data` (`unknown`): A JSON-RPC error's `data`, untrusted.

**Returns** `ExtensionInstallErrorData | undefined`

Source: [src/ipc/protocol.ts:436](https://github.com/Tahul/zidane/blob/main/src/ipc/protocol.ts#L436)

### `formatJoinString`

Function.

`<url>#<CODE>`.

```ts
function formatJoinString(url: string, code: string): string
```

**Parameters**

- `url` (`string`): The main server's client URL (`wss://…`).
- `code` (`string`): The join code (`XXXX-XXXX`).

**Returns** `string`

Source: [src/ipc/machine/join.ts:22](https://github.com/Tahul/zidane/blob/main/src/ipc/machine/join.ts#L22)

### `methodScope`

Function.

The scope a method needs, or `undefined` for a name outside the protocol.

```ts
function methodScope(method: string): 'chat' | 'admin' | undefined
```

**Parameters**

- `method` (`string`): A method name from the wire.

**Returns** `'chat' | 'admin' | undefined`

Source: [src/ipc/scopes.ts:380](https://github.com/Tahul/zidane/blob/main/src/ipc/scopes.ts#L380)

### `pairBrowser`

Function.

Trades a pairing code for a device token.

```ts
function pairBrowser(
  baseUrl: string,
  code: string,
  name?: string,
  options?: PairBrowserOptions,
): Promise<PairedBrowser>
```

**Parameters**

- `baseUrl` (`string`): The server's origin (`https://box.example`, or the `ws(s)://` URL the client uses). `''`: the page's own origin, for the web app the server serves.
- `code` (`string`): The code as the user typed it (`7KQM-3XFD`; the server ignores case and separators).
- `name?` (`string`): The browser's label, used when the operator gave none: the token is named `browser: <name>`.
- `options?` (`PairBrowserOptions`, default `{}`): A `fetch` to use instead of the global one.

**Returns** `Promise<PairedBrowser>`: The token, its id, scope and the server's name.

**Example**

```ts
import { createServerClient, pairBrowser, ServerPairError } from 'zidane/ipc/browser'

try {
  const { token } = await pairBrowser('https://box.example', '7KQM-3XFD', 'Firefox on the laptop')
  const client = createServerClient({ url: 'wss://box.example', token })
}
catch (error) {
  if (error instanceof ServerPairError && error.reason === 'expired')
    console.log('Run zidane-server pair again')
}
```

Source: [src/ipc/browser-pair.ts:93](https://github.com/Tahul/zidane/blob/main/src/ipc/browser-pair.ts#L93)

### `parseJoinString`

Function.

`{ url, code }` from a join string (spaces around it, any case in the
code, the dash optional); `null` unless the url is ws\:// or wss\:// with a
host and the code is 8 symbols of the alphabet. The code comes back as
`XXXX-XXXX`, the url without a trailing slash.

```ts
function parseJoinString(s: string): { code: string; url: string } | null
```

**Parameters**

- `s` (`string`): The join string as pasted.

**Returns** `{ code: string; url: string } | null`

Source: [src/ipc/machine/join.ts:34](https://github.com/Tahul/zidane/blob/main/src/ipc/machine/join.ts#L34)

### `runBlockOnHost`

Function.

Runs a reply's shell block on a host and resolves with the saved run. Rejects with the host's reason when the
block could not run.

```ts
function runBlockOnHost(
  client: BlockRunClient,
  sessionId: string,
  request: BlockRunRequest,
  options?: BlockRunOnHostOptions,
): Promise<BlockRun>
```

**Parameters**

- `client` (`BlockRunClient`): The host's client.
- `sessionId` (`string`): The session the reply is in.
- `request` (`BlockRunRequest`): The block.
- `options?` (`BlockRunOnHostOptions`, default `{}`): Output listener and stop signal.

**Returns** `Promise<BlockRun>`

Source: [src/ipc/block-run.ts:37](https://github.com/Tahul/zidane/blob/main/src/ipc/block-run.ts#L37)

### `scopeAllows`

Function.

Whether a connection granted `granted` may call a method that needs `required`.

```ts
function scopeAllows(granted: 'chat' | 'admin', required: 'chat' | 'admin'): boolean
```

**Parameters**

- `granted` (`'chat' | 'admin'`): The connection's scope.
- `required` (`'chat' | 'admin'`): The method's scope ([`METHOD_SCOPES`](https://zidane.si/docs/reference/ipc-browser.md#METHOD_SCOPES)).

**Returns** `boolean`

Source: [src/ipc/scopes.ts:48](https://github.com/Tahul/zidane/blob/main/src/ipc/scopes.ts#L48)

## Classes

### `ServerCallError`

Class.

A call the server answered with an error: its JSON-RPC `code` and `data`.

```ts
class ServerCallError extends Error
```

**Constructor**

```ts
new ServerCallError(message: string, code: number, data?: unknown)
```

**Parameters**

- `message` (`string`): The server's message.
- `code` (`number`): The JSON-RPC error code.
- `data?` (`unknown`): The error's data.

**Returns** `ServerCallError`

**Properties**

- `code` (`number`, readonly): The JSON-RPC error code ([`IpcErrorCode`](https://zidane.si/docs/reference/ipc-browser.md#IpcErrorCode) names zidane's own).
- `data?` (`unknown`, readonly): The error's data, when it had some (a `Forbidden` refusal's `required` scope).

Source: [src/ipc/browser.ts:82](https://github.com/Tahul/zidane/blob/main/src/ipc/browser.ts#L82)

### `ServerConnectionError`

Class.

A call that couldn't be answered: the connection dropped, or the client was refused or closed.

```ts
class ServerConnectionError extends Error
```

**Constructor**

```ts
new ServerConnectionError(message: string, state: ServerClientState)
```

**Parameters**

- `message` (`string`): What happened.
- `state` (`ServerClientState`): The client's state when the call failed.

**Returns** `ServerConnectionError`

**Properties**

- `state` (`ServerClientState`, readonly): The client's state when the call failed: `refused` names why, for good.

Source: [src/ipc/browser.ts:101](https://github.com/Tahul/zidane/blob/main/src/ipc/browser.ts#L101)

### `ServerPairError`

Class.

A refused or failed pairing, with its [`ServerPairFailure`](https://zidane.si/docs/reference/ipc-browser.md#ServerPairFailure).

```ts
class ServerPairError extends Error
```

**Constructor**

```ts
new ServerPairError(reason: ServerPairFailure, status?: number)
```

**Parameters**

- `reason` (`ServerPairFailure`): Why it failed.
- `status?` (`number`): The HTTP status, when the server answered.

**Returns** `ServerPairError`

**Properties**

- `reason` (`ServerPairFailure`, readonly): Why it failed.
- `status?` (`number`, readonly): The HTTP status, when the server answered.

Source: [src/ipc/browser-pair.ts:22](https://github.com/Tahul/zidane/blob/main/src/ipc/browser-pair.ts#L22)

## Constants

### `CLIENT_SCOPES`

Constant.

A client token's reach, from the narrowest.

```ts
const CLIENT_SCOPES: readonly ['chat', 'admin']
```

Source: [src/ipc/scopes.ts:29](https://github.com/Tahul/zidane/blob/main/src/ipc/scopes.ts#L29)

### `IPC_MIN_PROTOCOL_VERSION`

Constant.

The oldest protocol version this build still speaks, as a client and as a
zidane-server. A server accepts a client whose range
(`minProtocolVersion`…`protocolVersion`) overlaps its own, and the
connection speaks the lower of the two versions, so a web app deployed
against one release keeps working after the server moves one version on.
Raise it only when the code that speaks a version is removed. A local
daemon keeps the exact-version fence: it is respawned on upgrade.

```ts
const IPC_MIN_PROTOCOL_VERSION: number
```

Source: [src/ipc/protocol.ts:383](https://github.com/Tahul/zidane/blob/main/src/ipc/protocol.ts#L383)

### `IPC_PROTOCOL_VERSION`

Constant.

Changes since v5. Entries marked additive, or "no version bump", did
not raise the version. The current version is `IPC_PROTOCOL_VERSION`.

- `event` signals carry an optional `echo` flag marking host-generated
  SEND/STEER echoes of the user's own message.
- `chat.pushQueued` result gained the `'queued'` delivered variant.
- `sessions.setModel` now honors `fallbacks`: it persists the canonical
  `metadata.modelChain` and CLEARS a previously persisted chain when
  omitted/empty. It also accepts `effort` / `modelOptions` and resets
  both when omitted (a pick is atomic — no stale per-model knobs).
- additive: `extension.emit` notification + `extension:signal` fan-out
  (the permission-gated per-extension cross-window bus, `ctx.bus`;
  removed in zidane 10).
  Older daemons ignore the unknown notification; older clients drop the
  unknown signal kind — no version bump needed.
- additive: `extension.emit` / `extension:signal` carry an optional
  `nonce` (the emitter's per-process random id) so receivers dedupe on
  `(extensionId, nonce, seq)` instead of the collision-prone
  `(extensionId, seq)`. Older peers omit it and fall back to the
  seq-only key — no version bump needed.
- `SessionRow.modelFallbacks` is now populated from the session's
  persisted `metadata.modelChain`.
- Default socket path moved from `<stateDir>/daemon.sock` to the
  dedicated `<stateDir>/daemon/daemon.sock` (dir chmod'd 0700) so the
  daemon can harden its socket dir without touching shared state files.
- ADDITIVE (no version bump — older daemons answer "method not
  found", clients degrade to local compute): `suggest.resolve` RPC
  resolves inline ghost-text autocomplete daemon-side, and the
  `suggest:changed` signal fans the result out to every OTHER peer
  on the session so mirroring windows paint the same ghost without
  recomputing.
- ADDITIVE (no version bump — optional field, older daemons simply
  omit it and clients fall back to the single `suggestion`):
  `suggest.resolve` results and `suggest:changed` signals carry the
  resolver's full ordered `candidates` list so daemon mode keeps
  ↑/↓ candidate rotation instead of degrading to one suggestion.
- ADDITIVE (no version bump — `optional()` swallows "method not
  found" on an older daemon, which then simply keeps its stale
  registries as before): `runtime.reload` RPC drops the daemon's
  cached extension registries and retires live agents after a window
  reloaded its extensions.
- ADDITIVE (no version bump): `terminal.registerViewer` /
  `terminal.unregisterViewer`. The desktop app registers as a client that
  can show terminals; agents only get terminal tools while one is
  attached. An older daemon answers "method not found" (and keeps giving
  every agent the tools, as before); an older desktop app on a newer
  daemon never registers, so its agents run without terminal tools.
- ADDITIVE (no version bump): project / draft terminals
  (docs/PROJECT-SCOPE-AUDIT.md): `terminal.projectState`,
  `terminal.openInProject`, `terminal.adopt`, `terminal.releaseDraft`,
  the `terminal:project-changed` signal, and `HelloResult.projectTerminals`.
  An older daemon answers "method not found" and omits the flag; clients
  then offer terminals only in sessions.
- ADDITIVE (no version bump): `queue.attachments` returns a queued
  entry's attachments with their bytes, and `queue.update` accepts
  `attachments` to replace them. An older daemon answers "method not
  found" / ignores the field: the entry's attachments stay as queued.
- ADDITIVE (no version bump): `chat.steer` / `chat.followUp` resolve to
  whether the message reached a live run. Older daemons resolve `null`,
  which clients treat as delivered (the pre-existing behavior).
- ADDITIVE (no version bump): `sessions.fork`, `sessions.deleteTurn`,
  `sessions.editTurnText`, `sessions.setFolder`, `sessions.appendTurns`,
  `sessions.rewind`.
  History and folder edits run in the host instead of being written to
  the store by the client (then `sessions.touch` + `chat.rebuildAgent`).
  Older clients keep the old path, which still works on a shared disk.
  A newer client only meets an older daemon while it retires (the
  release fence drains it otherwise), and then gets "method not found".
- ADDITIVE (no version bump): `sessions.listMeta`, `sessions.getMeta`,
  `sessions.get`, `sessions.setExtensionState` serve a client the
  session data it used to read and write in its own store, so a window
  on another machine sees the host's sessions. `sessions.create` accepts `effort`, `modelOptions` and
  `pinnedSkills`; `todos.set` accepts `persistIdle`. An older host answers
  "method not found" / ignores the fields: a window falls back to the
  store it shares with a local daemon, and refuses a remote host.
- ADDITIVE (no version bump): `daemon.info` reports `activeWork` (a run,
  compaction, `/` command or background task in flight). An older host
  omits it; `zidane server wait-idle` then says it can't tell.
- ADDITIVE (no version bump): `sessions.loadEvents` paging accepts
  `beforeTurnId` (the page ends right before that turn, winning over
  `before`; an unknown turn is invalid params) and the page echoes it.
  An older host ignores the param and omits the echo, which is how a
  client tells.
- ADDITIVE (no version bump): `sessions.cacheImpact` and
  `sessions.cacheReport`. An older host answers "method not found":
  pickers show no cache estimate and session details no Cache section.
- ADDITIVE (no version bump): `sessions.moveEnvironment`. An older host
  answers "method not found", shown as the move's error. Its
  `removeOldWorktree` param and `oldWorktree` result came later: an older
  host ignores the param and answers with no result.
- ADDITIVE (no version bump): a folder's git checkout and files
  (`git.*`, `files.*`, the caller-only `git:clone:progress` signal),
  `sessions.export` and `hud.get`. Clients find them in the hello's
  `methods`; an older host lacks them and those controls stay hidden.
  `hud.get` and the `hud:state` / `hud:notify` signals are gone since
  zidane 10: extensions show status through `Slot` items
  (`extensions.ui.list`, `extensions:ui`); a client that still asks
  for `hud.get` gets "method not found".
- ADDITIVE (no version bump): `sessions.titleStatus`,
  `artifacts.refresh`, `usage.summary`, `git.watch` / `git.unwatch`
  (the watcher-only `git:refs` signal), `files.mediaTicket` (media at
  `GET /zidane/media`), project-scope `extensions.create`, and
  `auth.status`'s `customFields` / `configuredFields`. The methods are
  in the hello's `methods`; an older host omits the fields.
- ADDITIVE (no version bump): `daemon.ownedProcesses`. An older host
  answers "method not found"; the desktop app's performance monitor
  then counts none of its processes as the app's own.
- ADDITIVE (no version bump): `daemon.sessionProcesses`. An older host
  answers "method not found"; the performance monitor then shows none of
  its processes under a session.
- ADDITIVE (no version bump): `sessions.setPolicy` (and
  `sessions.create`'s `policy`), `integrations.register` / `update` /
  `list`, `mcp.instances` and `mcp.restart`. An older host answers
  "method not found" and ignores the field.
- ADDITIVE (no version bump): `interactions.rehydrateSessions`,
  `tokens.revokeSelf`, `fs.mkdir`, `fs.searchDirs`, the hello's `clone`
  and `createFolders` (`git.clone` and `git.cloneCancel` take a `chat`
  token), `whenIdle` on `sessions.appendTurns`, `origin`, `literal` and
  `clientMessageId` on the send methods, the `delivery:changed` and
  `integrations:changed` signals, and `takenOver` on `run:end`. An older
  host answers "method not found" or ignores the fields; an older client
  drops the unknown signals and reads a taken-over run as failed.
- 14: the `orchestration.*` verbs act as the CONNECTION (its token, or
  the local window) instead of taking a `mainId`; `createWorker` takes
  `tools` / `subscribe` and an optional `prompt`; new
  `orchestration.wait`, `orchestration.events`, `orchestration.pending`, `orchestration.answer`
  (`chat`) and `orchestration.approve` (`approve`); `answeredBy` on
  `interaction:resolved` / `approval:resolved` and on interaction
  responses. A v13 peer still speaks: `orchestration.main` is unchanged
  and a stray `mainId` is ignored.
- 15: plans replace todos. `plans.get` / `plans.edit` / `plans.control`
  and the `plans:snapshot` signal replace `todos.get` / `todos.set` and
  `todos:snapshot`. Not additive: the minimum version is 15 too, so an
  older peer is refused at hello instead of silently showing no plans.
- 16: one way to send a message while a run works. `chat.steer` and
  `chat.followUp` are removed: `queue.add` with `delivery` takes their
  place, with attachments and skills. `delivery` gains `auto` (the
  default, which follows `Settings.messageDelivery`) and `queue`.
  `Settings.queueMessages` becomes `Settings.messageDelivery`. Not
  additive: the minimum version is 16 too.

```ts
const IPC_PROTOCOL_VERSION = 16
```

Source: [src/ipc/protocol.ts:371](https://github.com/Tahul/zidane/blob/main/src/ipc/protocol.ts#L371)

### `IpcErrorCode`

Constant.

JSON-RPC error codes specific to the zidane daemon. Lives here (not in
`daemon/server.ts`) so clients can import the codes without pulling the
server's module graph.

```ts
const IpcErrorCode: { readonly Forbidden: -32015; readonly HandlerFailed: -32014; readonly NotHandshaken: -32011; readonly RateLimited: -32012; readonly ResponseTooLarge: -32013; readonly VersionMismatch: -32010 }
```

Source: [src/ipc/protocol.ts:390](https://github.com/Tahul/zidane/blob/main/src/ipc/protocol.ts#L390)

### `METHOD_SCOPES`

Constant.

The lowest client scope that may call each method.

```ts
const METHOD_SCOPES: { readonly [M in IpcMethodName]: ClientScope }
```

Source: [src/ipc/scopes.ts:53](https://github.com/Tahul/zidane/blob/main/src/ipc/scopes.ts#L53)

### `SERVER_AUTH_CHECK_PATH`

Constant.

The path of a zidane-server's auth check, relative to its WebSocket URL's origin (same as [`SERVER_AUTH_PATH`](https://zidane.si/docs/reference/ipc-browser.md#SERVER_AUTH_PATH)).

```ts
const SERVER_AUTH_CHECK_PATH = SERVER_AUTH_PATH
```

Source: [src/ipc/browser.ts:36](https://github.com/Tahul/zidane/blob/main/src/ipc/browser.ts#L36)

### `SERVER_AUTH_PATH`

Constant.

Where a browser client asks why it can't connect, relative to the server's origin:
a token's scope, or the refusal an upgrade would get.

```ts
const SERVER_AUTH_PATH = '/zidane/auth'
```

Source: [src/ipc/browser.ts:34](https://github.com/Tahul/zidane/blob/main/src/ipc/browser.ts#L34)

### `SERVER_EXTENSIONS_UI_PATH`

Constant.

Where the `ui` bundles are listed (`GET ?cwd=`) and served (`GET /<hash>.js`).

```ts
const SERVER_EXTENSIONS_UI_PATH = '/zidane/extensions/ui'
```

Source: [src/ipc/extension-paths.ts:9](https://github.com/Tahul/zidane/blob/main/src/ipc/extension-paths.ts#L9)

### `SERVER_EXTENSIONS_WEBVIEW_PATH`

Constant.

Where webview URLs are minted (`POST ?cwd=&id=`) and their files served (`/<ticket>/…`).

```ts
const SERVER_EXTENSIONS_WEBVIEW_PATH = '/zidane/extensions/webview'
```

Source: [src/ipc/extension-paths.ts:12](https://github.com/Tahul/zidane/blob/main/src/ipc/extension-paths.ts#L12)

### `SERVER_MEDIA_PATH`

Constant.

Where a zidane-server serves workspace media (`GET`, `files.mediaTicket`), relative to its origin.

```ts
const SERVER_MEDIA_PATH = '/zidane/media'
```

Source: [src/ipc/browser.ts:38](https://github.com/Tahul/zidane/blob/main/src/ipc/browser.ts#L38)

### `SERVER_OAUTH_CALLBACK_PATH`

Constant.

Where a zidane-server takes a browser client's MCP sign-in back (`auth.oauth.begin`), relative to its origin.

```ts
const SERVER_OAUTH_CALLBACK_PATH = '/zidane/oauth/callback'
```

Source: [src/ipc/browser.ts:40](https://github.com/Tahul/zidane/blob/main/src/ipc/browser.ts#L40)

### `SERVER_PAIR_PATH`

Constant.

Where a browser trades a pairing code for a device token (`POST`, JSON), relative to the server's origin.

```ts
const SERVER_PAIR_PATH = '/zidane/pair'
```

Source: [src/ipc/browser-pair.ts:10](https://github.com/Tahul/zidane/blob/main/src/ipc/browser-pair.ts#L10)

## Interfaces

### `BlockRunClient`

Interface.

What [`runBlockOnHost`](https://zidane.si/docs/reference/ipc-browser.md#runBlockOnHost) needs of a client: a call (a server client's `call`, an IPC client's `request`) and its signals.

```ts
interface BlockRunClient
```

**Properties**

- `call` (`<M extends 'sessions.runBlock' | 'sessions.runBlockCancel'>(method: M, params: IpcParams<M>) => Promise<IpcResult<M>>`): Calls a method on the host.
- `onSignal` (`(listener: (signal: HostSignal) => void) => () => void`): Hears the host's signals; returns the unsubscribe.

Source: [src/ipc/block-run.ts:13](https://github.com/Tahul/zidane/blob/main/src/ipc/block-run.ts#L13)

### `BlockRunOnHostOptions`

Interface.

Options for [`runBlockOnHost`](https://zidane.si/docs/reference/ipc-browser.md#runBlockOnHost).

```ts
interface BlockRunOnHostOptions
```

**Properties**

- `onOutput?` (`(stream: 'stdout' | 'stderr', text: string) => void`): Output as it arrives.
- `signal?` (`AbortSignal`): Stops the run on the host.

Source: [src/ipc/block-run.ts:21](https://github.com/Tahul/zidane/blob/main/src/ipc/block-run.ts#L21)

### `ExtensionInstallErrorData`

Interface.

The `data` of a `HandlerFailed` error from an extension install
(`catalog.install`, `extensions.changeOrigin`) that found extensions in
the source but not the one it needed: the installer's error code
(`name-mismatch`, `multiple-candidates`, `no-extension`) and the names it
found, for a client to list. Additive: older hosts send the names in the
message only.

```ts
interface ExtensionInstallErrorData
```

**Properties**

- `candidates` (`string[]`): The extension names the source holds.
- `installError` (`string`): The installer's error code: `name-mismatch`, `multiple-candidates` or `no-extension`.

Source: [src/ipc/protocol.ts:423](https://github.com/Tahul/zidane/blob/main/src/ipc/protocol.ts#L423)

### `ExtensionsClient`

Interface.

The typed extension API client.

```ts
interface ExtensionsClient
```

**Properties**

- `announce` (`(info: UiClientAnnounce) => Promise<void>`): Tells the host what this window shows (send on focus and session change).
- `catalogProvenance` (`(cwd: string, kind: CatalogKind) => Promise<CatalogItemProvenance[]>`): Where each item of a catalog (`kind`) comes from, for a folder.
- `commands` (`{ keymap: (cwd: string, sessionId?: string) => Promise<WireKeymap>; list: (cwd: string, sessionId?: string) => Promise<WireExtensionCommands>; onChange: (listener: (cwd: string, keymap?: { mode?: string }) => void) => () => void; popMode: (handle: string) => Promise<boolean>; pushMode: (cwd: string, mode: string, opts?: { priority?: number; sessionId?: string }) => Promise<string>; run: (cwd: string, id: string, opts?: { args?: string; sessionId?: string }) => Promise<boolean> }`): The commands and keymap modes extensions register.
- `entries` (`{ list: (cwd: string) => Promise<WireExtensionEntry[]>; onChange: (listener: (cwd: string) => void) => () => void }`): The extensions of a folder (status, `tui` entry, `ui` bundle), and when to list them again.
- `integrations` (`{ connectKey: (cwd: string, integrationId: string, key: string, methodId?: string) => Promise<WireIntegration>; disconnect: (cwd: string, integrationId: string, account?: string) => Promise<void>; flowInput: (flowId: string, inputId: string, value: string | undefined) => Promise<boolean>; list: (cwd: string) => Promise<WireIntegration[]>; onChange: (listener: (cwd: string) => void) => () => void; setDefault: (cwd: string, integrationId: string, account: string) => Promise<void>; start: (cwd: string, integrationId: string, methodId: string, onStep: (step: IntegrationFlowStep, flowId: string) => void) => Promise<WireIntegration> }`): The integrations extensions declare, and their connections.
- `links` (`{ open: (cwd: string, link: Omit<LinkOpenParams, 'cwd'>) => Promise<{ handled: boolean }> }`): The extensions' link handlers.
- `onRpcEvent` (`(listener: (event: RpcEventEnvelope) => void) => () => void`): Hears each event an extension's RPC contract emits.
- `rpc` (`<T = unknown>(contract: string, method: string, input?: unknown, opts?: { cwd?: string; signal?: AbortSignal }) => Promise<NoInfer<T>>`): Calls an RPC method. Rejects with [`RpcCallError`](https://zidane.si/docs/reference/extensions.md#RpcCallError) when the call
  fails (`rpc.forbidden`: the method's `scope` is above this connection's
  token).
- `serve` (`(server: ExtensionsUiServer) => () => void`): Answers the dialogs and UI requests the host routes to this window.
- `settings` (`{ get: (cwd: string, sessionId?: string) => Promise<WireExtensionSettings>; onChange: (listener: (cwd: string) => void) => () => void; set: (params: SettingsSetParams) => Promise<void> }`): The extensions' settings, with where each value comes from.
- `sources` (`{ browse: (source: string) => Promise<ExtensionSourceListing>; changeOrigin: (params: { name: string; scope: 'user' | 'project'; source: string }) => Promise<{ message: string; name: string; origin: ExtensionInstallOrigin; progress: string[] }> }`): Sources of extensions: what one holds, and moving an installed extension to another.
- `storage` (`{ load: (cwd: string, loc: WireStorageLocation) => Promise<StorageSnapshot & { projectRoot?: string }>; onChange: (listener: (change: { area: StorageArea; extensionId: string; key: string; kind: 'extensions:storage'; projectRoot?: string; scope: StorageScope; sessionId?: string; value?: Json; version?: number }) => void) => () => void; set: (cwd: string, loc: WireStorageLocation, area: StorageArea, key: string, value: Json | undefined) => Promise<WireStorageSetResult> }`): The extensions' synced storage.
- `ui` (`{ invoke: (cwd: string, request: UiInvokeRequest) => Promise<unknown>; list: (cwd: string) => Promise<WireUiList>; onChange: (listener: (cwd: string, change: UiChange | { type: 'reset' }) => void) => () => void; onPanelChanged: (listener: (change: { cwd: string; extensionId: string; panelId: string; sessionId?: string }) => void) => () => void }`): The UI items of extensions and the callbacks they register.

Source: [src/ipc/extensions-client.ts:43](https://github.com/Tahul/zidane/blob/main/src/ipc/extensions-client.ts#L43)

### `ExtensionsTransport`

Interface.

What the client needs of a connection: an `IpcClient` (`zidane/ipc`)
or a browser `ServerClient` (`zidane/ipc/browser`).

```ts
interface ExtensionsTransport
```

**Properties**

- `onSignal` (`(listener: (signal: HostSignal) => void) => () => void`): Hears every signal the host sends.
- `request` (`<M extends keyof IpcMethods>(method: M, params: IpcParams<M>) => Promise<IpcResult<M>>`): Sends an IPC request and resolves with its result.

Source: [src/ipc/extensions-client.ts:152](https://github.com/Tahul/zidane/blob/main/src/ipc/extensions-client.ts#L152)

### `ExtensionsUiServer`

Interface.

What a window does with what the host routes to it.

```ts
interface ExtensionsUiServer
```

**Properties**

- `client` (`(request: UiClientRequest) => unknown`): Runs a UI request (panel, navigate, composer); resolves with its result (`boolean`, or the open panel ids). `notify` resolves nothing.
- `dialog` (`(request: DialogRequest, ctx: { dialogId: string; extensionId: string; sessionId?: string; signal: AbortSignal; validate: (key: string, value: unknown) => Promise<string | null> }) => Promise<unknown>`): Shows a dialog; resolves with the raw answer (`undefined`: cancelled).
  `signal` aborts when the host gives up on it. A `form` dialog calls
  `validate(key, value)` as the user edits a field and before answering,
  and shows the message (`null`: valid) under the field. Answer only once
  every field validates: the host checks the answer again, and an invalid
  one makes the extension's `form` reject.

Source: [src/ipc/extensions-client.ts:28](https://github.com/Tahul/zidane/blob/main/src/ipc/extensions-client.ts#L28)

### `HelloResult`

Interface.

Result of the `hello` handshake and of `daemon.info`.

```ts
interface HelloResult
```

**Properties**

- `activeWork?` (`boolean`): `daemon.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.
- `adminCommands?` (`{ pair: string; token: string }`): How 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.
- `appVersion` (`string`): zidane version of the host.
- `buildId?` (`string`): Build fingerprint of the host code. `'unknown'` in compiled binaries.
- `clone?` (`boolean`): Clients 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.
- `codeVersion?` (`string`): Version of the zidane code the host runs.
- `createFolders?` (`boolean`): Clients 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?` (`string`): The 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.
- `hostId?` (`string`): Host 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?` (`HostKind`): What kind of host this is.
- `hostName?` (`string`): Display name of the host.
- `machineServe?` (`boolean`): This server lends itself as a machine to the hosts of its clients
  (`machine.attach`, `allowAsMachine` on). Absent: it doesn't. Additive.
- `methods?` (`keyof IpcMethods[]`): The 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.
- `minProtocolVersion?` (`number`): The oldest version the host still speaks ([`IPC_MIN_PROTOCOL_VERSION`](https://zidane.si/docs/reference/ipc-browser.md#IPC_MIN_PROTOCOL_VERSION)). Additive.
- `negotiatedProtocolVersion?` (`number`): The version this connection speaks: the lower of the client's and the host's. Additive:
  absent, the connection speaks `protocolVersion`.
- `pid` (`number`): Process id of the host.
- `projectTerminals?` (`true`): This host runs terminals without a session (`terminal.openInProject` and
  the other project / draft terminal methods). Absent: sessions only. Additive.
- `protocolVersion` (`number`): Protocol version the host speaks.
- `remoteInstalls?` (`boolean`): This 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.
- `retiring?` (`boolean`): The 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.
- `scope?` (`'chat' | 'admin'`): The client scope this connection's token grants (`./scopes`): calls above it are refused.
  Absent: every method (a local window). Additive.
- `signalEpoch?` (`string`): Names this host process's signal numbering ([`SIGNAL_SEQ_FIELD`](https://zidane.si/docs/reference/ipc.md#SIGNAL_SEQ_FIELD)):
  a position from another epoch cannot be resumed. Additive.
- `startedAt` (`number`): Start time of the host process, epoch ms.
- `sync?` (`boolean`): This server takes settings sync from a client's computer (`sync.*`). Absent: it doesn't. Additive.
- `syncCategories?` (`SyncCategory[]`): The sync categories it takes. Absent with `sync`: the ones before `environments`. Additive.

Source: [src/ipc/protocol.ts:2669](https://github.com/Tahul/zidane/blob/main/src/ipc/protocol.ts#L2669)

### `IpcMethods`

Interface.

Typed method map for the daemon transport. Keys are JSON-RPC method
names; each entry pins params/result so both the daemon dispatch table
and the client proxy are checked against the same contract.

Scope: the chat core every client needs. Host-UI-specific surfaces
(folder pickers, themes, keybindings) intentionally stay client-local.

```ts
interface IpcMethods extends HitlIpcMethods
```

**Properties**

- `agents.list` (`{ params: { cwd: string }; result: HostAgentProfile[] }`): The agent profiles `cwd` offers (`''`: no folder), as the agent picker lists them: a profile a setting turns off (Codemode) is left out. Additive.
- `approvals.denyAll` (`{ params: { sessionId?: string }; result: void }`, from `HitlIpcMethods`): Denies every pending approval, or only those of `sessionId` when given.
- `approvals.listPending` (`{ params: Record<string, never>; result: WireApprovalRequest[] }`, from `HitlIpcMethods`): Lists the approval requests waiting for an answer.
- `approvals.resolve` (`{ params: { decision: ApprovalDecision; requestId: string }; result: void }`, from `HitlIpcMethods`): Answers a pending approval request with a decision.
- `artifacts.badges` (`{ params: { sessionIds: string[] }; result: Record<string, SessionBadgeEntry[]> }`): The 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.
- `artifacts.delete` (`{ params: { artifactId: string; sessionId: string }; result: boolean }`): Remove one artifact. `false` when the store has no artifact support. Fans out `artifact:changed`.
- `artifacts.list` (`{ params: { kind?: string; limit?: number; projectRoot?: string | null; since?: number; uri?: string }; result: SessionArtifact[] }`): Artifacts across sessions, filtered by project root (`null` = untagged
  sessions, omitted = every project) and/or kind/uri (reverse lookup).
- `artifacts.refresh` (`{ params: { artifactId: string; force?: boolean; sessionId: string }; result: SessionArtifact | null }`): Re-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.
- `artifacts.upsert` (`{ params: { artifact: SessionArtifact }; result: SessionArtifact | null }`): Upsert 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.
- `auth.configure` (`{ params: { customFields?: Record<string, string>; provider: string; value?: string }; result: HostProviderAuth }`): Stores 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.
- `auth.oauth.begin` (`{ params: { account?: string; cwd?: string; kind?: string; mcpServer?: string; provider?: string; redirectUri?: string }; result: HostOAuthBegin }`): OAuth 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 `complete`s 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.
- `auth.oauth.cancel` (`{ params: { flowId: string }; result: { cancelled: boolean } }`): Abandon a flow of this connection.
- `auth.oauth.complete` (`{ params: { code?: string; flowId: string; input?: string; state?: string }; result: HostOAuthComplete }`): Deliver 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.
- `auth.oauth.respond` (`{ params: { flowId: string; stepId: string; value?: string }; result: HostOAuthBegin }`): Answer 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.
- `auth.remove` (`{ params: { account?: string; provider: string }; result: { provider: HostProviderAuth; removed: boolean } }`): Remove 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.
- `auth.rename` (`{ params: { account: string; label: string; provider: string }; result: HostProviderAuth }`): Rename a stored OAuth account (`account`: its key from `auth.status`). Presentation only: nothing is rebuilt. Additive.
- `auth.setApiKey` (`{ params: { key: string; provider: string }; result: HostProviderAuth }`): Store 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.
- `auth.setPreferred` (`{ params: { provider: string; target: 'oauth' | 'apikey' | { key: string } }; result: HostProviderAuth }`): Make 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.
- `auth.status` (`{ params: Record<string, never>; result: { providers: HostProviderAuth[] } }`): The 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.
- `badges.actions` (`{ params: { cwd: string; target: BadgeTarget }; result: BadgeMenuItem[] }`): The extensions' items (`ctx.registerBadgeActions`) of a badge's menu in `cwd`; the built-in ones are the client's. Additive.
- `badges.run` (`{ params: { cwd: string; id: string; source: string; target: BadgeTarget }; result: BadgeActionEffect }`): Runs an extension's badge item; the effect (copy, open, a notice) is the client's to apply. Additive.
- `browser.registerHost` (`{ params: { hostId: string }; result: { ok: boolean } }`): Dev 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.
- `browser.respond` (`{ params: { requestId: string; response: BrowserResponse }; result: { ok: boolean } }`): Answers a `browser:request` signal with the host's result.
- `browser.unregisterHost` (`{ params: { hostId: string }; result: { ok: boolean } }`): Withdraws a window as dev browser host.
- `catalog.extensions` (`{ params: { cwd?: string; kind?: string }; result: { extensions: HostCatalogExtension[] } }`): Extensions installed for `cwd`.
- `catalog.install` (`{ params: { all?: boolean; extension?: string; kind: HostInstallKind; overwrite?: boolean; scope?: 'user'; skills?: string[]; spec: string }; result: { installed: string[]; message: string; progress: string[] } }`): Install 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`](https://zidane.si/docs/reference/ipc-browser.md#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`).
- `catalog.mcps` (`{ params: { cwd?: string; kind?: string }; result: { errors: HostCatalogError[]; servers: HostCatalogMcp[] } }`): MCP servers: `env` and `headers` values, URL credentials and query values are redacted.
- `catalog.plugins` (`{ params: { cwd?: string; kind?: string }; result: { plugins: HostCatalogPlugin[] } }`): Plugins installed for `cwd`, with what each contributes.
- `catalog.remove` (`{ params: { kind: HostInstallKind; name: string }; result: { message: string; removed: string } }`): Remove a user-scope skill or extension of the host by name (its directory). As `catalog.install`.
- `catalog.skills` (`{ params: { cwd?: string; kind?: string }; result: { skills: HostCatalogSkill[] } }`): What 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.
- `catalog.update` (`{ params: { kind: HostInstallKind; name: string }; result: { message: string; updated: string; upToDate: boolean } }`): Update a user-scope extension installed from a source. As `catalog.install`.
- `chat.cancelWork` (`{ params: { id: string; reason?: string; sessionId: string }; result: boolean }`): Cancels 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.
- `chat.deliveryState` (`{ params: { clientMessageId?: string; requestId?: string; sessionId: string }; result: { runId?: string; settled: boolean; state: 'unknown' | DeliveryState } }`): What 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.
- `chat.interrupt` (`{ params: { sessionId: string }; result: void }`): Aborts the session's live run. Does nothing when no run is live.
- `chat.isRunning` (`{ params: { sessionId: string }; result: boolean }`): Resolves `true` while the session has a live run.
- `chat.listWork` (`{ params: { children?: boolean; sessionId: string }; result: RunningWorkItem[] }`): Lists 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.
- `chat.pushQueued` (`{ params: { activatedSkills?: string[]; clientMessageId?: string; keepDraft?: boolean; literal?: boolean; message: string; metadata?: Record<string, JsonValue>; origin?: TextOrigin; sessionId: string } & SendRequestId; result: { consumed?: 'steer' | 'followUp' | 'handled'; delivered: 'command' | 'send' | 'steer' | 'queued' } }`): Delivers 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.
- `chat.rebuildAgent` (`{ params: { sessionId: string }; result: void }`): Retire 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.
- `chat.send` (`{ params: Omit<SendOptions, 'wake'> & SendRequestId; result: { consumed?: 'steer' | 'followUp' | 'handled'; runId: string } }`): `wake` 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.
- `claudeImport.detect` (`{ params: { cwd?: string }; result: ClaudeImportDetection }`): What `~/.claude` on the host holds: whether there is a setup, and its transcripts for `cwd` and in every project. Additive.
- `claudeImport.preview` (`{ params: { cwd?: string }; result: OnboardingImportPreview }`): What each piece of the Claude Code import would copy and skip. Additive.
- `claudeImport.run` (`{ params: { cwd?: string } & ClaudeImportSelection; result: ClaudeImportSummary }`): Imports 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.
- `commands.completeArgs` (`{ params: { argsPrefix: string; cwd: string; kind?: string; name: string }; result: CommandArgSuggestionSummary[] }`): Argument suggestions for `/name <prefix>` — best-effort, empty on failure.
- `commands.list` (`{ params: { cwd: string; kind?: string }; result: CommandSummary[] }`): Extension-contributed `/` commands discovered for `cwd`.
- `completions.providers` (`{ params: { cwd: string }; result: ExtensionCompletionProviderSummary[] }`): The 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.
- `completions.submit` (`{ params: { cursor: number; cwd: string; text: string }; result: void }`): Runs the providers' submit hooks (`resolveReferences`, `onSubmit`) on a prompt about to be sent; resolves after them, or after 5 s. Additive.
- `completions.suggest` (`{ params: { cursor: number; cwd: string; providerId: string; query: string; text: string }; result: ExtensionCompletionItemSummary[] }`): One 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.
- `daemon.info` (`{ params: Record<string, never>; result: HelloResult }`): Daemon identity and version: `protocolVersion`, `appVersion`, `pid`, `startedAt` and the host identity fields of the `hello` result.
- `daemon.ownedProcesses` (`{ params: Record<string, never>; result: OwnedProcess[] }`): The 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.
- `daemon.sessionProcesses` (`{ params: Record<string, never>; result: SessionProcess[] }`): The 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.
- `daemon.shutdown` (`{ params: { whenIdle?: boolean }; result: void | { deferred?: boolean } }`): Graceful 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.
- `decisions.test` (`{ params: { cwd?: string; kind?: string; model?: string }; result: HostDecisionTestResult }`): Send 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.
- `drafts.get` (`{ params: { sessionId: string }; result: { attachments?: PromptAttachment[]; search?: { active: boolean; query: string }; shell?: boolean; text: string } }`): Current shared draft for a session — backfill on window attach.
- `drafts.set` (`{ params: { sessionId: string; shell?: boolean; text: string }; result: void }`): Replace 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.
- `drafts.setAttachments` (`{ params: { attachments: PromptAttachment[]; sessionId: string }; result: void }`): Replace the shared draft's composing attachments (notification).
- `environments.list` (`{ params: { cwd?: string; kind?: string }; result: EnvironmentDescriptor[] }`): Every 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.
- `environments.update` (`{ params: EnvironmentSettingsChange; result: void }`): Apply 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.
- `environments.verify` (`{ params: { kind: string }; result: EnvironmentVerifyResult }`): "Test connection" for a kind with its current options.
- `extensions.actions` (`{ params: { cwd: string }; result: ExtensionActionSummary[] }`): The action rows (`registerConfigItem` type `'action'`) the enabled extensions declare for `cwd`. Additive.
- `extensions.actionStatuses` (`{ params: { cwd: string }; result: Record<string, ExtensionConfigActionStatus> }`): The actions' passive `status()` probes, keyed `extension:key`; a probe that throws or takes over 3 s is left out. Additive.
- `extensions.browse` (`{ params: { source: string }; result: ExtensionSourceListing }`): The 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.
- `extensions.catalogs.provenance` (`{ params: { cwd: string; kind: CatalogKind }; result: CatalogItemProvenance[] }`): Which catalog items of `cwd` extensions added, changed or removed, with the extension that did it (Settings shows it). Additive.
- `extensions.changeOrigin` (`{ params: { name: string; scope: 'user' | 'project'; source: string }; result: { message: string; name: string; origin: ExtensionInstallOrigin; progress: string[] } }`): Install 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`](https://zidane.si/docs/reference/ipc-browser.md#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.
- `extensions.command.run` (`{ params: CommandRunParams; result: boolean }`): Runs a command by its published id (an extension command or a built-in). `false` when nothing ran. Additive.
- `extensions.commands` (`{ params: { cwd: string; sessionId?: string }; result: WireExtensionCommands }`): The extension commands of `cwd` with their effective bindings, scopes and modes, and the keymap mode on top for `sessionId`. Additive.
- `extensions.configSchema` (`{ params: { cwd: string }; result: WireExtensionConfigSchema }`): The options the enabled extensions declare for `cwd`
  (`registerConfigItem`), without the action items or the callbacks; the
  values live on the settings' `extensionConfig`. Additive.
- `extensions.create` (`{ params: CreateExtensionInput; result: CreateExtensionResult }`): Scaffolds 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.
- `extensions.entries` (`{ params: { cwd: string }; result: WireExtensionEntry[] }`): The 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.
- `extensions.integrations.connectKey` (`{ params: { cwd: string; integrationId: string; key: string; methodId?: string }; result: WireIntegration }`): Connects with an API key: verified by the extension, then kept in the credentials file. Additive.
- `extensions.integrations.disconnect` (`{ params: { account?: string; cwd: string; integrationId: string }; result: void }`): Removes the connection of `account`, or every connection of the integration when it is absent. Additive.
- `extensions.integrations.flowInput` (`{ params: { flowId: string; inputId: string; value?: string }; result: boolean }`): Answers a flow step that asked for input (`inputId`). `value` absent cancels the flow. Additive.
- `extensions.integrations.list` (`{ params: { cwd: string }; result: WireIntegration[] }`): The extension integrations of `cwd` (`ctx.integrations.register`) and their connections. Additive.
- `extensions.integrations.setDefault` (`{ params: { account: string; cwd: string; integrationId: string }; result: void }`): Makes the connection of `account` the integration's default. Additive.
- `extensions.integrations.start` (`{ params: { cwd: string; flowId?: string; integrationId: string; methodId: string }; result: WireIntegration }`): Runs 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.
- `extensions.keymap.list` (`{ params: { cwd: string; sessionId?: string }; result: WireKeymap }`): Every command of `cwd` with its effective bindings, scope and mode (`ctx.keymap.list`), and the active mode stack for `sessionId` (`ctx.keymap.active`). Additive.
- `extensions.keymap.pop` (`{ params: { handle: string }; result: boolean }`): Pops a mode this connection pushed. Additive.
- `extensions.keymap.push` (`{ params: { cwd: string; mode: string; priority?: number; sessionId?: string }; result: string }`): Activates 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.
- `extensions.links.open` (`{ params: LinkOpenParams; result: { handled: boolean } }`): Offers 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.
- `extensions.runAction` (`{ params: { cwd: string; extension: string; key: string }; result: ExtensionActionRunResult }`): Runs 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.
- `extensions.settings` (`{ params: { cwd: string; sessionId?: string }; result: WireExtensionSettings }`): The extensions' settings of `cwd` with values, locks and the layer each value comes from. `sessionId` adds that session's layer. Additive.
- `extensions.settings.set` (`{ params: SettingsSetParams; result: void }`): Writes 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.
- `extensions.storage.load` (`{ params: { cwd: string } & WireStorageLocation; result: StorageSnapshot & { projectRoot?: string } }`): Everything stored at a location of `cwd`'s extension storage, and the project root its `project`/`session` files live under. Additive.
- `extensions.storage.set` (`{ params: { area: StorageArea; cwd: string; key: string; value?: Json } & WireStorageLocation; result: WireStorageSetResult }`): Writes (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`).
- `extensions.ui.invoke` (`{ params: { cwd: string } & UiInvokeRequest; result: unknown }`): Runs 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.
- `extensions.ui.list` (`{ params: { cwd: string }; result: WireUiList }`): Every 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.
- `files.diagnostics` (`{ params: { cwd: string; disabled?: string[]; paths: string[]; timeoutMs?: number }; result: DiagnosticsResult }`): Runs 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.
- `files.diagnosticsInvalidate` (`{ params: { cwd: string }; result: void }`): Drops the cached diagnostics of `cwd`: the next run checks again.
- `files.diagnosticsTools` (`{ params: { cwd: string }; result: DiagnosticsToolInfo[] }`): The diagnostics tools and whether each runs for `cwd` (configured, missing its binary, not used).
- `files.list` (`{ params: { cwd: string }; result: FileEntry[] }`): The files under `cwd` and the folders holding them, as `@` completes them: git's list (ignore rules kept), else a walk; capped.
- `files.location` (`{ params: { cwd: string }; result: FolderLocation }`): Where `cwd` sits: its git checkout (the folder itself outside git) and its project (the main checkout for a worktree).
- `files.mediaTicket` (`{ params: { ticket: string }; result: void }`): Lets 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.
- `files.resolvePaths` (`{ params: { cwd: string; texts: string[] }; result: ResolvedPath[] }`): What names in prose point at (files, folders, else branches), in order: what a transcript's path chips open.
- `files.search` (`{ params: { caseSensitive?: boolean; cwd: string; query: string; searchId?: string }; result: ContentSearchResult }`): Lines 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.
- `fs.listDirs` (`{ params: { path?: string }; result: FsDirListing }`): The 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.
- `fs.mkdir` (`{ params: { name: string; parent: string }; result: FsDirEntry }`): Creates 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.
- `fs.roots` (`{ params: Record<string, never>; result: FsRoots }`): Where 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.
- `fs.searchDirs` (`{ params: { path?: string; query: string }; result: FsDirSearch }`): The 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.
- `git.branches` (`{ params: { cwd: string }; result: GitBranchRow[] }`): The local branches, most recently committed first, each against the default branch.
- `git.branchPullRequest` (`{ params: { branch: string; cwd: string; fresh?: boolean }; result: GitPr | null }`): `branch`'s open (or draft) pull request, or `null`. `fresh`: past the cache.
- `git.checkout` (`{ params: { cwd: string; sessionId?: string; target: GitSwitchTarget }; result: GitCheckoutResult }`): Switches 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).
- `git.clone` (`{ params: { input: string; parent: string }; result: RepoCloneResult }`): Clones `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`).
- `git.cloneCancel` (`{ params: Record<string, never>; result: void }`): Cancels this connection's clone: the half-cloned folder is removed and `git.clone` answers `cancelled`.
- `git.commit` (`{ params: { cwd: string; sha: string }; result: GitCommitInfo | null }`): One commit's facts, for a sha chip; `null` when the repository has no such commit.
- `git.createBranch` (`{ params: { cwd: string; name: string; sessionId?: string }; result: GitCheckoutResult }`): Starts branch `name` from the current checkout and switches to it; refused while an agent runs in it.
- `git.diff` (`{ params: { context?: number | null; cwd: string; path?: string }; result: string }`): The 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).
- `git.fileStatus` (`{ params: { cwd: string }; result: GitStatusEntry[] }`): Each changed path's status against HEAD, untracked files included.
- `git.pullRequests` (`{ params: { cwd: string; fresh?: boolean; search?: string }; result: GitPrListResult }`): Open 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.
- `git.status` (`{ params: { cwd: string }; result: GitInfo | null }`): Where the checkout stands (branch, upstream, ahead / behind, uncommitted changes); `null` outside a checkout.
- `git.sync` (`{ params: { cwd: string; sessionId?: string }; result: GitSyncResult }`): Pulls (merging) then pushes the current branch, or publishes it without an upstream; refused while an agent runs in it.
- `git.unwatch` (`{ params: { cwd: string }; result: void }`): Releases one `git.watch` of `cwd` by this connection.
- `git.watch` (`{ params: { cwd: string }; result: boolean }`): Follows `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.
- `history.searchAll` (`{ params: { excerptLimit?: number; query: string; sessionIds: string[] }; result: Record<string, SessionHistoryMatch> }`): Cross-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.
- `history.searchSession` (`{ params: { limit?: number; query: string; sessionId: string }; result: SearchTurnMatch[] }`): Transcript 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).
- `host.capabilities` (`{ params: { refresh?: boolean }; result: HostCapabilities }`): What this host can do: OS, tools on PATH, sandbox, environment kinds, what it allows. Cached a minute; `refresh` probes again.
- `host.installTool` (`{ params: { name: string }; result: { capabilities: HostCapabilities; ok: boolean; output: string } }`): Install 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.
- `integrations.list` (`{ params: Record<string, never>; result: IntegrationInfo[] }`): The integrations registered on this host, in registration order. Additive.
- `integrations.register` (`{ params: { detail?: string; kind: string; name: string; state: 'connected' | 'failed' | 'stopped' | 'starting' | 'degraded' }; result: void }`): Report 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.
- `integrations.update` (`{ params: { detail?: string; name: string; state: 'connected' | 'failed' | 'stopped' | 'starting' | 'degraded' }; result: void }`): Change the state of an integration this connection registered; `detail` replaces the previous one (absent clears it). Additive.
- `interactions.cancel` (`{ params: { reason?: string; requestId: string }; result: { ok: boolean } }`, from `HitlIpcMethods`): Cancels a pending interaction. `reason` is passed back to the agent.
- `interactions.list` (`{ params: { sessionId?: string }; result: PendingInteraction[] }`, from `HitlIpcMethods`): Lists pending interactions (questions and prompts the agent asked the user), optionally for one session.
- `interactions.rehydrate` (`{ params: { sessionId: string }; result: PendingInteraction[] }`, from `HitlIpcMethods`): Re-sends the session's pending interactions, for a client that connected after they were raised.
- `interactions.rehydrateSessions` (`{ params: { sessionIds: string[] }; result: PendingInteraction[] }`, from `HitlIpcMethods`): `interactions.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).
- `interactions.respond` (`{ params: { requestId: string; response: InteractionResponse }; result: { ok: boolean } }`, from `HitlIpcMethods`): Answers a pending interaction.
- `logs.list` (`{ params: Record<string, never>; result: { records: LogRecord[] } }`): A 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.
- `logs.unwatch` (`{ params: Record<string, never>; result: void }`): Release one `logs.watch` of this connection.
- `logs.watch` (`{ params: Record<string, never>; result: void }`): Follow the log: this connection gets `logs:record` for each new record. Calls count; a dropped connection releases its own. Additive.
- `machine.attach` (`{ params: { hostId: string }; result: MachineRegisterParams }`): Reverse 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.
- `machine.call` (`{ params: { method: string; params?: JsonValue }; result: JsonValue }`): Runs 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.
- `machine.detach` (`{ params: Record<string, never>; result: { detached: boolean } }`): Ends this connection's machine attachment. `detached` is `false` when it had none.
- `machines.forget` (`{ params: { machineId: string }; result: { forgotten: boolean } }`): Forgets a machine. It disconnects and its kinds stop resolving.
- `machines.links.status` (`{ params: Record<string, never>; result: MachineLinksStatus }`): State of this host's machine links: the shares it offers and the servers it uses.
- `machines.list` (`{ params: Record<string, never>; result: MachineInfo[] }`): The machines this host knows (`docs/MACHINES.md`), online or not, and
  forgetting one (it disconnects; its `local@` / `worktree@` kinds stop
  resolving). Additive.
- `machines.listDirs` (`{ params: { machineId: string; path?: string }; result: { dirs: string[]; path: string; roots: string[] } }`): Folders 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.
- `machines.share.start` (`{ params: { hostId: string; name: string; roots: string[]; token?: string }; result: MachineLinksStatus }`): A 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.
- `machines.share.stop` (`{ params: { hostId: string }; result: MachineLinksStatus }`): Stops sharing this computer with a server.
- `machines.useServer` (`{ params: { enabled: boolean; hostId: string }; result: MachineLinksStatus }`): Turns on or off using a server as this computer's linked server.
- `mcp.instances` (`{ params: { cwd?: string }; result: McpServerInstance[] }`): The 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.
- `mcp.remove` (`{ params: { name: string }; result: { removed: boolean } }`): Remove an MCP server from the host user's `mcps.json`; `removed: false` when it has none. As `catalog.install`.
- `mcp.restart` (`{ params: { cwd?: string; name: string }; result: { restarted: number } }`): End `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.
- `mcp.signOut` (`{ params: { name: string }; result: void }`): Forget an MCP server's sign-in on the host (its tokens). Every window gets `catalog:changed`. Additive.
- `mcp.test` (`{ params: { cwd?: string; kind?: string; name: string }; result: McpServerStatus }`): Connect 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.
- `mcp.upsert` (`{ params: { clientSecret?: string; config: McpServerConfig; cwd?: string; scope?: 'user' | 'project' }; result: { created: boolean; name: string } }`): Add 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`.
- `models.list` (`{ params: { cwd?: string; kind?: string }; result: { providers: HostModelProvider[] } }`): The 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.
- `models.test` (`{ params: { cwd?: string; kind?: string; model: string }; result: HostDecisionTestResult }`): Send 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.
- `onboarding.complete` (`{ params: { records: OnboardingState; settings: OnboardingSettingsChange }; result: HostSettings }`): The 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.
- `onboarding.detect` (`{ params: { cwd?: string }; result: OnboardingDetection }`): What 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.
- `onboarding.providers` (`{ params: { cwd?: string }; result: HostOnboardingProvider[] }`): The providers as the wizard's Connect step lists them, with their custom fields and the model each runs when none is picked. Additive.
- `orchestration.answer` (`{ params: { requestId: string; response: InteractionResponse }; result: boolean }`): Answers a question or a plan, recording the connection as `answeredBy`. `false` when it was answered first.
- `orchestration.approve` (`{ params: { decision: ApprovalDecision; requestId: string }; result: boolean }`): Decides a tool approval (an `approve` token), recording the connection as `answeredBy`. `false` when it was decided first.
- `orchestration.cancel` (`{ params: { sessionId: string }; result: void }`): Cancels a session's run.
- `orchestration.createWorker` (`{ params: CreateSessionParams; result: string }`): Creates a session (optionally holding orchestration tools and a subscription) and resolves with its id.
- `orchestration.events` (`{ params: EventQuery; result: SessionEvent[] }`): Searches the recent session events (runs ended, sessions blocked), newest first.
- `orchestration.list` (`{ params: { limit?: number }; result: WorkerRow[] }`): Lists sessions with their live status, newest first, up to `limit`. The list can be partial.
- `orchestration.main` (`{ params: Record<string, never>; result: string | null }`): The main session id, creating it (directory-less) when the setting is on and none exists.
- `orchestration.pending` (`{ params: { sessionId?: string }; result: PendingRequestRow[] }`): The prompts waiting for an answer (questions, plans, tool approvals), of one session or all.
- `orchestration.read` (`{ params: { full?: boolean; sessionId: string }; result: WorkerSummary }`): Summary of one session (with its `link`); rejects when unknown. `lastMessage` is cut at 600 characters; `full: true` returns it whole.
- `orchestration.send` (`{ params: { prompt: string; sessionId: string }; result: boolean }`): Queues a prompt as the session's next turn; `false` when declined (the person stopped the session, or their queued prompts go first).
- `orchestration.steer` (`{ params: { attachments?: PromptAttachment[]; message: string; sessionId: string }; result: void }`): Sends a steering message, with optional attachments, to a session's live run.
- `orchestration.transcript` (`{ params: { full?: boolean; limit?: number; sessionId: string }; result: string }`): The last `limit` turns of a session as plain text, each cut at 1200 characters; `full: true` returns them whole.
- `orchestration.wait` (`{ params: { sessionId: string; timeoutSec?: number }; result: WaitResult }`): Resolves once the session is idle or blocked, or after `timeoutSec` (default 30, at most 50).
- `palette.list` (`{ params: { ctx: PaletteContext; cwd: string }; result: PaletteItem[] }`): The 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.
- `palette.run` (`{ params: { ctx: PaletteContext; cwd: string; itemId: string; source: string }; result: { ok: true; result: PaletteRunResult } | { error: string; ok: false } }`): Run `itemId` on its provider (`source`); a nested list, a prompt or a draft comes back as `result`. Additive.
- `palette.unwatch` (`{ params: { cwd: string }; result: void }`): Release one `palette.watch` of this connection.
- `palette.watch` (`{ params: { cwd: string }; result: void }`): As `panels.watch`, for every provider of `cwd`: `palette:changed`. Additive.
- `panels.action` (`{ params: { actionId: string; ctx?: PanelLoadContextInput; cwd: string; panelId: string; payload?: unknown }; result: { ok: true } | { error: string; ok: false } }`): Run one of a panel's actions (a row's or the footer's `actionId`, its `payload`). Additive.
- `panels.list` (`{ params: { cwd: string }; result: PanelSummary[] }`): The 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.
- `panels.load` (`{ params: { ctx?: PanelLoadContextInput; cwd: string; panelId: string }; result: PanelContent }`): One panel's content for `ctx` (the session it shows beside, what opened it). Additive.
- `panels.unwatch` (`{ params: { cwd: string; panelId: string }; result: void }`): Release one `panels.watch` of this connection.
- `panels.watch` (`{ params: { cwd: string; panelId: string }; result: void }`): Keep a panel's live updates on: this connection gets `panel:changed`
  when its content changes. Calls count; a dropped connection releases its
  own. Additive.
- `perf.history` (`{ params: Record<string, never>; result: { samples: PerfSample[] } }`): The samples the host holds (the last 5 minutes of watching), oldest first. Additive.
- `perf.threads` (`{ params: { pid: number }; result: { threads: PerfOsThread[] } }`): The OS threads of one of the processes the host lists (its own tree), busiest first. Refuses any other pid. Additive.
- `perf.unwatch` (`{ params: Record<string, never>; result: void }`): Release one `perf.watch` of this connection. Additive.
- `perf.watch` (`{ params: Record<string, never>; result: void }`): Follow 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.
- `plans.control` (`{ params: { action: 'stop' | 'drop'; planId: string; sessionId: string }; result: PlansSnapshot }`): Stop or drop a plan. Stopping or dropping the plan a live run applies
  interrupts that run. Resume is a message (`buildPlanResumeMessage`), not a call.
- `plans.edit` (`{ params: { op: PlanEditOp; planId: string; sessionId: string }; result: PlansSnapshot }`): A 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.
- `plans.get` (`{ params: { sessionId: string }; result: PlansSnapshot | null }`): The session's plans (from its live agent, else the store), or `null` for an unknown session.
- `prefs.get` (`{ params: Record<string, never>; result: HostComposerPrefs | null }`): The picks remembered across apps (`state.json`): effort and options per model, the next chat's model chain. `null` when none is. Additive.
- `prefs.set` (`{ params: { patch: HostComposerPrefs }; result: void }`): Merges picks into `state.json` (each top-level key replaces). Additive.
- `presence.list` (`{ params: Record<string, never>; result: SessionPresence[] }`): Current presence snapshot — backfill for a freshly opened session list.
- `presence.watch` (`{ params: { sessionId: string }; result: void }`): Tag 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.
- `queue.add` (`{ params: { activatedSkills?: string[]; asCommand?: string; attachments?: PromptAttachment[]; clientMessageId?: string; delivery?: QueueDelivery; keepDraft?: boolean; literal?: boolean; metadata?: Record<string, JsonValue>; origin?: TextOrigin; sessionId: string; text: string } & SendRequestId; result: { consumed?: 'steer' | 'followUp' | 'handled'; delivered: 'steer' | 'sent' | 'queued' } }`): Sends 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).
- `queue.attachments` (`{ params: { id: string; sessionId: string }; result: PromptAttachment[] | null }`): A queued entry's attachments with their bytes; `null` when already sent / dropped.
- `queue.list` (`{ params: { sessionId: string }; result: QueuedItem[] }`): Type-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.
- `queue.pushNow` (`{ params: { id: string; sessionId: string }; result: { delivered: 'send' | 'steer' | 'queued' | 'missing' } }`): Steer a queued entry, attachments included, into the live run now (falls back to send when idle).
- `queue.remove` (`{ params: { id: string; sessionId: string }; result: boolean }`): Removes a queued entry by id. Resolves `true` when it was removed.
- `queue.update` (`{ params: { attachments?: PromptAttachment[]; id: string; sessionId: string; text: string }; result: boolean }`): Edit a queued entry in place; order is kept. `attachments` replaces the
  entry's list when given. `false` when already sent / dropped.
- `references.providers` (`{ params: { cwd: string; peek?: boolean }; result: ReferenceProviderWire[] | null }`): The 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.
- `references.resolve` (`{ params: { cwd: string; items: { key: string; providerId: string }[] }; result: (ExtensionReferenceView | null)[] }`): The views of the keys a client found, in order: `null` for one that names nothing. At most 50 keys per call. Additive.
- `rpc.call` (`{ params: RpcCallParams & { cwd?: string }; result: RpcResponseEnvelope }`): Calls 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.
- `rpc.cancel` (`{ params: { callId: string }; result: boolean }`): Aborts this connection's `rpc.call` of `callId`; it answers `rpc.aborted`. `false` when none is in flight. Additive.
- `runtime.reload` (`{ params: Record<string, never>; result: void }`): Drop 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.
- `safelist.list` (`{ params: Record<string, never>; result: { projects: SafelistProject[] } }`, from `HitlIpcMethods`): The host's "Always allow" entries, per project (its `projects.json`): what approving with `accept-safelist` added. Additive.
- `safelist.remove` (`{ params: { entry: string; project: string }; result: { removed: boolean } }`, from `HitlIpcMethods`): Revoke one "Always allow" entry of a project; `removed: false` when it was not there. Additive.
- `schedules.create` (`{ params: ScheduleInput; result: Schedule }`): Create a schedule. The fields are a `ScheduleInput`.
- `schedules.delete` (`{ params: { id: string }; result: boolean }`): Remove a schedule and its fires. `false` when it was gone.
- `schedules.extensionRemoved` (`{ params: { extensionId: string }; result: void }`): An extension was removed: turn off the schedules whose action calls it (kept, marked, for the person to delete). A no-op while the feature is off.
- `schedules.fires` (`{ params: { id: string; limit?: number }; result: ScheduleFire[] }`): A schedule's fires, newest first (`limit` default 20, at most 50).
- `schedules.list` (`{ params: ScheduleListFilter; result: Schedule[] }`): The stored schedules, oldest first, each with its last fire. `sessionId`: only those whose prompt goes to it.
- `schedules.runNow` (`{ params: { id: string }; result: ScheduleFire }`): Run a schedule's action now; its next fire does not move.
- `schedules.status` (`{ params: Record<string, never>; result: { enabled: boolean; supported: boolean } }`): Whether the feature is on (`enabled`) and whether this host's store keeps schedules (`supported`).
- `schedules.update` (`{ params: { id: string; patch: SchedulePatch }; result: Schedule }`): Change the fields of `patch`. A new trigger, or turning it on, counts its next fire from now.
- `search.set` (`{ params: { active: boolean; query: string; sessionId: string }; result: void }`): Replace the shared transcript-search state (notification, per keystroke).
- `secrets.list` (`{ params: { sessionId: string }; result: SecretEntry[] }`, from `HitlIpcMethods`): The secrets of the session's project (`Settings.secrets`): names and expiry times, never values.
- `secrets.revoke` (`{ params: { name: string; sessionId: string }; result: { removed: boolean } }`, from `HitlIpcMethods`): Remove a secret of the session's project.
- `secrets.save` (`{ params: { name: string; sessionId: string; ttl: SecretTtl; value: string }; result: SecretEntry }`, from `HitlIpcMethods`): Add or replace a secret of the session's project. Refused over a plain-text connection from another machine.
- `server.update.check` (`{ params: Record<string, never>; result: ServerUpdateStatus }`): Check 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`.
- `server.update.configure` (`{ params: { enabled: boolean }; result: ServerUpdateStatus }`): Turn the zidane-server's self-update on or off.
- `server.update.install` (`{ params: Record<string, never>; result: ServerUpdateStatus }`): Install the release that is `ready` or `waiting` now, without waiting for background work to finish.
- `server.update.status` (`{ params: Record<string, never>; result: ServerUpdateStatus }`): A zidane-server's self-update: its state, the setting, the newest release seen.
- `sessions.appendNote` (`{ params: { blocks: CommandOutputBlock[]; sessionId: string }; result: boolean }`): `ctx.appendNote` outside a run: a display-only note, rendered live and
  persisted (`ChatHost.appendNote`). False for an unknown session or no blocks.
- `sessions.appendTurns` (`{ params: { sessionId: string; turns: SessionTurn[]; whenIdle?: boolean }; result: void }`): Turns 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).
- `sessions.artifacts` (`{ params: { kind?: string; limit?: number; sessionId: string }; result: SessionArtifact[] }`): Artifacts 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.
- `sessions.blockRuns` (`{ params: { sessionId: string }; result: { runs: Record<string, BlockRun> } }`): The session's saved block runs, by key (`blockRunKey`).
- `sessions.cacheImpact` (`{ params: { change: CacheImpactChange; sessionId: string }; result: CacheImpact | null }`): What 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.
- `sessions.cacheReport` (`{ params: { limit?: number; sessionId: string }; result: CacheReport | null }`): The 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".
- `sessions.compact` (`{ params: { sessionId: string }; result: CompactionReport | null }`): Compact now (`ChatHost.compactSessionNow`): what was done, `null` when nothing was. Older daemons resolve `null`.
- `sessions.contextBreakdown` (`{ params: { sessionId: string }; result: ContextBreakdown | null }`): The session's context usage broken down by category, or `null` when unknown.
- `sessions.contextSegments` (`{ params: { sessionId: string }; result: ContextSegmentsReport | null }`): Every 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`.
- `sessions.create` (`{ params: CreateSessionParams; result: SessionRow }`): Creates a session and resolves with its row.
- `sessions.createSystemOverride` (`{ params: { sessionId: string }; result: { created: boolean; path: string } }`): Seed a user-scope `SYSTEM.md` from the session's doctrine; throws when an override could not apply.
- `sessions.delete` (`{ params: { sessionId: string }; result: { environment?: EnvironmentTeardownResult } }`): Resolves with what happened to the session's environment (a provider may keep it).
- `sessions.deleteTurn` (`{ params: { sessionId: string; turnId: string }; result: void }`): History edits (`ChatHost.deleteTurn` / `editTurnText`): refused while the session runs.
- `sessions.editTurnText` (`{ params: { sessionId: string; text: string; turnId: string }; result: void }`): Replaces the text of one turn. Refused while the session runs.
- `sessions.environmentActions` (`{ params: { sessionId: string }; result: EnvironmentActionSummary[] }`): The per-session commands the session's environment offers right now (push, open PR, …).
- `sessions.export` (`{ params: { format: SessionExportFormat; sessionId: string }; result: SessionExportFile }`): The 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).
- `sessions.fork` (`{ params: { sessionId: string; title?: string; turnId: string }; result: { id: string } }`): Fork at `turnId` into a new session (`ChatHost.forkSession`); announced as a `sessions:changed` create.
- `sessions.generateTitle` (`{ params: { model?: string; providerKey?: string; sessionId: string }; result: { title: string } }`): Title 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".
- `sessions.get` (`{ params: { sessionId: string; turns?: boolean }; result: SessionDocumentHead | null }`): The 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.
- `sessions.getHeader` (`{ params: { sessionId: string; usage?: boolean }; result: SessionHeader | null }`): One 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.
- `sessions.getMeta` (`{ params: { sessionId: string }; result: SessionMeta | null }`): One `SessionMeta` by id (rows a filtered list can't return, e.g. the main); `null` when unknown.
- `sessions.getToolResult` (`{ params: { callId: string; sessionId: string; turnId?: string }; result: string | null }`): The 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.
- `sessions.getTurn` (`{ params: { sessionId: string; turnId: string }; result: SessionTurn | null }`): One turn of a session by id, or `null` when unknown.
- `sessions.getTurns` (`{ params: { from?: number; limit?: number; sessionId: string }; result: { total: number; turns: SessionTurn[]; version?: string } | null }`): A slice of a session's turns, `[from, from + limit)` (default from 0,
  [`SESSION_TURNS_PAGE`](https://zidane.si/docs/reference/ipc.md#SESSION_TURNS_PAGE) turns, at most [`SESSION_TURNS_MAX_PAGE`](https://zidane.si/docs/reference/ipc.md#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`](https://zidane.si/docs/reference/ipc.md#loadSessionDocument)) instead of in one reply. With
  `sessions.get` `turns: 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`](https://zidane.si/docs/reference/ipc.md#loadSessionDocument)). `null` when
  unknown. Additive: an older host answers "method not found", ignores
  `turns: false`, and names no version.
- `sessions.list` (`{ params: { archive?: 'active' | 'all' | 'archived'; projectRoot?: string | null }; result: SessionRow[] }`): Lists session rows. `projectRoot` filters by project, `archive` picks active, archived or all sessions.
- `sessions.listMeta` (`{ params: { projectRoot?: string | null }; result: SessionMeta[] }`): The 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.
- `sessions.loadEvents` (`{ params: { sessionId: string }; result: StreamEvent[] }`): The 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`](https://zidane.si/docs/reference/ipc.md#LOAD_EVENTS_PAGE_TURNS), at most
  [`LOAD_EVENTS_MAX_PAGE_TURNS`](https://zidane.si/docs/reference/ipc.md#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`](https://zidane.si/docs/reference/ipc.md#loadEventsPage). Paging is additive: an older host ignores the
  fields and answers the whole array.
- `sessions.moveEnvironment` (`{ params: { cwd?: string; environment: EnvironmentRequest; removeOldWorktree?: boolean; sessionId: string }; result: { oldWorktree?: EnvironmentTeardownResult } }`): Move an idle session to another environment (`local`, `worktree`, `local@M`, `worktree@M`, any direction), in `cwd` on the target; provisioning continues in the background.
- `sessions.removeBlockRun` (`{ params: { key: string; sessionId: string }; result: void }`): Forgets a block's saved run.
- `sessions.resume` (`{ params: { afterSeq: number; epoch: string; sessionId: string }; result: SessionResumeResult }`): Reattach without a reload: the session's signals numbered after
  `afterSeq` (see [`SIGNAL_SEQ_FIELD`](https://zidane.si/docs/reference/ipc.md#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.
- `sessions.retryEnvironment` (`{ params: { sessionId: string }; result: void }`): Provision a failed (or restart-stranded) environment again.
- `sessions.rewind` (`{ params: { inclusive: boolean; sessionId: string; turnId: string }; result: void }`): Cut the history at `turnId` in place (`ChatHost.rewindSession`); `inclusive` keeps the turn. Refused while the session runs.
- `sessions.runBlock` (`{ params: { code: string; language: string; sessionId: string; turnId: string }; result: { runId: string } }`): Runs 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.
- `sessions.runBlockCancel` (`{ params: { runId: string }; result: { cancelled: boolean } }`): Stops a Run here this connection started (`cancelled: false` when it is not running).
- `sessions.runEnvironmentAction` (`{ params: { actionId: string; sessionId: string }; result: EnvironmentActionResult }`): Run one of them in the session's environment (resumed when suspended).
- `sessions.setAgentId` (`{ params: { agentId: string; sessionId: string }; result: void }`): Switches the agent the session runs as.
- `sessions.setArchived` (`{ params: { archived: boolean; sessionId: string }; result: void }`): Archives or restores a session.
- `sessions.setEffort` (`{ params: { effort: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'adaptive'; sessionId: string }; result: void }`): Sets the thinking effort of the session.
- `sessions.setExtensionState` (`{ params: { extension: string; key: string; sessionId: string; value?: JsonValue }; result: void }`): One 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.
- `sessions.setFavorite` (`{ params: { favorite: boolean; sessionId: string }; result: void }`): Keep the session at the top of lists (`metadata.favorite`). Not activity: no recency bump. Additive.
- `sessions.setFolder` (`{ params: { cwd: string; sessionId: string }; result: void }`): Bind to a folder, or back to a plain chat with `cwd: ''` (`ChatHost.setSessionFolder`).
- `sessions.setLaunchOverrides` (`{ params: { sessionId: string } & SessionLaunchOverrides; result: void }`): `zidane 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.
- `sessions.setModel` (`{ params: { account?: string; effort?: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'adaptive'; fallbacks?: ModelFallbackRef[]; modelId: string; modelOptions?: Record<string, boolean>; providerKey: string; sessionId: string }; result: void }`): The 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).
- `sessions.setModelOptions` (`{ params: { options: Record<string, boolean>; sessionId: string }; result: void }`): Replaces the model-specific boolean options of the session.
- `sessions.setPolicy` (`{ params: { policy: SessionPolicy; sessionId: string }; result: void }`): Replaces 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.
- `sessions.setSpace` (`{ params: { sessionId: string; spaceId: string }; result: void }`): Move the session to a space (`metadata.spaceId`); the Default space id clears it. See `chat/spaces`.
- `sessions.setTitle` (`{ params: { sessionId: string; title: string }; result: void }`): Renames a session.
- `sessions.sideSession` (`{ params: { sessionId: string }; result: SideSessionLookup }`): A 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.
- `sessions.systemMd` (`{ params: { sessionId: string }; result: { file: SystemMdFile | null; shadowed: readonly SystemMdFile[] } | null }`): Which `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.
- `sessions.titleStatus` (`{ params: { sessionId: string }; result: string[] }`): How 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.
- `sessions.touch` (`{ params: { sessionId: string }; result: void }`): A 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.
- `sessions.workspaceCopy` (`{ params: { from: string; sessionId: string; toDir: string }; result: EntryResult }`): Copies `from` into folder `toDir` (`''`: the root) under a free name.
- `sessions.workspaceCreate` (`{ params: { content?: string; freeName?: boolean; kind: 'file' | 'dir'; path: string; sessionId: string }; result: EntryResult }`): Creates a file (`content`: base64 bytes, default empty) or a folder; `freeName` takes the next free name instead of refusing a taken one.
- `sessions.workspaceEmptyDirs` (`{ params: { sessionId: string }; result: string[] }`): The workspace's empty folders, relative to its root (a file listing leaves them out), capped.
- `sessions.workspaceExec` (`{ params: { command: string; cwd?: string; env?: Record<string, string>; sessionId: string; timeoutSeconds?: number }; result: ExecResult }`): The 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).
- `sessions.workspaceExecCancel` (`{ params: { execId: string }; result: { cancelled: boolean } }`): Kill a streamed command's process group (this connection's only; `cancelled: false` otherwise or when it already ended).
- `sessions.workspaceExecStream` (`{ params: { command: string; cwd?: string; sessionId: string }; result: { execId: string } }`): The 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`.
- `sessions.workspaceFileSize` (`{ params: { path: string; sessionId: string }; result: number | null }`): Size in bytes of a file in the session's workspace, or `null` when it does not exist.
- `sessions.workspaceListFiles` (`{ params: { options?: WorkspaceListFilesOptions; path: string; sessionId: string }; result: ListFilesEntry[] }`): Lists the entries under `path` in the session's workspace.
- `sessions.workspaceMove` (`{ params: { from: string; sessionId: string; to: string }; result: EntryResult }`): Moves (renames) `from` to `to`.
- `sessions.workspaceReadFile` (`{ params: { path: string; sessionId: string }; result: string }`): Reads a text file from the session's workspace.
- `sessions.workspaceRemove` (`{ params: { path: string; sessionId: string }; result: EntryResult }`): Removes `path` (a folder whole), for good.
- `sessions.workspaceWriteFile` (`{ params: { content: string; path: string; sessionId: string }; result: void }`): Writes a text file in the session's workspace.
- `settings.get` (`{ params: Record<string, never>; result: HostSettings }`): Reads the host settings.
- `settings.set` (`{ params: { patch: Partial<HostSettings> }; result: HostSettings }`): Applies a partial settings patch and resolves with the full settings after it.
- `sidebar.getSpace` (`{ params: Record<string, never>; result: string | null }`): The space a client's sidebar showed last, `null` when none was saved. Additive.
- `sidebar.getViews` (`{ params: Record<string, never>; result: Record<string, unknown> }`): The sidebar views a client saved on this host, by space id (`state.json`'s `sidebarViews`): each client checks what it reads. Additive.
- `sidebar.setSpace` (`{ params: { spaceId: string }; result: void }`): Saves the space the sidebar shows. Additive.
- `sidebar.setView` (`{ params: { spaceId: string; view: Record<string, unknown> }; result: void }`): Saves 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.
- `skills.browse` (`{ params: { source: string }; result: SkillSourceListing }`): The 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.
- `suggest.resolve` (`{ params: { caret: number; seq: number; sessionId: string; text: string }; result: { candidates?: string[]; seq: number; suggestion: string | null } }`): Resolve 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.
- `sync.claim` (`{ params: { categories?: SyncCategory[]; deviceId: string; deviceName: string; keys?: string[]; takeover?: boolean }; result: SyncClaimResult }`): Makes 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.
- `sync.push` (`{ params: { category: SyncCategory; deviceId: string; payload: SyncPayload }; result: SyncPushResult }`): Applies one category's snapshot from the source device.
- `sync.release` (`{ params: { deviceId: string }; result: { released: boolean } }`): Stops the source device's sync.
- `sync.reset` (`{ params: { field: string }; result: { reset: boolean } }`): Drops the local override of one field so sync applies to it again.
- `sync.status` (`{ params: Record<string, never>; result: SyncStatus }`): Settings 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.
- `terminal.ack` (`{ params: { clientId: string; offset: number; terminalId: string }; result: void }`): Acknowledges terminal output up to `offset`, so the host keeps it flowing.
- `terminal.adopt` (`{ params: { draftId: string; sessionId: string }; result: TerminalAdoptResult }`): The draft became `sessionId`: its terminals move there in one pass (over the cap: back to the project).
- `terminal.attach` (`{ params: { clientId: string; maxLines?: number; terminalId: string }; result: TerminalAttachResult }`): `maxLines` caps the history snapshot to the last lines a view can show (0 or absent: no cap).
- `terminal.close` (`{ params: { terminalId: string }; result: void }`): Closes a terminal.
- `terminal.detach` (`{ params: { clientId: string; terminalId: string }; result: void }`): Detaches a view from a terminal.
- `terminal.open` (`{ params: TerminalOpenInput; result: TerminalInfo }`): Opens a terminal in a session's environment.
- `terminal.openInProject` (`{ params: TerminalProjectOpenInput; result: TerminalInfo }`): Opens a terminal bound to a project rather than a session.
- `terminal.projectState` (`{ params: TerminalProjectStateInput; result: TerminalProjectState }`): Terminals 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.
- `terminal.registerViewer` (`{ params: { viewerId: string }; result: { ok: boolean } }`): This 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.
- `terminal.releaseDraft` (`{ params: { draftId: string }; result: void }`): The draft was discarded (or became a server session): its terminals go back to the project.
- `terminal.resize` (`{ params: { claim?: boolean; clientId: string; cols: number; rows: number; terminalId: string }; result: void }`): Resizes the terminal to a view's size. `claim` makes this view own the size.
- `terminal.restart` (`{ params: { terminalId: string }; result: TerminalInfo }`): Restarts a terminal's process and resolves with its info.
- `terminal.setHidden` (`{ params: { hidden: boolean; terminalId: string }; result: void }`): Hides a terminal from the agent, or shows it again.
- `terminal.state` (`{ params: { sessionId: string }; result: TerminalSessionState }`): Terminals, 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.
- `terminal.unregisterViewer` (`{ params: { viewerId: string }; result: { ok: boolean } }`): Withdraws a viewer registered with `terminal.registerViewer`.
- `terminal.write` (`{ params: { clientId?: string; data: string; response?: boolean; terminalId: string }; result: void }`): `clientId` + `response`: bytes the view's emulator generated (DSR/DA replies), dropped unless that view owns the size.
- `tokens.create` (`{ params: { name: string; scope: ServerTokenScope }; result: ServerTokenInfo & { token: string } }`): Create 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.
- `tokens.createMachineToken` (`{ params: { name: string }; result: { id: string; name: string; token: string } }`): Mint 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.
- `tokens.list` (`{ params: Record<string, never>; result: ServerTokenInfo[] }`): This server's tokens, revoked ones included, never their secrets (a zidane-server only). Additive.
- `tokens.machineInvite` (`{ params: { name?: string; ttlMs?: number }; result: { code: string; expiresAt: number } }`): Issue 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.
- `tokens.pair` (`{ params: { name?: string; scope: 'chat' | 'admin'; ttlMs?: number }; result: { code: string; expiresAt: number } }`): Issue 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.
- `tokens.revoke` (`{ params: { id: string }; result: { revoked: ServerTokenInfo[] } }`): Revoke a live token by id, with the live tokens it minted; their connections drop and the
  runs and terminals they started stop. Audited. Additive.
- `tokens.revokeSelf` (`{ params: Record<string, never>; result: { revoked: ServerTokenInfo[] } }`): Revoke 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.
- `ui.client.announce` (`{ params: UiClientAnnounce; result: void }`): What 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.
- `ui.client.reply` (`{ params: { requestId: string; result: unknown }; result: boolean }`): Answers a `ui:client` request sent to this connection. `false` when it is no longer pending. Additive.
- `ui.dialog.answer` (`{ params: { answer?: unknown; dialogId: string }; result: boolean }`): Answers a `ui:dialog` shown on this connection (`answer` absent: cancelled). `false` when it is no longer pending. Additive.
- `ui.dialog.validate` (`{ params: { dialogId: string; key: string; value: unknown }; result: string | null }`): Checks 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.
- `usage.github` (`{ params: { probe?: boolean }; result: ProviderUsageSnapshot[] }`): GitHub'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.
- `usage.providers` (`{ params: { refresh?: boolean }; result: readonly ProviderUsageSnapshot[] }`): The 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.
- `usage.summary` (`{ params: { range: UsageRange }; result: UsageSummary }`): Token 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.

Source: [src/ipc/protocol.ts:506](https://github.com/Tahul/zidane/blob/main/src/ipc/protocol.ts#L506)

### `PairBrowserOptions`

Interface.

Options for [`pairBrowser`](https://zidane.si/docs/reference/ipc-browser.md#pairBrowser).

```ts
interface PairBrowserOptions
```

**Properties**

- `fetch?` (`(url: string, init: RequestInit) => Promise<Response>`): The fetch to use. Default: `globalThis.fetch`.

Source: [src/ipc/browser-pair.ts:54](https://github.com/Tahul/zidane/blob/main/src/ipc/browser-pair.ts#L54)

### `PairedBrowser`

Interface.

A paired browser's device token.

```ts
interface PairedBrowser
```

**Properties**

- `id?` (`string`): The token's id, the one `tokens.list` and `tokens.revoke` use. Absent from servers older than it.
- `scope` (`'chat' | 'admin'`): The scope the code was issued with.
- `serverName?` (`string`): The server's name, when it has one (`--name`).
- `token` (`string`): The token, for `createServerClient({ token })`. Keep it; it is shown once.

Source: [src/ipc/browser-pair.ts:42](https://github.com/Tahul/zidane/blob/main/src/ipc/browser-pair.ts#L42)

### `ServerClient`

Interface.

A connection to a zidane-server: typed calls, signals and its state.

```ts
interface ServerClient
```

**Properties**

- `call` (`<M extends keyof IpcMethods>(method: M, params: IpcParams<M>) => Promise<IpcResult<M>>`): Calls a method. Waits while (re)connecting; fails when the connection drops mid-call.
- `can` (`(method: keyof IpcMethods) => boolean`): Whether this connection may call `method`: the host offers it and the token reaches it.
  `true` against a host that predates the list. `false` while not open.
- `close` (`() => void`): Closes the connection and stops reconnecting.
- `hello` (`() => HelloResult | null`): The current connection's hello, `null` while not open.
- `notify` (`<M extends keyof IpcMethods>(method: M, params: IpcParams<M>) => void`): Sends a notification (no answer). Dropped while not open.
- `onOpen` (`(listener: (hello: HelloResult, reconnected: boolean) => void) => () => void`): Called after every handshake, `reconnected` after the first: re-read or resume what the
  page shows. Returns its unsubscribe.
- `onSignal` (`(listener: (signal: HostSignal, meta?: SignalMeta) => void) => () => void`): Called with every signal the host fans out, and its position in its session; returns its unsubscribe.
- `onState` (`(listener: (state: ServerClientState) => void) => () => void`): Called on every state change; returns its unsubscribe.
- `ready` (`Promise<HelloResult>`): Resolves with the first hello; rejects when the client is refused or closed before it.
- `state` (`() => ServerClientState`): The connection's state now.

Source: [src/ipc/browser.ts:116](https://github.com/Tahul/zidane/blob/main/src/ipc/browser.ts#L116)

### `ServerClientOptions`

Interface.

Options for [`createServerClient`](https://zidane.si/docs/reference/ipc-browser.md#createServerClient).

```ts
interface ServerClientOptions
```

**Properties**

- `appVersion?` (`string`): Reported in the server's logs and audit (default `'web'`).
- `connectTimeoutMs?` (`number`): How long an attempt may take to open and finish its handshake before it is dropped and retried, in ms (default 10 000).
- `fetch?` (`typeof fetch`): `fetch`, for the auth check after a failed connect. Default: the global one.
- `heartbeatMs?` (`number`): Ping interval in ms; a ping unanswered by the next one drops the connection (default 20 000; 0: off).
- `onState?` (`(state: ServerClientState) => void`): Called on every state change.
- `reconnect?` (`false | { initialMs?: number; maxMs?: number }`): First reconnect delay and its ceiling, in ms (default 500 doubling to 15 000). `false`: never reconnect.
- `token?` (`string`): A client token (`zidane server token create --scope chat`). Absent: a server without auth.
- `url` (`string`): `ws://` or `wss://` URL of the server.
- `WebSocket?` (`(url: string | URL, protocols?: string | string[]) => WebSocket`): WebSocket constructor. Default: the global one.

Source: [src/ipc/browser.ts:60](https://github.com/Tahul/zidane/blob/main/src/ipc/browser.ts#L60)

### `SignalMeta`

Interface.

What a signal listener gets beside the signal: its number in its session, when it has one.

```ts
interface SignalMeta
```

**Properties**

- `seq` (`number`): Position of the signal in its session. Starts at 1 and has no gaps within one host process.

Source: [src/ipc/protocol.ts:461](https://github.com/Tahul/zidane/blob/main/src/ipc/protocol.ts#L461)

## Types

### `ClientScope`

Type.

A client token's reach: [`CLIENT_SCOPES`](https://zidane.si/docs/reference/ipc-browser.md#CLIENT_SCOPES).

```ts
type ClientScope = typeof CLIENT_SCOPES[number]
```

Source: [src/ipc/scopes.ts:31](https://github.com/Tahul/zidane/blob/main/src/ipc/scopes.ts#L31)

### `IpcMethodName`

Type.

Name of any method in [`IpcMethods`](https://zidane.si/docs/reference/ipc-browser.md#IpcMethods).

```ts
type IpcMethodName = keyof IpcMethods
```

Source: [src/ipc/protocol.ts:1916](https://github.com/Tahul/zidane/blob/main/src/ipc/protocol.ts#L1916)

### `IpcParams`

Type.

Params type of the method `M` in [`IpcMethods`](https://zidane.si/docs/reference/ipc-browser.md#IpcMethods).

```ts
type IpcParams<M extends IpcMethodName> = IpcMethods[M]['params']
```

**Type parameters**

- `M` (`extends IpcMethodName`)

Source: [src/ipc/protocol.ts:1918](https://github.com/Tahul/zidane/blob/main/src/ipc/protocol.ts#L1918)

### `IpcResult`

Type.

Result type of the method `M` in [`IpcMethods`](https://zidane.si/docs/reference/ipc-browser.md#IpcMethods).

```ts
type IpcResult<M extends IpcMethodName> = IpcMethods[M]['result']
```

**Type parameters**

- `M` (`extends IpcMethodName`)

Source: [src/ipc/protocol.ts:1920](https://github.com/Tahul/zidane/blob/main/src/ipc/protocol.ts#L1920)

### `ServerClientState`

Type.

Where a [`ServerClient`](https://zidane.si/docs/reference/ipc-browser.md#ServerClient)'s connection is.

```ts
type ServerClientState =
  | { attempt: number; status: 'connecting' }
  | { hello: HelloResult; status: 'open' }
  | { attempt: number; error: string; inMs: number; status: 'retrying' }
  | { message: string; reason: ServerRefusal; status: 'refused' }
  | { status: 'closed' }
```

Source: [src/ipc/browser.ts:50](https://github.com/Tahul/zidane/blob/main/src/ipc/browser.ts#L50)

### `ServerPairFailure`

Type.

Why a pairing failed. The server's answers: `invalid` (no such code, or not a
code's shape), `expired`, `used` (spent, or burned by wrong attempts),
`rate-limited`, `forbidden` (an origin, proxy or transport its upgrade policy
refuses). And the client's: `unavailable` (the server has no pairing route:
too old, or running without auth) and `network` (no answer it understands).

```ts
type ServerPairFailure =
  | 'invalid'
  | 'expired'
  | 'used'
  | 'rate-limited'
  | 'forbidden'
  | 'unavailable'
  | 'network'
```

Source: [src/ipc/browser-pair.ts:19](https://github.com/Tahul/zidane/blob/main/src/ipc/browser-pair.ts#L19)

### `ServerRefusal`

Type.

Why a server refused this client for good: `token` (unknown or revoked), the server's
admission refusals (`origin` not allowed, `insecure-transport`, `untrusted-proxy`, a
`scope` it may not connect with), or a `protocol` the two don't share.

```ts
type ServerRefusal =
  | 'token'
  | 'origin'
  | 'insecure-transport'
  | 'untrusted-proxy'
  | 'scope'
  | 'protocol'
```

Source: [src/ipc/browser.ts:47](https://github.com/Tahul/zidane/blob/main/src/ipc/browser.ts#L47)

## Re-exports

These names are documented on the entry point that owns them.

- [zidane/chat](https://zidane.si/docs/reference/chat.md): [`HostSignal`](https://zidane.si/docs/reference/chat.md#HostSignal)
