{
  "api": "vibeke/1",
  "generated_from": "vk-server METHODS tables; signatures from spec/07 §2; params/result shapes from the schema registry (crates/vk-server/src/api_schema.rs)",
  "schema": "vibeke-1.schema.json",
  "shape_language": "{field, field?: type = default, ...}; [T]; A|B (bare lowercase words are string literals); {*: T} maps; CamelCase names are shared definitions in the schema's $defs",
  "render_protocol": 4,
  "holder_protocol": {
    "proto": 2,
    "min": 1
  },
  "method_count": 259,
  "methods": [
    {
      "name": "adapter.delivery_ack",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": null,
      "spec": null,
      "params": "{interaction: Target, idempotency_key: string, applied?: bool}",
      "result": "{}"
    },
    {
      "name": "adapter.gate",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": null,
      "spec": null,
      "params": "{harness: string, event: string, payload?: any, pid?: int}",
      "result": "{decision: object | null, interaction?: Target, idempotency_key?: string, mode?: observe, resumed?: bool}"
    },
    {
      "name": "adapter.report_self",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": null,
      "spec": null,
      "params": "{pane?: Target, pane_id?: Target, source?: string = vibeke, seq?: int, agent?: string, harness?: string, state: idle|working|blocked|done|string, message?: string, resume_argv?: [string]}",
      "result": "{type: 'ok', dropped?: 'stale_seq', applied?: bool}"
    },
    {
      "name": "adapter.signal",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": null,
      "spec": null,
      "params": "{harness: string, event: string, payload?: any, pid?: int}",
      "result": "{}"
    },
    {
      "name": "agent.get",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{target}` → `{run, pane, open_interactions[], last_turn?}`",
      "params": "{target: Target}",
      "result": "{run: AgentRun, pane: Pane, open_interactions: [Interaction], last_turn?: any}"
    },
    {
      "name": "agent.harnesses",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{}` → `{harnesses: [{id, display, version_detected?, integration_installed, capabilities: {native_approval, native_question, steer, transcript, resume, headless}}]}`",
      "params": "{}",
      "result": "{harnesses: [{id: string, display?: string, version_detected?: string|null, integration_installed?: bool, capabilities?: [string]}]}"
    },
    {
      "name": "agent.interrupt",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{target}` → `{run}` — native abort where available (`abort` RPC, Esc for TUIs)",
      "params": "{target: Target}",
      "result": "{run: AgentRun}"
    },
    {
      "name": "agent.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{workspace?, state?: [AgentState], harness?}` → `{runs: [AgentRun + {pane, open_interactions: n}]}`",
      "params": "{workspace?: Target, state?: [AgentState], harness?: string}",
      "result": "{runs: [AgentRun]}"
    },
    {
      "name": "agent.manifests",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agents"
      ],
      "milestone": null,
      "spec": null,
      "params": "{}",
      "result": "{manifests: [{id: string, name: string, source: string, family: string, transports: [string], validated_range: any, capabilities_unversioned: any, capabilities_unverified: any, detects: bool, screen_rules: bool, warnings: [string]}], warnings: [string]}"
    },
    {
      "name": "agent.manifests_reload",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": null,
      "spec": null,
      "params": "{}",
      "result": "{warnings: [string], manifests: [{id: string, name: string, source: string, family: string, transports: [string], validated_range: any, capabilities_unversioned: any, capabilities_unverified: any, detects: bool, screen_rules: bool, warnings: [string]}]}"
    },
    {
      "name": "agent.prompt",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{target, text, images?: [blob|path], mode?: send|steer|follow_up = send, wait?: bool, until?: [AgentState], timeout_ms?}` → `{run, turn?}` — submits text + Enter atomically via the best channel (RPC `prompt`/`steer` for headless and extension-capable harnesses, bracketed paste + Enter otherwise). If the run is not working and no lifecycle change occurs within 5 s → `stalled`",
      "params": "{target: Target, text: string, images?: [string], mode?: send|steer|follow_up = send, wait?: bool, until?: [string], timeout_ms?: int}",
      "result": "{run: AgentRun, turn?: any}"
    },
    {
      "name": "agent.read",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{target, source?: visible|recent|transcript, lines?, format?}` → as `pane.read`, plus `transcript` returns the last N turns from the structured log",
      "params": "{target: Target, source?: visible|recent|transcript = visible, lines?: int, format?: text|ansi|cells}",
      "result": "{text?: string, turns?: [any], rows?: int, revision?: int, truncated?: bool}"
    },
    {
      "name": "agent.release",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{target}` → `{}` — stop tracking (the process keeps running as an untracked pane occupant)",
      "params": "{target: Target}",
      "result": "{}"
    },
    {
      "name": "agent.rename",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{target, name: string|null}` → `{run}`",
      "params": "{target: Target, name: string|null}",
      "result": "{run: AgentRun}"
    },
    {
      "name": "agent.report",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": null,
      "spec": null,
      "params": "{pane?: Target, state: string, harness?: string = claude, message?: string}",
      "result": "{}"
    },
    {
      "name": "agent.resumable",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agents"
      ],
      "milestone": null,
      "spec": null,
      "params": "{}",
      "result": "{runs: [AgentRun]}"
    },
    {
      "name": "agent.resume",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{pane?, run: ended_run_id, mode?}` → `{run}` — re-launches via the harness resume argv in the same or a new pane",
      "params": "{pane?: Target, run: Target, mode?: string}",
      "result": "{run: AgentRun}"
    },
    {
      "name": "agent.send_keys",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{target, keys}` → `{}`",
      "params": "{target: Target, keys: [string]}",
      "result": "{}"
    },
    {
      "name": "agent.spawn",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{harness, name?, where: {split_of: pane, direction?} | {new_tab_in: workspace} | {task: task} , prompt?, args?, focus?: false}` → `{pane, run}` — Creates a pane or tab, starts the agent, and optionally sends the first prompt.",
      "params": "{harness: string, name?: string, where?: object, prompt?: string, args?: [string], focus?: bool = false}",
      "result": "{pane: Pane, run: AgentRun}"
    },
    {
      "name": "agent.start",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{pane, harness, name?, mode?: tui|headless = tui, args?: [..], env?, model?, task?, ready_timeout_ms?: 30000}` → `{run}` — requires an available shell pane at its prompt (`conflict:pane_busy` otherwise). Returns once the adapter (or detector) reports `idle`",
      "params": "{pane?: Target, harness: string, name?: string, mode?: tui|headless = tui, args?: [string], env?: {*: string}, model?: string, task?: Target, ready_timeout_ms?: int = 30000}",
      "result": "{run: AgentRun}"
    },
    {
      "name": "agent.wait",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{target, until?: [WaitCondition] = [idle, done, needs_approval, needs_answer, error, exited], timeout_ms?}` → `{run, state, interaction?}` — `WaitCondition` is an execution state (04 §2.4) or a derived condition. `needs_approval`/`needs_answer` means an open interaction of that type. `done` means idle after a turn completes since the wait started. It does not mean that the user read the result.",
      "params": "{target: Target, until?: [string], timeout_ms?: int}",
      "result": "{run: AgentRun, state: string, interaction?: Interaction}"
    },
    {
      "name": "api.methods",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{}` → `{methods: [{name, milestone, capability, mutating}]}`",
      "params": "{}",
      "result": "{methods: [{name: string, mutating: bool, milestone?: string, capability?: string}]}"
    },
    {
      "name": "api.schema",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{method?}` → `{schema}` — the JSON Schema bundle (§1.5), or with `method` that method's `x-method` entry plus `$defs`. `not_found` for an unknown method",
      "params": "{method?: string}",
      "result": "{schema: object}"
    },
    {
      "name": "assistant.cancel",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "assist"
      ],
      "milestone": "14; as built 2026-10-06",
      "spec": "`{request}` → `{request}`. Aborts the provider call. A canceled active request still counts its reservation against the day's budget",
      "params": "{request: string}",
      "result": "{request: object}"
    },
    {
      "name": "assistant.confirm",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "assist"
      ],
      "milestone": "14; as built 2026-10-06",
      "spec": "`{request, preview_digest}` → `{request}` (state `queued`). Rechecks consent, endpoint, queue, rate and daily budget. Sends exactly the previewed payload",
      "params": "{request: string, preview_digest: string}",
      "result": "{request: object}"
    },
    {
      "name": "assistant.consent",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "assist"
      ],
      "milestone": "14; as built 2026-10-06",
      "spec": "`{workspace?, connection?\\|profile?, classes?: [selected_text\\|structured_state\\|review_package\\|screen], operations?: [op], auto_send?: [op]}` → `{consent, notice}`. Default classes exclude `screen`. The grant binds the canonical workspace path to the connection's adapter+endpoint fingerprint",
      "params": "{workspace?: Target, connection?: string, profile?: string, classes?: [selected_text|structured_state|review_package|screen], operations?: [string], auto_send?: [string]}",
      "result": "{consent: object, notice: string}"
    },
    {
      "name": "assistant.generate",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "assist"
      ],
      "milestone": "14; as built 2026-10-06",
      "spec": "`{operation: suggest_task_details\\|review_summary\\|pane_title\\|briefing\\|handoff\\|effort_estimate, profile?, idempotency_key?, retry_of?, inputs \\| top-level: {run?, turns?: [n], pane?, task?, workspace?, include_screen?}}` → `{request, preview: {digest, system, user, model, adapter, endpoint_host, execution_machine, max_output_tokens, bytes, estimated_input_tokens, estimated_max_cost_usd?, sources, omitted, redactions, notice}, requires_confirmation, confirm_with?}`. Consent is checked before content is retrieved. Nothing is sent unless the operation is in both `[assistant] auto_send` and the workspace consent's `auto_send`",
      "params": "{operation: suggest_task_details|review_summary|pane_title|briefing|handoff|effort_estimate, profile?: string, idempotency_key?: string, retry_of?: string, inputs?: object, run?: Target, turns?: [int], pane?: Target, task?: Target, workspace?: Target, include_screen?: bool}",
      "result": "{request: object, preview: {digest: string, system?: string, user?: string, model?: string, adapter?: string, endpoint_host?: string, execution_machine?: string, max_output_tokens?: int, bytes?: int, estimated_input_tokens?: int, estimated_max_cost_usd?: number|null, sources?: [object], omitted?: any, redactions?: any, notice?: string}, requires_confirmation: bool, confirm_with?: object}"
    },
    {
      "name": "assistant.get",
      "mutating": false,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "open",
      "tables": [
        "assist"
      ],
      "milestone": "14; as built 2026-10-06",
      "spec": "`{request}` → `{request: {id, operation, state: awaiting_confirmation\\|queued\\|running\\|done\\|failed\\|cancelled\\|interrupted, workspace, inputs (IDs only), profile, connection, adapter, model, endpoint_host, machine, prompt_version, sources (metadata + digests), omitted, redactions, context_digest, preview_digest, payload_bytes, estimated_input_tokens, max_output_tokens, usage: {input_tokens?, output_tokens?}, attempts, estimated_cost_usd?, finish_reason?, error?: {category, message}, output?: {generated: true, label, ...operation fields}, timestamps}}`",
      "params": "{request: string}",
      "result": "{request: object}"
    },
    {
      "name": "assistant.list",
      "mutating": false,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "open",
      "tables": [
        "assist"
      ],
      "milestone": "14; as built 2026-10-06",
      "spec": "`{workspace?, state?, limit?}` → `{requests}` (without outputs)",
      "params": "{workspace?: Target, state?: string, limit?: int}",
      "result": "{requests: [object]}"
    },
    {
      "name": "assistant.providers",
      "mutating": false,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "open",
      "tables": [
        "assist"
      ],
      "milestone": "14; as built 2026-10-06",
      "spec": "`{}` → `{connections: [{id, adapter, endpoint, endpoint_error?, credential, verified}], profiles, default_profile}`",
      "params": "{}",
      "result": "{connections: [{id: string, adapter: string, endpoint: string, endpoint_error?: string|null, credential: string, verified: bool}], profiles: [object], default_profile?: string|null}"
    },
    {
      "name": "assistant.purge",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "assist"
      ],
      "milestone": "14; as built 2026-10-06",
      "spec": "`{request}\\|{workspace}\\|{all: true}` → `{purged}`. Deletes records and generated outputs (cancels unfinished ones first)",
      "params": "{request?: string, workspace?: Target, all?: bool}",
      "result": "{purged: int}"
    },
    {
      "name": "assistant.revoke",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "assist"
      ],
      "milestone": "14; as built 2026-10-06",
      "spec": "`{workspace?, connection?}` → `{revoked, cancelled_requests}`. Cancels that workspace's unfinished requests",
      "params": "{workspace?: Target, connection?: string}",
      "result": "{revoked: int, cancelled_requests: int}"
    },
    {
      "name": "assistant.status",
      "mutating": false,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "open",
      "tables": [
        "assist"
      ],
      "milestone": "14; as built 2026-10-06",
      "spec": "`{}` → `{enabled, configured, config_problem?, coordinator: {machine, session}, profile?: {id, connection, adapter, model, endpoint_host, credential: \"env:NAME\"\\|\"file:PATH\"\\|..., limits, pricing_usd_per_mtok?}, limits, today: {utc_day, used, reserved, remaining}, auto_send, consents, requests: {awaiting_confirmation, queued, running, stored}, operations, background: false}` — no secrets, no provider contact",
      "params": "{}",
      "result": "{enabled: bool, configured: bool, config_problem?: string|null, coordinator?: {machine: string, session: string}, profile?: object|null, limits?: object, today?: {utc_day: int, used: any, reserved: any, remaining: any}}"
    },
    {
      "name": "attention.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{budget_ms?: int, effort?: quick|minutes|deep}",
      "result": "{items: [{key: {kind: string, id: string}, class: int | 'finished_turns', title: string, subtitle: string, task: string | null, run: string | null, pane: string | null, interaction: string | null, explanation: string, age_ms: int, risk: string | null, effort: string | null, effort_estimate: {effort: string, source: 'heuristic'} | null, blocks_tasks: int, snoozed_until_ms: int | null, woke_from_snooze: string | null, urgent: bool}], coverage: {complete: bool, notes: [string], scope: 'all' | {workspace: string}, excluded: int}, five_minute: {keys: [{kind: string, id: string}], omitted_count: int, note: string, item_notes: [{key: {kind: string, id: string}, note: string}]} | null}"
    },
    {
      "name": "attention.update",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{key: {kind: string, id: string}, seen?: bool, item_rev?: int, snooze_until_ms?: int | null, pin?: bool}",
      "result": "{key: {kind: string, id: string}, seen: bool, seen_rev: int | null, snoozed_until_ms: int | null, pinned: bool, warning: string | null}"
    },
    {
      "name": "blob.abort",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{upload_id: string}",
      "result": "{aborted: bool}"
    },
    {
      "name": "blob.append",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{upload_id: string, offset: int, data_b64: string}",
      "result": "{offset: int}"
    },
    {
      "name": "blob.begin",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{name: string, size: int, sha256?: string}",
      "result": "{upload_id: string, max_chunk: int}"
    },
    {
      "name": "blob.commit",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{upload_id: string, stage?: browser, unpack?: tar}",
      "result": "{hash: string, sha256: string, size: int, path_on_machine: string, path: string, unpacked?: bool}"
    },
    {
      "name": "blob.get",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "blob_api"
      ],
      "milestone": "M1",
      "spec": "`{hash, range?}` → `{mime, data_b64}`",
      "params": "{hash: string, range?: {offset?: int, length?: int}}",
      "result": "{hash: string, mime: string, size: int, offset: int, length: int, data_b64: string}"
    },
    {
      "name": "blob.put",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{mime, data_b64}` (≤ 16 MiB) or `{mime, path}` (server reads local file) → `{hash, size}`",
      "params": "{mime: string, data_b64?: string, path?: string}",
      "result": "{hash: string, size: int}"
    },
    {
      "name": "blob.stat",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "blob_api"
      ],
      "milestone": "M1",
      "spec": "`{hash}` → `{mime, size, created_at, refs}`",
      "params": "{hash: string}",
      "result": "{hash: string, mime: string, size: int, created_at: int, refs: int, path: string}"
    },
    {
      "name": "browser.attach_screencast",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{session}` → `{session, delivery: \"internal+poll\", width, height}` / `{session, detached}` / `{session, after_seq?}` → `{session, seq, mime: \"image/jpeg\", width, height, received_ms, data_b64 \\| null}` — full scope only. In-process browser panes use `AgentBrowsers::attach_screencast` (latest-wins `watch` channel) and `AgentBrowsers::human_input`.",
      "params": "{session?: string, browser_session?: string, target?: string}",
      "result": "{session: string, delivery: string, width: int, height: int, poll: string}"
    },
    {
      "name": "browser.click",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{browser_session, selector|text|role, text?, key?, submit?}` → `{}`",
      "params": "{session?: string, browser_session?: string, target?: string, selector?: string, text?: string, x?: number, y?: number, click_count?: int = 1, timeout_ms?: int = 5000}",
      "result": "{session: string, x: number, y: number, element: {x: number, y: number, width: number, height: number, tag: string, text: string}|null}"
    },
    {
      "name": "browser.close",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agent_browser"
      ],
      "milestone": null,
      "spec": null,
      "params": "{session?: string, browser_session?: string, target?: string}",
      "result": "{session: string, closed: bool}"
    },
    {
      "name": "browser.command",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "browser_pane"
      ],
      "milestone": "M3",
      "spec": "`{pane, cmd: back|forward|reload|stop|navigate|screenshot|text|window|pane, url?, hard?, text?}` → `{pane}` (`window` → the `preview.open` window result. `pane` → `{pane, profile}`) — for panes rendered by this server. Not from a pane.",
      "params": "{pane: Target, cmd: back|forward|reload|stop|navigate|screenshot|text|window|pane, url?: string, hard?: bool, text?: string}",
      "result": "{pane: string} | {pane: string, profile: string} | {opened_in: window, url: string, machine: string, profile: string, profile_dir: string, browser: string, browser_kind: string, pid: int, reused: bool, socks_port: int|null, route: string} | {opened_in: default_browser, url: string} | object"
    },
    {
      "name": "browser.console",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{browser_session|preview, since_ms?, level?: error|warn|all}` → `{entries: [{ts, level, text, source}]}`",
      "params": "{session?: string, browser_session?: string, target?: string, level?: error|warn|warning|all, since_ms?: int, since?: string, limit?: int = 200} | {pane: Target, kind?: all|console|network, level?: string, errors?: bool, failed?: bool, failed_only?: bool, after?: int, since_ms?: int, since?: string, limit?: int}",
      "result": "{session: string, entries: [{ts: int, level: string, text: string, source: string, url?: any, line?: int|null}]} | {pane: string, entries: [object], last_seq: int, source: local|relayed|none, url: string|null}"
    },
    {
      "name": "browser.detach_screencast",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{session}` → `{session, delivery: \"internal+poll\", width, height}` / `{session, detached}` / `{session, after_seq?}` → `{session, seq, mime: \"image/jpeg\", width, height, received_ms, data_b64 \\| null}` — full scope only. In-process browser panes use `AgentBrowsers::attach_screencast` (latest-wins `watch` channel) and `AgentBrowsers::human_input`.",
      "params": "{session?: string, browser_session?: string, target?: string}",
      "result": "{session: string, detached: bool}"
    },
    {
      "name": "browser.diff",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "screenshots"
      ],
      "milestone": "M3",
      "spec": "`{a: blob, b: blob, threshold?}` → `{blob, changed_ratio, regions}` — refuses different `environment.kind` unless `force`",
      "params": "{a: string, b: string, threshold?: number|string = 0.1, force?: bool, inline?: bool}",
      "result": "{a: object, b: object, threshold: number, channel_threshold: any, width: int, height: int, size_mismatch: bool, a_size: {width: int, height: int}, b_size: {width: int, height: int}, changed_pixels: int, total_pixels: int, changed_ratio: number, regions: [{x: int, y: int, width: int, height: int, pixels: int}], regions_total: int, forced: bool, blob: string, path_on_machine: string, bytes: int, data_b64?: string, mime?: string, inline_skipped?: string}"
    },
    {
      "name": "browser.dom",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{browser_session|preview, selector?, format?: text|html|a11y}` → `{content}`",
      "params": "{session?: string, browser_session?: string, target?: string, format?: a11y|accessibility|text|html = a11y, max_bytes?: int, selector?: string}",
      "result": "{session: string, url: string, format: string, content: string, truncated: bool}"
    },
    {
      "name": "browser.eval",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{browser_session, expression}` → `{value}` — gated by capability `browser.script`",
      "params": "{session?: string, browser_session?: string, target?: string, expression?: string, js?: string}",
      "result": "{session: string, value: any}"
    },
    {
      "name": "browser.install",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{confirm?, version?, url?, sha256?}` → without `confirm`: `{plan: {version, platform, url, sha256, checksum_known, dir, binary, installed}, confirm_required: true}`. With `confirm`: downloads, verifies, installs → `{installed, binary, plan}`. Full scope only.",
      "params": "{confirm?: bool, version?: string, url?: string, sha256?: string}",
      "result": "{plan: {version: string, platform: string, url: string, sha256: string|null, checksum_known: bool, dir: string, binary: string, installed: bool}, confirm_required: bool} | {installed: bool, binary: string, plan: object}"
    },
    {
      "name": "browser.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{}` → `{sessions: [...], browser: <status>, machine}` — only sessions the caller may see.",
      "params": "{}",
      "result": "{sessions: [object], browser: object, machine: string}"
    },
    {
      "name": "browser.navigate",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{browser_session, url|path, wait?}` → `{status, final_url}` — destination rules apply to redirects too (06 B5)",
      "params": "{session?: string, browser_session?: string, target?: string, url?: string, path?: string, wait?: load|domcontentloaded|commit|none|string = load, timeout_ms?: int = 15000}",
      "result": "{session: string, status: int|null, final_url: string, title: string}"
    },
    {
      "name": "browser.network",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{browser_session|preview, failed_only?, since_ms?}` → `{entries: [{ts, method, url, status?, error?, blocked_by_policy?}]}`",
      "params": "{session?: string, browser_session?: string, target?: string, failed_only?: bool, failed?: bool, since_ms?: int, since?: string, limit?: int = 200} | {pane: Target, kind?: all|console|network, level?: string, errors?: bool, failed?: bool, failed_only?: bool, after?: int, since_ms?: int, since?: string, limit?: int}",
      "result": "{session: string, entries: [{ts: int, method?: string|null, url?: string, type: string|null, status?: int|null, error?: string|null, mime?: string|null, blocked_reason?: string, blocked_by_policy?: string, layer?: string, duration_ms?: int}]} | {pane: string, entries: [object], last_seq: int, source: local|relayed|none, url: string|null}"
    },
    {
      "name": "browser.open",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agent_browser"
      ],
      "milestone": null,
      "spec": null,
      "params": "{url?: string, preview?: string, machine?: string, device?: string, viewport?: string | {width?: int, height?: int, w?: int, h?: int}, dpr?: number, color_scheme?: string, dark?: bool, wait?: string, timeout_ms?: int}",
      "result": "BrowserSession"
    },
    {
      "name": "browser.pane.console",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "browser_pane"
      ],
      "milestone": "M3",
      "spec": "`{pane, toggle?: true, focus?: false}` → `{pane, pane_handle, browser_pane}` (opened) \\| `{closed, pane_handle, browser_pane}` (toggled off) \\| `{…, existing: true}` (`toggle: false`) — the console/network split: a pane under the browser pane (30 %) running `vibeke browser console --pane <id> --follow`, marked `created_by = \"browser-console:<browser pane id>\"`. Closed by the server when its browser pane goes. Not from a pane.",
      "params": "{pane?: Target, toggle?: bool = true, focus?: bool = false}",
      "result": "{closed: string, pane_handle: string, browser_pane: string} | {pane: string, pane_handle: string, browser_pane: string, existing?: bool}"
    },
    {
      "name": "browser.pane.console_push",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "browser_pane"
      ],
      "milestone": "M3",
      "spec": "`{pane, entries: [console/network entry]}` → `{pane, stored}` — The media host sends captured entries to the browser pane owner. The page must use a loopback URL. Limits: one batch per second and 200 entries per batch. The owner keeps only known fields in its ring buffer. It removes sensitive data again and limits text to 8 KiB. Pane tokens cannot call this method.",
      "params": "{pane: Target, entries: [object]}",
      "result": "{pane: string, stored: int}"
    },
    {
      "name": "browser.pane.create",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "browser_pane"
      ],
      "milestone": "M3",
      "spec": "`{pane?, preview? | url?, split?, machine?, focus?: true, focus_client?}` → `{opened_in: \"pane\", pane, pane_handle, tab, url, machine, source_pane}` — on the owning server. `pane` defaults to the preview's pane, then the caller's pane / focused pane. URLs: `http(s)` (`localhost:5173/x` gets `http://`). From a pane only loopback, only next to the caller's own panes, never moving focus. Events `pane.created {kind: \"browser\"}`, `tab.layout_changed`.",
      "params": "{preview?: Target, url?: string, split?: right|down|left|up|tab|float = right, pane?: Target, machine?: string, device?: string, viewport?: string|{width: int, height: int}, fit?: bool, focus?: bool = true, focus_client?: string}",
      "result": "{opened_in: pane, pane: string, pane_handle: string, tab: string, url: string, machine: string, source_pane: string|null}"
    },
    {
      "name": "browser.pane.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "browser_pane"
      ],
      "milestone": "M3",
      "spec": "`{}` → `{panes: [{pane, handle, tab, browser}]}`",
      "params": "{}",
      "result": "{panes: [{pane: string, handle: string, tab: string, browser: BrowserPane}]}"
    },
    {
      "name": "browser.pane.status",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "browser_pane"
      ],
      "milestone": null,
      "spec": null,
      "params": "{}",
      "result": "{browsers: [{profile: string, dpr: number, pid?: int, targets: int, up_ms: int}], targets: [{pane: string, owner: string, url?: string, title?: string, profile: string, machine: string, route: string, running: bool, screencast: bool, viewers: int, frames: int, fps: number, decode_ms: number, css: [number], frame?: [int], history: any, error?: string, pin?: {device?: string, width: int, height: int}, letterbox?: {rect: [number], scale: number}, console: int, network: int, clipboard: {forwarded: int, blocked: int}}], windowed: [string], tiles_sent: int, media_bytes: int}"
    },
    {
      "name": "browser.pane.update",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "browser_pane"
      ],
      "milestone": "M3",
      "spec": "`{pane, url?, title?, history?, history_index?, device?, viewport?: \"WxH\" \\| \"fit\", fit?}` → `{pane}` — persists navigation reported by the viewing client (remote owners). Event `browser.navigated`. `device` (a `vk_browser::devices` preset: `iphone-15`, `pixel-8`, `ipad`, `desktop-1280/1440/1920`) or `viewport` (64..=8192 CSS px per edge) pins the page size (06 B3.2, letterboxed). `viewport: \"fit\"` / `fit: true` unpins. Both at once or an unknown name → `invalid_params`. Event `browser.viewport_changed {device, viewport}`. Not from a pane.",
      "params": "{pane: Target, url?: string, title?: string, history?: [string], history_index?: int, device?: string, viewport?: string|{width: int, height: int}, fit?: bool}",
      "result": "{pane: string}"
    },
    {
      "name": "browser.press",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{browser_session, selector|text|role, text?, key?, submit?}` → `{}`",
      "params": "{session?: string, browser_session?: string, target?: string, key: string}",
      "result": "{session: string, key: string}"
    },
    {
      "name": "browser.release",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{session}` → `{session, human_control}` — full scope only. Events `browser.taken_over` / `browser.released {by}`.",
      "params": "{session?: string, browser_session?: string, target?: string}",
      "result": "{session: string, human_control: bool}"
    },
    {
      "name": "browser.screencast_frame",
      "mutating": false,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "open",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{session}` → `{session, delivery: \"internal+poll\", width, height}` / `{session, detached}` / `{session, after_seq?}` → `{session, seq, mime: \"image/jpeg\", width, height, received_ms, data_b64 \\| null}` — full scope only. In-process browser panes use `AgentBrowsers::attach_screencast` (latest-wins `watch` channel) and `AgentBrowsers::human_input`.",
      "params": "{session?: string, browser_session?: string, target?: string, after_seq?: int}",
      "result": "{session: string, seq: int, mime: string, width: int|null, height: int|null, received_ms: int, data_b64: string} | {session: string, seq: int|null, data_b64: null}"
    },
    {
      "name": "browser.screenshot",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{browser_session?|preview?|url?, full_page?, selector?, viewport?, device?}` → `{blob, path_on_machine, width, height, meta: ScreenshotMeta}` — `meta.environment` and `meta.code {task, head_sha, dirty_digest}` per 06 B6. File also written to `$TMPDIR/vibeke-shots/<hash>.png`",
      "params": "{session?: string, browser_session?: string, target?: string, url?: string, preview?: string, device?: string, viewport?: string|object, dpr?: number, color_scheme?: string, dark?: bool, full_page?: bool, selector?: string, timeout_ms?: int, inline?: bool}",
      "result": "{session: string|null, id: string, handle: string, blob: string, path_on_machine: string, width: int, height: int, bytes: int, binding: bound|illustrative, label: string, meta: ScreenshotMeta, data_b64?: string, mime?: string, inline_skipped?: string, one_shot?: bool, opened_session?: string, status?: int|null, final_url?: string|null, title?: string|null}"
    },
    {
      "name": "browser.session_close",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{browser_session}` → `{}`",
      "params": "{session?: string, browser_session?: string, target?: string}",
      "result": "{session: string, closed: bool}"
    },
    {
      "name": "browser.session_open",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{preview?|url?, viewport?: {w, h, dpr}, device?, color_scheme?: light|dark}` → `{browser_session}` — headless context **on the machine where the dev server runs**, owned by the caller's pane/run",
      "params": "{url?: string, preview?: string, machine?: string, device?: string, viewport?: string | {width?: int, height?: int, w?: int, h?: int}, dpr?: number, color_scheme?: string, dark?: bool, wait?: string, timeout_ms?: int}",
      "result": "BrowserSession"
    },
    {
      "name": "browser.snapshot",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agent_browser"
      ],
      "milestone": null,
      "spec": null,
      "params": "{session?: string, browser_session?: string, target?: string, format?: a11y|accessibility|text|html = a11y, max_bytes?: int, selector?: string}",
      "result": "{session: string, url: string, format: string, content: string, truncated: bool}"
    },
    {
      "name": "browser.status",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{}` → `{browsers: [{profile, dpr, pid, targets, up_ms}], targets: [{pane, owner, url, title, profile, machine, route, running, screencast, viewers, frames, fps, decode_ms, css, frame, history, error}], windowed, tiles_sent, media_bytes}` — the media host's view.",
      "params": "{}",
      "result": "{running: true, pid: int|null, product: string, binary: string, kind: string, uptime_ms: int, sessions: int, denied: int, profile_dir: string, idle_timeout_ms: int} | {running: false, sessions: int, denied: int, binary: string|null, kind: string|null, profile_dir: string, idle_timeout_ms: int}"
    },
    {
      "name": "browser.take_over",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{session}` → `{session, human_control}` — full scope only. Events `browser.taken_over` / `browser.released {by}`.",
      "params": "{session?: string, browser_session?: string, target?: string}",
      "result": "{session: string, human_control: bool}"
    },
    {
      "name": "browser.type",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{browser_session, selector|text|role, text?, key?, submit?}` → `{}`",
      "params": "{session?: string, browser_session?: string, target?: string, text: string, selector?: string, clear?: bool, submit?: bool, timeout_ms?: int}",
      "result": "{session: string, typed: int}"
    },
    {
      "name": "browser.wait",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agent_browser"
      ],
      "milestone": "M3",
      "spec": "`{browser_session, for: load|networkidle|{selector}|{ms}}` → `{}`",
      "params": "{session?: string, browser_session?: string, target?: string, for?: string = load, timeout_ms?: int = 15000}",
      "result": "{session: string, waited: string}"
    },
    {
      "name": "browser.watch",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "browser_pane"
      ],
      "milestone": "M3",
      "spec": "`{session \\| agent_pane, pane?, split?: right\\|down\\|left\\|up\\|tab, focus?: true, focus_client?}` → `{opened_in: \"watch\", session, read_only: true, pane, pane_handle, tab, url, machine, source_pane}` — full scope only (`permission_denied` from a pane). `agent_pane` picks that pane's newest open session (`not_found` \"… has no open browser session\"). Creates a browser pane with `watch = <session>` in this server's layout next to `pane` (default: the session's owner pane). The pane is read-only until `BrowserCmd::TakeOver(true)` (render stream), which sets human control held by `pane:<id>` (events `browser.taken_over {by, via: \"watch_pane\"}`). `TakeOver(false)` or closing the pane releases it (`browser.released`). CLI: `vibeke browser watch <session> [--pane p] [--split …] [--machine m]`.",
      "params": "{session?: string, agent_pane?: Target, pane?: Target, split?: right|down|left|up|tab|float = right, focus?: bool = true, focus_client?: string}",
      "result": "{opened_in: string, session: string, read_only: bool, pane: string, pane_handle: string, tab: string, url: string, machine: string, source_pane: string|null}"
    },
    {
      "name": "client.appearance",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "parity",
        "theme"
      ],
      "milestone": "M1",
      "spec": "`{dark: bool, source?: osc11\\|csi996}` → `{appearance, colorfgbg}` — host terminal light/dark report (theme propagation, 08 §11) [M4]",
      "params": "{dark: bool, source?: osc11|csi996|string}",
      "result": "{appearance: Appearance, colorfgbg: string}"
    },
    {
      "name": "client.focus",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "parity",
        "notify"
      ],
      "milestone": "M1",
      "spec": "`{pane \\| url: \"vibeke://focus?session=…&pane=…\", raise?: true}` → `{pane, client, focused, raised, host}` — focus in the most recently active attached client and raise its host terminal (08 §7.1 click-to-focus). Full scope only [M4]",
      "params": "{pane?: Target, url?: string, raise?: bool = true}",
      "result": "{pane: string, client: string, focused: bool, raised: bool, host: any}"
    },
    {
      "name": "client.hello",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{client, version, api, kind: tui|cli|plugin|gateway|agent, token?}` → `{server_version, api, session, machine, capabilities[], features[]}`",
      "params": "{client: string, version: string, api: string, kind: tui|cli|plugin|gateway|agent|string, token?: string, host?: {bundle_id?: string, term_program?: string}}",
      "result": "{server_version: string, api: string, session: string, machine: string, capabilities: [string], features: [string], client_id?: string}"
    },
    {
      "name": "client.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{}` → `{clients: [{id, kind, client, version, attached_at, peer: {uid, pid?, machine?}, focused_pane?}]}`",
      "params": "{}",
      "result": "{clients: [{id: string, kind: string, client?: string, version?: string, attached_at: int, peer?: {uid: int, pid?: int, machine?: string}, focused_pane: string|null}]}"
    },
    {
      "name": "compat.herdr.call",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "compat"
      ],
      "milestone": null,
      "spec": null,
      "params": "{method: string, params?: object, as_plugin?: {session: string, ticket: string}}",
      "result": "{result: any} | {error: {code: string, message: string}}"
    },
    {
      "name": "compat.invocation.verify",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "compat"
      ],
      "milestone": null,
      "spec": null,
      "params": "{ticket: string}",
      "result": "{plugin_id: string, digest: string, grant_id: string, log_id: string, session: string, sandboxed: bool}"
    },
    {
      "name": "compat.status",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "compat"
      ],
      "milestone": null,
      "spec": null,
      "params": "{}",
      "result": "{baseline: {herdr: string, commit: string}, support: string, listener: {enabled: bool, path: string, live: bool}, inventory: {implemented: int, partial: int, missing: int}, brokers: int, herdr_root: string, registry: string}"
    },
    {
      "name": "compat.ui.state",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "compat"
      ],
      "milestone": null,
      "spec": null,
      "params": "{}",
      "result": "{window_title?: string, popup?: {pane: string, plugin_id: string, entrypoint_id: string}, agent_views: [{plugin_id: string, run: string, text: string, detail?: string, tone?: string, updated_ms: int}]}"
    },
    {
      "name": "config.get",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "config_api"
      ],
      "milestone": "M1",
      "spec": "`{key?}` → `{value, source: default|user|repo|cli}`",
      "params": "{key?: string}",
      "result": "{key?: string, value: any, source: default|user|runtime, path: string, overrides: [string], errors: [ConfigDiagnostic]}"
    },
    {
      "name": "config.reload",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "config_api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{}",
      "result": "{changed: [string], errors: [ConfigDiagnostic], warnings?: [ConfigWarning]}"
    },
    {
      "name": "config.set",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "config_api"
      ],
      "milestone": "M1",
      "spec": "`{key, value, persist?: false}` → `{}` — runtime override",
      "params": "{key: string, value: any, persist?: bool = false}",
      "result": "{key: string, value: any, persisted: bool, path: string, changed: [string]}"
    },
    {
      "name": "config.validate",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "config_api"
      ],
      "milestone": "M1",
      "spec": "`{path?}` → `{errors: [{line, col, message}]}`",
      "params": "{path?: string}",
      "result": "{path: string, valid: bool, errors: [ConfigDiagnostic], warnings: [ConfigWarning]}"
    },
    {
      "name": "desk.context",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "desk"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{session, turns?: [n]\\|\"3-5,7\", path?, objective?}` → `{package: {objective, decisions, remaining_work, selected_turns: [{turn, user, assistant, tool_calls}], repository: {repo, cwd, revision: {revision, branch, uncommitted_files}}}, text}` — The result is deterministic and does not use a model. The first prompt is the default objective. The user can edit labeled extracts for decisions and remaining work. The default selection is the last three turns.",
      "params": "{session: string, turns?: [int] | string, path?: string, objective?: string}",
      "result": "{package: object, text: string}"
    },
    {
      "name": "desk.forget",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "desk"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{session}\\|{repo}\\|{workspace}\\|{before}` → `{rows_deleted, sessions_forgotten}` — deletes index rows. Sessions are tombstoned so the indexer never re-adds them. `before` deletes older rows. Event `desk.forgotten {scope} {rows, sessions}` (no text)",
      "params": "{session?: string, repo?: string, workspace?: Target, before?: string|int}",
      "result": "{rows_deleted: int, sessions_forgotten: int}"
    },
    {
      "name": "desk.index",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "desk"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{budget?}` → `{pass: {registered, bytes, rows, purged, reset, pending, errors}}`",
      "params": "{budget?: int}",
      "result": "{pass: {registered: int, bytes: int, rows: int, purged: int, reset: int, pending: int, errors: any}}"
    },
    {
      "name": "desk.open",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "desk"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{session, turn?, path?, focus?: false}` → `{status, action: focus_live_pane\\|resume_native_session\\|start_new_agent_with_context, turn_items, focused, actions: [{id: focus, label: \"Focus live pane\"}, {id: resume_native, label: \"Resume native session\", command}, {id: new_agent, label: \"Start new agent with context\"}]}`. Focuses the live run's pane **only** with `focus: true` (an explicit user action). Never resumes",
      "params": "{session: string, turn?: int, path?: string, focus?: bool = false}",
      "result": "{status: string, action: string, turn_items?: any, focused?: bool, actions?: [object]}"
    },
    {
      "name": "desk.resume",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "desk"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{session, mode?: native, pane?, workspace?}` → **Resume native session**: `conflict:session_live` while it runs (focus it instead). `unsupported` without a resume handle. Otherwise, the method types the resume command into the given pane or a new tab in the session's workspace. The new tab uses the session's working directory. A pane with an agent returns `conflict:pane_busy`. A stored run without `pane` uses `agent.resume` behavior. The result is `{mode, label, command, run}`. `{session, mode: new_agent, workspace?, start?: false, harness?, pane?, turns?, objective?}` → **Start new agent with context**: builds the `desk.context` package and saves it as a workspace draft. With `start` also starts the harness (no prompt) in a free pane → `{draft, package, sent: false, run?, pane?}`. Nothing is ever sent: the user edits and sends the draft (`draft.send`)",
      "params": "{session: string, mode?: native, pane?: Target, workspace?: Target}",
      "result": "object"
    },
    {
      "name": "desk.search",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "desk"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{text, repo?, harness?, since?, until?, session?, limit?: 20, sort?: relevance\\|recent, fresh?: true}` → `{hits: [{session, path, harness, machine, repo, cwd, turn, role, kind, ts, offset, snippet, status: live\\|resumable\\|none, live: {run, pane}, resume: {argv, command, run}}], index: {sources, rows, forgotten_sessions}}`. `repo` is a directory (matched as main repository root or cwd prefix). `since`/`until` take epoch ms, `7d`/`12h`/`30m` or `YYYY-MM-DD`. **live** = a current run is in that native session. **resumable** = a resume argv is known (a stored run's, else the harness's own)",
      "params": "{text: string, repo?: string, harness?: string, since?: string|int, until?: string|int, session?: string, limit?: int = 20, sort?: relevance|recent, fresh?: bool = true}",
      "result": "{hits: [object], index: object}"
    },
    {
      "name": "desk.sessions",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "desk"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{repo?, harness?, limit?: 50}` → `{sessions: [{session, harness, machine, repo, cwd, workspace, run, first_ts, last_ts, turns, rows, paths, status, live, resume}]}`, most recent first",
      "params": "{repo?: string, harness?: string, limit?: int = 50}",
      "result": "{sessions: [{session: string, harness: string, machine?: string, repo?: string|null, cwd?: string|null, workspace?: string|null, run?: string|null, first_ts?: int, last_ts?: int, turns?: int, rows?: int, paths?: any, status?: string, live?: any, resume?: any}]}"
    },
    {
      "name": "desk.status",
      "mutating": false,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "open",
      "tables": [
        "desk"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{}` → `{db, selection: {runs, roots}, exclude, retention_days, counts, sources: [{path, harness, session, origin: run\\|root, repo, rows, offset, size, pending_bytes, excluded}], last_pass}` — makes source selection, exclusions and retention visible",
      "params": "{}",
      "result": "{db: string, selection: object, exclude: any, retention_days: int, counts: object, sources: [object], last_pass: any}"
    },
    {
      "name": "draft.check",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "drafts"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{target_run, draft?}` → `{run, pane, harness, native_conversation_id, send_path: prompt_input\\|open_pane_only, unsafe?, follow_up: prompt_input, steer: false, hidden_attachments}`",
      "params": "{target_run: Target, draft?: Target}",
      "result": "{run: string, pane: string, harness: string, native_conversation_id: string|null, send_path: prompt_input|open_pane_only, unsafe?: any, follow_up?: string, steer?: bool, hidden_attachments?: any}"
    },
    {
      "name": "draft.combine",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "drafts"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{ids: [two or more of one scope], title?, separator?: \"\\n\\n\", delete_sources?: false}` → new `{draft}` with joined text, de-duplicated attachments and `combined_from`",
      "params": "{ids: [string], title?: string, separator?: string, delete_sources?: bool = false}",
      "result": "{draft: object}"
    },
    {
      "name": "draft.create",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "drafts"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{scope?: workspace\\|task, id?, text, title?, attachments?: [{kind: file\\|screenshot, path\\|blob\\|data_b64, name?, label?}], idempotency_key?}` → `{draft}`. `id` defaults to the caller's workspace. `path` must be an existing absolute path on this server's machine. `blob` is a `blob.put` hash. `data_b64` is stored now in the pane inbox (06 A11.4) — remote clients use `blob`/`data_b64`",
      "params": "{scope?: workspace|task, id?: string, text: string, title?: string, attachments?: [{kind: file|screenshot, path?: string, blob?: string, data_b64?: string, name?: string, label?: string}], idempotency_key?: string}",
      "result": "{draft: object}"
    },
    {
      "name": "draft.delete",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "drafts"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{draft}` → `{deleted}`",
      "params": "{draft: Target}",
      "result": "{deleted: any}"
    },
    {
      "name": "draft.get",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "drafts"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{draft}` → `{draft}`. `{scope?, id?, all?}` → `{drafts}` in user order (archived drafts are not listed). A send left `sending` by a server restart is reported and persisted as `delivery_unknown`",
      "params": "{draft: Target}",
      "result": "{draft: object}"
    },
    {
      "name": "draft.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "drafts"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{draft}` → `{draft}`. `{scope?, id?, all?}` → `{drafts}` in user order (archived drafts are not listed). A send left `sending` by a server restart is reported and persisted as `delivery_unknown`",
      "params": "{scope?: workspace|task, id?: string, all?: bool}",
      "result": "{drafts: [object]}"
    },
    {
      "name": "draft.reconcile",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "drafts"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{draft}` → `{send, receipt: {known, …}, may_retry, note}` — a late matching turn upgrades the attempt to `delivered`. A still-uncertain attempt is marked reconciled, which is what allows a warned retry",
      "params": "{draft: Target}",
      "result": "{send: object, receipt: object, may_retry: bool, note: string}"
    },
    {
      "name": "draft.reorder",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "drafts"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{order: [draft ids]}` → listed drafts first in that order, the rest after",
      "params": "{order: [string]}",
      "result": "{drafts?: [object]}"
    },
    {
      "name": "draft.send",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "drafts"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{draft, target_run, idempotency_key, include_notes?: false, keep?: false, retry_despite_unknown?}` → `{draft, send, send_path}`. Uses task messages' guarded prompt-input path (15 §9) without a tracked task: the run and its native conversation are fixed when the send starts. The run must be idle with a known native conversation and no open interaction. No attached TUI can focus the pane. The input box must be verifiably empty. Each attachment must be visible to the pane (`sandbox::can_see`). Otherwise `conflict:send_unsafe {fallback: open_pane_to_send, draft_kept: true}` with **zero bytes written** and no attempt recorded. Delivery holds the pane input lock while it repeats the checks and submits the text. The result is `delivered` only after a matching turn starts at or after the baseline in the same conversation. Otherwise `delivery_unknown` (or `failed`). The sent text is the draft, then `Attached files:` with one path per attachment, then `Notes:` only with `include_notes`. A delivered draft is archived unless `keep`. Receipts are owner-aware (`review::receipts`). The same key replays the current outcome. After `delivery_unknown`: `conflict:reconcile_first` until `draft.reconcile`, then `retry_despite_unknown`",
      "params": "{draft: Target, target_run: Target, idempotency_key: string, include_notes?: bool = false, keep?: bool = false, retry_despite_unknown?: bool}",
      "result": "{draft: object, send: object, send_path: string}"
    },
    {
      "name": "draft.update",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "drafts"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{draft, text?, title?, attachments?, add_attachment?, remove_attachment?: index, expected_rev?}` → `{draft}` (`conflict:draft_changed`, `conflict:send_in_progress`)",
      "params": "{draft: Target, text?: string, title?: string, attachments?: [any], add_attachment?: object, remove_attachment?: int, expected_rev?: int}",
      "result": "{draft: object}"
    },
    {
      "name": "events.read",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{after?: Cursor, before?: Cursor, types?, subjects?, limit?: 500}` → `{events, next: Cursor}` — paginated history (within retention)",
      "params": "{after?: Cursor|int, before?: Cursor|int, types?: [string] | string, subjects?: object, limit?: int = 500}",
      "result": "{events: [Event], next: Cursor}"
    },
    {
      "name": "events.subscribe",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{after?: Cursor, types?: [glob], subjects?: {workspace?, tab?, pane?, run?, task?}, include_snapshot?: false, machine?: label|\"*\"}` → `{subscription_id, at: Cursor}` then notifications",
      "params": "{after?: Cursor|int, types?: [string] | string, subjects?: {workspace?: Target, tab?: Target, pane?: Target, run?: Target, task?: Target}, include_snapshot?: bool = false, machine?: string}",
      "result": "{subscription_id: string, at: Cursor}"
    },
    {
      "name": "events.unsubscribe",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{subscription_id}` → `{unsubscribed: bool}` — *as built:* ends a subscription of the same connection (its server task is aborted; pushes already queued may still arrive and clients drop them); idempotent, `false` for an unknown or already finished id; pane scope `open`. Only on a control connection (like `events.subscribe`); a connection's subscriptions end when it closes.",
      "params": "{subscription_id: string}",
      "result": "{unsubscribed: bool}"
    },
    {
      "name": "events.wait",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{types, subjects?, after?: Cursor, timeout_ms?}` → `{event}` — one-shot wait (CLI-friendly)",
      "params": "{types?: [string] | string, subjects?: object, after?: Cursor|int, timeout_ms?: int = 60000}",
      "result": "{event: Event}"
    },
    {
      "name": "fs.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "16 G2",
      "spec": "`{pane, path?: \"\"}` → `{path, entries: [{name, kind: file|dir|symlink|other, size? (files), ignored, secret}], truncated}` — one level of the directory `path` relative to the repository root of the pane's cwd. Directories first, then by name. ≤ 2000 entries. Symlinks are listed, never followed. `.git` is not listed. Secret-looking entries are listed with `secret: true` and no size, and a secret directory lists as `{secret: true, entries: []}`",
      "params": "{pane?: Target, path?: string = ''}",
      "result": "{path: string, entries: [{name: string, kind: file|dir|symlink|other, size?: int, ignored: bool, secret: bool}], truncated: bool}"
    },
    {
      "name": "fs.read",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "16 G2",
      "spec": "`{pane, path}` → `{path, text?, binary, truncated, size, secret}` — at most 512 KiB of a regular file (`truncated` when larger, cut on a character boundary). `binary` (NUL in the first 8 KiB) returns no text. Secret-looking files return `{secret: true}` without content",
      "params": "{pane?: Target, path: string}",
      "result": "{path: string, text?: string, binary: bool, truncated: bool, size: int, secret: bool}"
    },
    {
      "name": "git.diff",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "16 G2",
      "spec": "`{pane|path, file, staged?}` → `{file, diff, truncated, binary, untracked, secret?}`. `file` must be a relative path listed by `git.status`. Diff against `HEAD` (or the index with `staged`), capped at 512 KiB",
      "params": "{pane?: Target, path?: string, file: string, staged?: bool}",
      "result": "{file: string, diff: string, truncated: bool, binary: bool, untracked: bool, secret?: bool}"
    },
    {
      "name": "git.log",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "16 G2",
      "spec": "`{pane|path, base?, limit?: 50 (≤ 200)}` → `{commits: [{sha, short, author, ts (epoch ms), subject}], truncated}`, newest first. With `base`, only commits in `base..HEAD`",
      "params": "{pane?: Target, path?: string, base?: string, limit?: int = 50}",
      "result": "{commits: [{sha: string, short: string, author: string, ts: int, subject: string}], truncated: bool}"
    },
    {
      "name": "git.status",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "16 G2",
      "spec": "`{pane}` (pane scope: own pane only) or `{path}` (full scope) → `{repo_root, branch?, upstream?, ahead, behind, clean, truncated, files: [{path, orig_path?, x, y, kind: modified|added|deleted|renamed|untracked|conflicted, staged, adds?, dels?, binary, secret}]}`. `not_found:not_a_repo` outside a repository",
      "params": "{pane?: Target, path?: string}",
      "result": "{repo_root: string, branch?: string|null, upstream?: string|null, ahead: int, behind: int, clean: bool, truncated: bool, files: [{path: string, orig_path?: string|null, x: string, y: string, kind: string, staged: bool, adds?: int|null, dels?: int|null, binary: bool, secret: bool}]}"
    },
    {
      "name": "group.add",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "parity"
      ],
      "milestone": "M1",
      "spec": "`{}` → `{groups: [Group + {agent_summary}], ungrouped}`. `{group, workspace, index?}` / `{workspace}` → `{workspace, group}`",
      "params": "{group: Target, workspace?: Target, index?: int}",
      "result": "{workspace: Workspace, group: string|null}"
    },
    {
      "name": "group.collapse",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "parity"
      ],
      "milestone": "M1",
      "spec": "`{group, …}` → `{group}`",
      "params": "{group: Target, collapsed?: bool}",
      "result": "{group: Group}"
    },
    {
      "name": "group.create",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "parity"
      ],
      "milestone": "M1",
      "spec": "`{name, parent?}` → `{group}`",
      "params": "{name: string, parent?: Target}",
      "result": "{group: Group}"
    },
    {
      "name": "group.delete",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "parity"
      ],
      "milestone": "M1",
      "spec": "`{group, …}` → `{group}`",
      "params": "{group: Target}",
      "result": "{}"
    },
    {
      "name": "group.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "parity"
      ],
      "milestone": "M1",
      "spec": "`{}` → `{groups: [Group + {agent_summary}], ungrouped}`. `{group, workspace, index?}` / `{workspace}` → `{workspace, group}`",
      "params": "{}",
      "result": "{groups: [Group], ungrouped: [string]}"
    },
    {
      "name": "group.move",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "parity"
      ],
      "milestone": "M1",
      "spec": "`{group, …}` → `{group}`",
      "params": "{group: Target, parent?: Target|null, index?: int, delta?: int}",
      "result": "{group: Group}"
    },
    {
      "name": "group.remove",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "parity"
      ],
      "milestone": "M1",
      "spec": "`{}` → `{groups: [Group + {agent_summary}], ungrouped}`. `{group, workspace, index?}` / `{workspace}` → `{workspace, group}`",
      "params": "{workspace?: Target, index?: int}",
      "result": "{workspace: Workspace, group: string|null}"
    },
    {
      "name": "group.rename",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "parity"
      ],
      "milestone": "M1",
      "spec": "`{group, …}` → `{group}`",
      "params": "{group: Target, name: string}",
      "result": "{group: Group}"
    },
    {
      "name": "image.upload",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M3",
      "spec": "`{pane, mime, data_b64 | path_on_client}` → `{path_on_machine, blob}` — client→remote image transfer (paste/drag)",
      "params": "{pane: Target, mime: string, data_b64?: string, path_on_client?: string}",
      "result": "{path_on_machine: string, blob?: string}"
    },
    {
      "name": "interaction.answer",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{interaction, decision?: allow|allow_always|deny, choices?: {qid: [oid]}, text?, scope?: once|session|rule, rule?: PolicyRule, idempotency_key?, actor?, expected_decision_rev?}` → `{interaction, delivery: {state, channel: native|keystrokes}}` — `state` per the delivery state machine in 02/04. Repeating the same `idempotency_key` with the same answer returns the recorded state (`duplicate: true`) and never delivers again. A different answer under that key is a `conflict`. `actor` (full-scope callers only) labels `answered_by`, e.g. `gateway:Espen's phone` (16 §7.7). The key is kept separately as `answer_key`. `expected_decision_rev` makes the answer a compare-and-set: if the interaction moved on, the call fails with `conflict` (`stale: …`). The server returns `permission_denied:self_answer_forbidden` for tokens from the run's own pane or any descendant pane or run. This call grants authorization (09 §5.1.1).",
      "params": "{interaction: Target, decision?: allow|allow_always|deny, choices?: {*: [string]}, text?: string, scope?: once|session|rule, rule?: PolicyRule, idempotency_key?: string, actor?: string, expected_decision_rev?: int}",
      "result": "{interaction: Interaction, delivery: {state: string, channel?: native|keystrokes|none|string}, duplicate?: bool}"
    },
    {
      "name": "interaction.cancel",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{interaction}` → `{interaction}` (user dismisses. Adapter delivers deny/escape)",
      "params": "{interaction: Target}",
      "result": "{interaction: Interaction}"
    },
    {
      "name": "interaction.get",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{interaction}` → `{interaction}`",
      "params": "{interaction: Target}",
      "result": "{interaction: Interaction}"
    },
    {
      "name": "interaction.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "agents"
      ],
      "milestone": "M1",
      "spec": "`{status?: open, run?, workspace?, kind?}` → `{interactions}` — sorted by `opened_at` in Phase 1. Phase 2 adds ranking",
      "params": "{status?: open|string, run?: Target, workspace?: Target, kind?: string}",
      "result": "{interactions: [Interaction]}"
    },
    {
      "name": "layout.apply",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "parity",
        "layouts"
      ],
      "milestone": "M1",
      "spec": "`{layout, workspace?, new_workspace?: {cwd, name}}` → `{workspace, tabs, panes}`",
      "params": "{layout: LayoutSpec | string, workspace?: Target, new_workspace?: {cwd: string, name?: string}}",
      "result": "{workspace: Workspace, tabs: [Tab], panes: [Pane]}"
    },
    {
      "name": "layout.export",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api",
        "layouts"
      ],
      "milestone": "M1",
      "spec": "`{tab|workspace}` → `{layout: LayoutSpec}` (TOML/JSON-serializable, includes commands and cwds)",
      "params": "{tab?: Target, workspace?: Target}",
      "result": "{layout: LayoutSpec}"
    },
    {
      "name": "layout.get",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "parity",
        "layouts"
      ],
      "milestone": "M1",
      "spec": "`{}` → `{layouts: [{name, description, cwd, tabs, panes, valid}]}`. `{name}` → `{layout}` — named layouts from `[layouts.<name>]` [M4]",
      "params": "{name?: string}",
      "result": "{layouts: [{name: string, description?: string|null, cwd?: string|null, tabs: int, panes: int, valid: bool}]} | {layout: LayoutSpec}"
    },
    {
      "name": "layout.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "parity",
        "layouts"
      ],
      "milestone": "M1",
      "spec": "`{}` → `{layouts: [{name, description, cwd, tabs, panes, valid}]}`. `{name}` → `{layout}` — named layouts from `[layouts.<name>]` [M4]",
      "params": "{name?: string}",
      "result": "{layouts: [{name: string, description?: string|null, cwd?: string|null, tabs: int, panes: int, valid: bool}]} | {layout: LayoutSpec}"
    },
    {
      "name": "notes.get",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "drafts"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{workspace?}` → `{notes: {workspace, text, rev}}`. `{workspace?, text, expected_rev?}` → `{notes}`",
      "params": "{workspace?: Target}",
      "result": "{notes: {workspace: string, text: string, rev: int}}"
    },
    {
      "name": "notes.set",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "drafts"
      ],
      "milestone": "research R2/R3; server + CLI built; TUI built, 08 §6.7",
      "spec": "`{workspace?}` → `{notes: {workspace, text, rev}}`. `{workspace?, text, expected_rev?}` → `{notes}`",
      "params": "{workspace?: Target, text: string, expected_rev?: int}",
      "result": "{notes: {workspace: string, text: string, rev: int}}"
    },
    {
      "name": "notification.config",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "parity",
        "notify"
      ],
      "milestone": "M1",
      "spec": "`{}` → `{channels: [os, terminal_bell, osc9, sound, plugin:<id>], rules}` — *M4:* `{channels: [toast, native, osc, …], native: {backend, unavailable_reason}, rules: {on, suppress_when_focused, coalesce_ms, quiet_hours}, hosts}`",
      "params": "{}",
      "result": "{channels: [string], rules: any, native?: object, hosts?: any}"
    },
    {
      "name": "notification.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{unread_only?: true, limit?}` → `{notifications}`",
      "params": "{unread_only?: bool = true, limit?: int}",
      "result": "{notifications: [Notification]}"
    },
    {
      "name": "notification.read",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{notification|all: true}` → `{}`",
      "params": "{notification?: Target, all?: bool}",
      "result": "{}"
    },
    {
      "name": "notification.send",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{title, body?, urgency?: normal, subject?: pane|run|task, sound?: bool}` → `{notification}` — for scripts/plugins",
      "params": "{title: string, body?: string, urgency?: string = normal, subject?: string, sound?: bool}",
      "result": "{notification: Notification}"
    },
    {
      "name": "pane.can_see_paths",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{pane?: Target, paths?: [string]}",
      "result": "{visible: [bool]}"
    },
    {
      "name": "pane.close",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane, force?}` → `{}`",
      "params": "{pane?: Target, force?: bool}",
      "result": "{}"
    },
    {
      "name": "pane.current",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{}` → `{pane}` (requires pane token / `@current`)",
      "params": "{}",
      "result": "{pane: Pane}"
    },
    {
      "name": "pane.embed",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "parity"
      ],
      "milestone": "M1",
      "spec": "`{pane, target?, direction?: right, ratio?}` → `{pane, tab}` — a floating pane back into the tiling, split next to `target` (default the focused tiled pane) [M4]",
      "params": "{pane: Target, target?: Target, direction?: right|down|left|up = right, ratio?: number}",
      "result": "{pane: Pane, tab: Tab}"
    },
    {
      "name": "pane.equalize",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{tab?: Target}",
      "result": "{layout: LayoutSpec}"
    },
    {
      "name": "pane.float",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "parity"
      ],
      "milestone": "M1",
      "spec": "`{tab, rect?: {x%,y%,w%,h%}, cwd?, command?, focus?}` → `{pane}` [M4] — *implemented:* without `pane`, a new floating pane (default 70%×70% centered). With `pane`, floats a tiled pane (`conflict` for a tab's last tiled pane) or moves/resizes/raises a floating one. Floats live in `Tab.floating: [{pane, x, y, w, h, z}]` (percent), not in `layout`",
      "params": "{pane?: Target, tab?: Target, rect?: {x?: number, y?: number, w?: number, h?: number}, cwd?: string, command?: [string], focus?: bool}",
      "result": "{pane: Pane}"
    },
    {
      "name": "pane.focus",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane, client?}` → `{pane}`",
      "params": "{pane: Target, client?: string}",
      "result": "{pane: Pane}"
    },
    {
      "name": "pane.get",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane}` → `{pane, run?, open_interactions[]}`",
      "params": "{pane?: Target}",
      "result": "{pane: Pane, run?: AgentRun|null, open_interactions?: [Interaction], live?: PaneLive|null}"
    },
    {
      "name": "pane.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{workspace?, tab?, has_agent?}` → `{panes}`",
      "params": "{workspace?: Target, tab?: Target, has_agent?: bool}",
      "result": "{panes: [Pane]}"
    },
    {
      "name": "pane.mark_seen",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane}` → `{pane}`",
      "params": "{pane?: Target}",
      "result": "{pane: Pane}"
    },
    {
      "name": "pane.mark_unread",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane}` → `{pane}`",
      "params": "{pane?: Target}",
      "result": "{pane: Pane}"
    },
    {
      "name": "pane.move",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "pane_api"
      ],
      "milestone": "M1",
      "spec": "`{pane, to: {tab} | {workspace} | {new_tab_in: workspace}, position?}` → `{pane, previous_pane_handle}`",
      "params": "{pane?: Target, to: {tab?: Target, workspace?: Target, new_tab_in?: Target}, direction?: right|down|left|up = right, anchor?: Target, position?: {pane?: Target, direction?: string}, focus?: bool = false}",
      "result": "{pane: Pane, tab: Tab, previous_pane_handle: string, source_tab_closed: bool}"
    },
    {
      "name": "pane.pin",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane, pinned: bool}` → `{pane}`",
      "params": "{pane?: Target, pinned: bool}",
      "result": "{pane: Pane}"
    },
    {
      "name": "pane.read",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane, source: visible|recent|recent_unwrapped|scrollback|detection, lines?: 200, from_line?, format?: text|ansi|cells, include_cursor?}` → `{text|cells, rows, revision, truncated, scroll}`",
      "params": "{pane?: Target, source?: visible|recent|recent_unwrapped|scrollback|detection|last-command = visible, lines?: int = 200, from_line?: int, format?: text|ansi|cells = text, include_cursor?: bool}",
      "result": "{text?: string, cells?: any, rows?: int, revision?: int, truncated?: bool, scroll?: any, cursor?: any, running?: bool, exit_code?: int|null, prompt_line?: int}"
    },
    {
      "name": "pane.rename",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane, title: string|null}` → `{pane}` (emits `pane.title_changed`)",
      "params": "{pane?: Target, title: string|null}",
      "result": "{pane: Pane}"
    },
    {
      "name": "pane.report_agent",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": null,
      "spec": null,
      "params": "{pane?: Target, pane_id?: Target, source?: string = herdr, seq?: int, agent?: string, harness?: string, state: idle|working|blocked|done|string, message?: string, resume_argv?: [string]}",
      "result": "{type: 'ok', dropped?: 'stale_seq', applied?: bool}"
    },
    {
      "name": "pane.report_agent_session",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "agents"
      ],
      "milestone": null,
      "spec": null,
      "params": "{pane?: Target, pane_id?: Target, source?: string = herdr, seq?: int, agent?: string, harness?: string, agent_session_id?: string, agent_session_path?: string, session_start_source?: string}",
      "result": "{type: 'ok', dropped?: 'stale_seq'}"
    },
    {
      "name": "pane.resize",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane, direction, cells?|percent?}` → `{layout}`",
      "params": "{pane?: Target, direction: right|down|left|up, cells?: int, percent?: number}",
      "result": "{layout: any}"
    },
    {
      "name": "pane.run",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane, command: string, wait?: bool, timeout_ms?}` → `{}` or (with wait) `{exit_code?, output_tail}` — sends text + Enter. With `wait`, uses OSC 133 prompt marks when the shell integration is active, else falls back to \"foreground process returns to shell\"",
      "params": "{pane?: Target, command: string, wait?: bool, timeout_ms?: int}",
      "result": "{exit_code?: int|null, output_tail?: string}"
    },
    {
      "name": "pane.screenshot",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "open",
      "tables": [
        "pane_api"
      ],
      "milestone": "M1",
      "spec": "`{pane, format?: png|svg|html}` → `{blob}` — renders the pane grid (for bug reports and Phase 2) [M3]",
      "params": "{pane?: Target, format?: text|ansi|html|png|svg = ansi, source?: visible|recent = visible, lines?: int = 200, include_cursor?: bool, inline?: bool}",
      "result": "{blob: {hash: string, size: int, mime: string, path: string}, format: string, source: string, cols: int, rows: int, lines: int, revision: int, cursor?: {row: int, col: int, visible: bool}, data?: string}"
    },
    {
      "name": "pane.scroll",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "pane_api"
      ],
      "milestone": "M1",
      "spec": "`{pane, to: bottom|top|line, line?, delta?}` → `{scroll}`",
      "params": "{pane?: Target, to?: bottom|top|line, line?: int, delta?: int, client?: string}",
      "result": "{scroll: {offset: int, total: int, at_bottom: bool}}"
    },
    {
      "name": "pane.send_bytes",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{pane?: Target, data_b64: string}",
      "result": "{}"
    },
    {
      "name": "pane.send_keys",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane, keys: [string]}` → `{}` — key grammar §2.6.1. All keys validated before any byte is written",
      "params": "{pane?: Target, keys: [string]}",
      "result": "{}"
    },
    {
      "name": "pane.send_text",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane, text, paste?: auto|bracketed|raw = auto}` → `{bytes}` — `auto` honors the pane's live bracketed-paste mode *(notify ok)*",
      "params": "{pane?: Target, text: string, paste?: auto|bracketed|raw = auto}",
      "result": "{bytes: int}"
    },
    {
      "name": "pane.split",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane, direction: right|down|left|up, ratio?: 0.5, cwd?, command?: argv, env?: {k:v}, focus?: false, title?}` → `{pane}`",
      "params": "{pane?: Target, direction?: right|down|left|up = right, ratio?: number = 0.5, cwd?: string, command?: [string], env?: {*: string}, focus?: bool = false, title?: string}",
      "result": "{pane: Pane}"
    },
    {
      "name": "pane.wait_idle",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane, quiet_ms: 2000, timeout_ms?}` → `{revision}`",
      "params": "{pane?: Target, quiet_ms?: int = 2000, timeout_ms?: int}",
      "result": "{revision: int}"
    },
    {
      "name": "pane.wait_output",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane, match?: string, regex?: string, source?, timeout_ms?, since_revision?}` → `{matched: string, line, revision}`",
      "params": "{pane?: Target, match?: string, regex?: string, source?: string, timeout_ms?: int, since_revision?: int}",
      "result": "{matched: string, line: any, revision: int}"
    },
    {
      "name": "pane.zoom",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "own_target",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{pane, zoomed?: toggle}` → `{tab}`",
      "params": "{pane?: Target, zoomed?: bool}",
      "result": "{tab: Tab}"
    },
    {
      "name": "paste.translated",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{pane?: Target, files: [{blob: string, bytes?: int, local_name?: string, dir?: bool}], target_namespace?: string}",
      "result": "{recorded: int}"
    },
    {
      "name": "plugin.action.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "compat"
      ],
      "milestone": null,
      "spec": null,
      "params": "{plugin?: string}",
      "result": "{actions: [{plugin_id: string, action_id: string, qualified_id: string, title: string, description?: string, contexts: any, available: bool, status: string}], keybindings: [{plugin_id: string, key: string, action: string, description?: string, installed: bool, reason?: string, conflicts_with?: any}]}"
    },
    {
      "name": "plugin.action.run",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "compat"
      ],
      "milestone": null,
      "spec": null,
      "params": "{plugin: string, action: string, source?: palette|keybinding, context?: {pane_id?: Target, pane?: Target, tab_id?: Target, tab?: Target, workspace_id?: Target, workspace?: Target}, pane_id?: Target, tab_id?: Target, workspace_id?: Target} | {action: string, source?: palette|keybinding, context?: object}",
      "result": "{log: {log_id: string, plugin_id: string, action_id?: string, event?: string, entrypoint_id?: string, source: string, command: any, long_lived: bool, isolation: sandbox|host, status: string, started_unix_ms: int, finished_unix_ms?: int, started_at: int, finished_at?: int, exit_code?: int, stdout: string, stderr: string, context: object}}"
    },
    {
      "name": "plugin.link.open",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "compat"
      ],
      "milestone": null,
      "spec": null,
      "params": "{plugin: string, handler: string, url: string, context?: {pane_id?: Target, tab_id?: Target, workspace_id?: Target}, pane_id?: Target, tab_id?: Target, workspace_id?: Target}",
      "result": "{log: object}"
    },
    {
      "name": "plugin.link_handler.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "compat"
      ],
      "milestone": null,
      "spec": null,
      "params": "{}",
      "result": "{handlers: [{plugin_id: string, handler_id: string, title?: string, pattern: string, action_id?: string, available: bool, status: string}]}"
    },
    {
      "name": "plugin.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "compat"
      ],
      "milestone": "M5",
      "spec": "`{}` → `{plugins: [{id, version, enabled, kind: actions|process, capabilities, status}]}`",
      "params": "{}",
      "result": "{plugins: [{id: string, version?: string, enabled: bool, kind?: actions|process|string, capabilities?: any, status?: any}]}"
    },
    {
      "name": "plugin.log.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "compat"
      ],
      "milestone": null,
      "spec": null,
      "params": "{plugin?: string, limit?: int}",
      "result": "{logs: [object]}"
    },
    {
      "name": "plugin.registry.notify",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "compat"
      ],
      "milestone": null,
      "spec": null,
      "params": "{}",
      "result": "{ok: bool}"
    },
    {
      "name": "plugin.surface.close",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "compat"
      ],
      "milestone": null,
      "spec": null,
      "params": "{pane: Target}",
      "result": "{closed: Target | null}"
    },
    {
      "name": "preview.declare",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "preview"
      ],
      "milestone": "M3",
      "spec": "`{port, host?: 127.0.0.1, scheme?: http, path?, label?, pane?, task?}` → `{preview}`",
      "params": "{port: int|string, path?: string = '/', scheme?: http|https = http, label?: string, pane?: Target, task?: Target, tls_origin?: bool}",
      "result": "{preview: Preview}"
    },
    {
      "name": "preview.dismiss",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "preview"
      ],
      "milestone": "M3",
      "spec": "`{preview}` → `{preview}` — accept or hide a discovered suggestion",
      "params": "{preview: Target, machine?: string}",
      "result": "{}"
    },
    {
      "name": "preview.forget",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "preview"
      ],
      "milestone": "M3",
      "spec": "`{preview}` → `{}`",
      "params": "{preview: Target, machine?: string}",
      "result": "{}"
    },
    {
      "name": "preview.get",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "preview"
      ],
      "milestone": "M3",
      "spec": "`{preview}` → `{preview}`",
      "params": "{preview: Target, machine?: string}",
      "result": "{preview: Preview}"
    },
    {
      "name": "preview.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "preview"
      ],
      "milestone": "M3",
      "spec": "`{machine?, task?, pane?, status?: suggested|up|down|all}` → `{previews}` — suggestions only with `status: suggested|all`",
      "params": "{machine?: string, task?: Target, pane?: Target, status?: suggested|declared|up|down|gone|all, all?: bool}",
      "result": "{previews: [Preview], machine?: string}"
    },
    {
      "name": "preview.mirror",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "preview"
      ],
      "milestone": "M3",
      "spec": "`{preview}` → `{local_port}` — explicit, unauthenticated raw local port (06 B4). Full scope only",
      "params": "{preview: Target, machine?: string}",
      "result": "{machine: string, preview: string, preview_handle: string, local_port: int, addrs: [string], since_ms: int, accepted: int, rejected: int, authenticated: bool, peer_check: same_user, warning: string, url?: string, already?: bool}"
    },
    {
      "name": "preview.open",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "preview"
      ],
      "milestone": "M3",
      "spec": "`{preview, mode?: profile|proxy, client?: client_id}` → `{opened_in: profile|proxy|default_browser, url}` — profile mode (default) launches/reuses the Vibeke browser profile routed over SOCKS5 to the preview's machine and opens `http://localhost:<port>/<path>`. Proxy mode returns a tokenized `*.vibeke.localhost` URL",
      "params": "{preview?: Target, url?: string, machine?: string, mode?: pane|window|proxy, window?: bool, proxy?: bool, split?: right|down|left|up|tab|float, pane?: Target, focus?: bool = true, device?: string, viewport?: string|{width: int, height: int}, profile?: string, no_open?: bool = false, open?: bool, tls_origin?: bool}",
      "result": "{opened_in: pane, pane: string, pane_handle: string, tab: string, url: string, machine: string, source_pane: string|null} | {opened_in: window, url: string, machine: string, profile: string, profile_dir: string, browser: string, browser_kind: string, pid: int, reused: bool, socks_port: int|null, route: none|loopback|remote} | {opened_in: default_browser, url: string} | {opened_in: proxy, url: string, proxy_url: string, host: string, proxy_port: int, machine: string, preview: string, opened: bool, token_ttl_s: int, session_ttl_s: int, tls_origin: bool, remote_url: string, caveats: string, ca?: PreviewCa, open_url?: string}"
    },
    {
      "name": "preview.profile",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "preview"
      ],
      "milestone": null,
      "spec": null,
      "params": "{action?: list|reset = list, profile?: string, machine?: string}",
      "result": "{profiles: [{name: string, path: string, running: bool, pid: int|null, machine: string|null, route: string|null, bytes: int}], root: string} | {profile: string, removed: bool}"
    },
    {
      "name": "preview.profile.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "preview"
      ],
      "milestone": null,
      "spec": null,
      "params": "{}",
      "result": "{profiles: [{name: string, path: string, running: bool, pid: int|null, machine: string|null, route: string|null, bytes: int}], root: string}"
    },
    {
      "name": "preview.profile.reset",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "preview"
      ],
      "milestone": null,
      "spec": null,
      "params": "{profile?: string, machine?: string}",
      "result": "{profile: string, removed: bool}"
    },
    {
      "name": "preview.promote",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "preview"
      ],
      "milestone": "M3",
      "spec": "`{preview}` → `{preview}` — accept or hide a discovered suggestion",
      "params": "{preview: Target, machine?: string}",
      "result": "{preview: Preview}"
    },
    {
      "name": "preview.status",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "preview"
      ],
      "milestone": "M3",
      "spec": "`{}` → `{socks_port?, browsers: [{profile, machine, route, pid, running}], links: [{machine, connected, bytes_in, bytes_out, rtt_ms}], accepted, rejected}`. `server.status` also carries `preview: {socks_port, browsers, previews}`.",
      "params": "{}",
      "result": "{socks_port: int|null, browsers: [{profile: string, machine: string, route: string, pid: int, running: bool}], links: [{machine: string, connected: bool, bytes_in: int|null, bytes_out: int|null, rtt_ms: int|null}], accepted: int, rejected: int, proxy: {port: int, tls: bool, routes: [{host: string, machine: string, preview: string, handle: string, port: int, scheme: http|https, tls: bool}], stats: {requests: int, denied: int, websockets: int}}|null, mirrors: [PreviewMirror]}"
    },
    {
      "name": "preview.unmirror",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "preview"
      ],
      "milestone": "M3",
      "spec": "`{preview}` → `{local_port}` — explicit, unauthenticated raw local port (06 B4). Full scope only",
      "params": "{preview?: Target|int, port?: int, machine?: string}",
      "result": "{local_port: int, machine: string, preview: string}"
    },
    {
      "name": "preview.url",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "preview"
      ],
      "milestone": "M3",
      "spec": "`{preview, mode?}` → `{remote_url, profile_url, proxy_url?}` — no side effects (for agents: what URL to tell the human)",
      "params": "{preview: Target, machine?: string}",
      "result": "{remote_url: string, profile_url: string, proxy_url: string|null}"
    },
    {
      "name": "sandbox.allow",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "sandbox"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target, host: string}",
      "result": "{task: string, allowed: string}"
    },
    {
      "name": "sandbox.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "sandbox"
      ],
      "milestone": null,
      "spec": null,
      "params": "{}",
      "result": "{sandboxes: [{sandbox: string, task?: string, checkout?: string, level: string, provider?: string, network: any, yolo: bool, proxy_port?: int, task_allow?: any, credentials: any, container?: {container: string, state: string, image: any, code: any, workdir: any, clone?: {branch: string, base: string}, devcontainer: any, warnings: any, in_box_vibeke: any}}]}"
    },
    {
      "name": "sandbox.remove",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "sandbox"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target, force?: bool = false}",
      "result": "{container: string, action: string, sync: any, leftovers: any, error?: string, unsynced_kept: bool}"
    },
    {
      "name": "sandbox.start",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "sandbox"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target}",
      "result": "{state: string, created: bool}"
    },
    {
      "name": "sandbox.status",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "sandbox"
      ],
      "milestone": null,
      "spec": null,
      "params": "{}",
      "result": "{levels: [{level: string, available: bool, detail?: any, hint?: string}], config: object, container: {runtime?: string|null, docker_sandboxes?: {plugin: any, note: string}|null, vibeke_linux: any, vibeke_linux_hint: string}}"
    },
    {
      "name": "sandbox.stop",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "sandbox"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target}",
      "result": "{state: string}"
    },
    {
      "name": "screenshot.delete",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "screenshots"
      ],
      "milestone": "M3",
      "spec": "`{id, force?}` → `{id, handle, deleted, blob_removed}` — human only (`permission_denied` for panes). A screenshot referenced by a review acceptance needs `force` (`conflict {reason: \"referenced_by_acceptance\"}`). The blob goes when no other record references it. Event `screenshot.deleted {ids, reason: deleted\\|retention}`.",
      "params": "{id: string, force?: bool}",
      "result": "{id: string, handle: string, deleted: bool, blob_removed: bool}"
    },
    {
      "name": "screenshot.get",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "screenshots"
      ],
      "milestone": "M3",
      "spec": "`{id}` (id or `sN`) → `ScreenshotMeta + {path_on_machine, exists, data_b64? (inline)}` — other workspaces' screenshots are `not_found` for panes.",
      "params": "{id: string}",
      "result": "ScreenshotMeta"
    },
    {
      "name": "screenshot.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "screenshots"
      ],
      "milestone": "M3",
      "spec": "`{task?, preview?, run?, since?: ms \\| \"1h\", since_ms?, limit?: 50}` → `{screenshots: [ScreenshotMeta + {path_on_machine, exists}], count, total}` — newest first. Pane scope: only screenshots whose `workspace` is the pane's workspace.",
      "params": "{task?: Target, preview?: Target, run?: Target, since?: string|int, since_ms?: int, limit?: int = 50}",
      "result": "{screenshots: [ScreenshotMeta], count: int, total: int}"
    },
    {
      "name": "screenshot.open",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "screenshots"
      ],
      "milestone": "M3",
      "spec": "`{id}` → as `get` with the image inline (the CLI writes it to `$TMPDIR/vibeke-screenshots/<id>.png` and opens it with `open`/`xdg-open`. `VIBEKE_NO_OPEN=1` only reports the path).",
      "params": "{id: string}",
      "result": "ScreenshotMeta"
    },
    {
      "name": "scrollback.forget",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "parity"
      ],
      "milestone": "M1",
      "spec": "`{pane}\\|{workspace}\\|{before}\\|{all: true}` (exactly one), `dry_run?: false`, `plan?` → `{scope, pane_ids, plan, dry_run, panes, segments_deleted, bytes_deleted, fts_rows_deleted, archive_panes_dropped}` — deletes archived scrollback for the scope: zstd segments, `scrollback_fts` rows and `archive_panes` metadata. `scope` is canonical (pane/workspace id, absolute `before` ms), `pane_ids` the resolved panes (null for `before`/`all`), `plan` a digest of both. If the scope no longer matches `plan`, the server returns `conflict`. The CLI sends the dry run's `scope` + `plan` to confirm the deletion. This prevents a focus change or relative cutoff from changing the deletion target. Idempotent. `before` is segment-granular. Does not delete events, blobs, the desk index, drafts or notes (02, 09 §9.3). Event `scrollback.forgotten {scope} {panes, segments, bytes, fts_rows, panes_dropped}` (no text). Full scope only. CLI `vibeke forget` asks first unless `--yes`.",
      "params": "{pane?: Target, workspace?: Target, before?: string|int, all?: bool, dry_run?: bool = false, plan?: string}",
      "result": "{scope: any, pane_ids: [string], plan: any, dry_run: bool, panes?: int, segments_deleted?: int, bytes_deleted?: int, fts_rows_deleted?: int, archive_panes_dropped?: int}"
    },
    {
      "name": "search.query",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{q, scope?: {workspace?, pane?, run?}, sources?: [scrollback, transcript, events], limit?: 50, regex?: false}` → `{hits: [{pane, run?, source, line, text, ts, context}]}` — FTS5 over archive + transcripts",
      "params": "{q: string, scope?: {workspace?: Target, pane?: Target, run?: Target}, sources?: [scrollback|transcript|events], limit?: int = 50, regex?: bool = false}",
      "result": "{hits: [{pane?: string, run?: string|null, source: string, line?: any, text: string, ts?: int, context?: any}]}"
    },
    {
      "name": "server.reload_config",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{}` → `{changed: [keys], errors: []}`",
      "params": "{}",
      "result": "{changed: [string], errors: [ConfigDiagnostic], warnings?: [ConfigWarning]}"
    },
    {
      "name": "server.restart",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "session_api"
      ],
      "milestone": "M1",
      "spec": "`{binary?: path}` → `{new_pid}` — exec's the new server. Holders untouched (01 §1.2)",
      "params": "{binary?: string}",
      "result": "{new_pid: int, binary: string}"
    },
    {
      "name": "server.status",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{}` → `{pid, version, uptime_ms, session, panes, holders: {live, orphaned}, clients, event_seq, db_size, rss}`",
      "params": "{}",
      "result": "{pid: int, version: string, uptime_ms: int, session: string, machine: string, panes: int, holders: {live: int, orphaned?: int}, clients: int, event_seq: int, socket?: string, degraded?: any, preview?: object, timers?: object, db_size?: int, rss?: int}"
    },
    {
      "name": "server.stop",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{kill_panes: bool = false}` → `{}` — with `kill_panes:false`, holders keep running and the next server reattaches",
      "params": "{kill_panes?: bool = false}",
      "result": "{}"
    },
    {
      "name": "session.create",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "session_api"
      ],
      "milestone": "M1",
      "spec": "`{name}` → `{session}` (spawns a server)",
      "params": "{name: string}",
      "result": "{session: SessionEntry}"
    },
    {
      "name": "session.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "session_api"
      ],
      "milestone": "M1",
      "spec": "`{}` → `{sessions: [{name, running, pid?, socket}]}` (scans the runtime dir)",
      "params": "{}",
      "result": "{sessions: [SessionEntry]}"
    },
    {
      "name": "session.rename",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "session_api"
      ],
      "milestone": "M1",
      "spec": "`{name, new_name}` → `{session}`",
      "params": "{name: string, new_name: string}",
      "result": "{session: SessionEntry, previous_name: string}"
    },
    {
      "name": "session.snapshot",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{include?: [workspaces, tabs, panes, runs, interactions, tasks, previews, layouts, machines]}` → `{at_seq, workspaces[], groups[], tabs[], panes[], runs[], interactions[], tasks[], previews[], layouts[], focused: {client_id → {workspace, tab, pane}}}`",
      "params": "{include?: [workspaces|tabs|panes|runs|interactions|tasks|previews|layouts|machines|groups|string]}",
      "result": "{at_seq: int, workspaces?: [Workspace], groups?: [Group], tabs?: [Tab], panes?: [Pane], runs?: [AgentRun], interactions?: [Interaction], tasks?: [Task], previews?: [Preview], layouts?: [any], focused?: {*: {workspace: string|null, tab: string|null, pane: string|null}}}"
    },
    {
      "name": "session.stop",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "session_api"
      ],
      "milestone": "M1",
      "spec": "`{name, kill_panes?: false}` → `{}`",
      "params": "{name: string, kill_panes?: bool = false}",
      "result": "{session: object, stopped: bool}"
    },
    {
      "name": "status.segments",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "parity"
      ],
      "milestone": "M1",
      "spec": "`{pane?, client?}` → `{segments: {machine, session, workspace, task, branch, ports, attention, agents_summary, cpu, clock, sync_input}, focus, appearance, client_side: [mode, prefix_indicator]}` — data for the built-in status-bar segments (08 §4) from that client's focus [M4]",
      "params": "{pane?: Target, client?: string}",
      "result": "{segments: object, focus: any, appearance: Appearance, client_side: [string]}"
    },
    {
      "name": "tab.close",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{tab, force?}` → `{}`",
      "params": "{tab: Target, force?: bool}",
      "result": "{}"
    },
    {
      "name": "tab.create",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{workspace, cwd?, title?, focus?: false, command?: argv, layout?: LayoutSpec}` → `{tab, root_pane}`",
      "params": "{workspace?: Target, cwd?: string, title?: string, focus?: bool = false, command?: [string], layout?: LayoutSpec}",
      "result": "{tab: Tab, root_pane: Pane}"
    },
    {
      "name": "tab.floats",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "parity"
      ],
      "milestone": "M1",
      "spec": "`{tab?, visible?}` → `{tab}` — show/hide all floats (`Tab.floats_hidden`. Toggles without `visible`) [M4]",
      "params": "{tab?: Target, visible?: bool}",
      "result": "{tab: Tab}"
    },
    {
      "name": "tab.focus",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{tab, client?}` → `{tab}`",
      "params": "{tab: Target, client?: string}",
      "result": "{tab: Tab}"
    },
    {
      "name": "tab.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{workspace?}` → `{tabs}`",
      "params": "{workspace?: Target}",
      "result": "{tabs: [Tab]}"
    },
    {
      "name": "tab.move",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{tab, index, workspace?}` → `{tabs}` (numbers are stable. Order changes)",
      "params": "{tab: Target, index: int, workspace?: Target}",
      "result": "{tabs: [Tab]}"
    },
    {
      "name": "tab.rename",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{tab, title: string|null}` → `{tab}`",
      "params": "{tab: Target, title: string|null}",
      "result": "{tab: Tab}"
    },
    {
      "name": "task.check.authorize",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target, check: string, subject: string, subject_id?: string, definition_digest?: string, idempotency_key?: string}",
      "result": "{grant: object, definition: object, provenance: any, subject: string, head_sha: string, confirmation_label: string, execution: {machine: any, runner: 'host', checkout: string}}"
    },
    {
      "name": "task.check.cancel",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{check_run: string}",
      "result": "{check_run: object, cancelling: bool}"
    },
    {
      "name": "task.check.get",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{check_run: string}",
      "result": "{check_run: object, definition: object, task: Target, log_tail: string | null}"
    },
    {
      "name": "task.check.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target, subject?: string, subject_id?: string}",
      "result": "{task: Target, subject: object | null, checks: [object], confirmation_label: string}"
    },
    {
      "name": "task.check.run",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target, check: string, subject: string, subject_id?: string, definition_digest?: string, idempotency_key?: string, authorize?: bool}",
      "result": "{check_run: object, definition: object, provenance: any}"
    },
    {
      "name": "task.create",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1; remote tasks M3; tracking per 15 T1–T4",
      "spec": "`{title, repo: path, base?: ref, isolation?: worktree|none, slug?, branch?, agents?: [{harness, name?, prompt?}], setup?: bool = true, ports?: n, group?}` → `{task, workspace, panes[], runs[]}` — `isolation` is `worktree|none|auto` (default from `tasks.checkout`. `auto` is a worktree). The choice is recorded as `Task.checkout`. `jj_workspace` is refused with `invalid_params` (jj support was removed for v1, 2026-10-06). `task.finish {remove_worktree}` removes the worktree (never for `none`)",
      "params": "{title: string, repo: string, base?: string, isolation?: worktree|none|auto, slug?: string, branch?: string, agents?: [{harness: string, name?: string, prompt?: string}], setup?: bool = true, ports?: int, group?: Target, root?: string, branch_template?: string, fetch?: bool, dry_run?: bool = false}",
      "result": "{task: Task, workspace: Workspace, panes: [Pane], runs: [AgentRun], copied?: [string], files?: [MaterializedFile], deps?: any, setup?: {pane: string|null, status: string|null, agents_pending: bool, commands: [{source: string, command: string}]}, warnings?: [string]} | {dry_run: true, title: string, repo_root: string, slug: string, plan: object, agents: any, setup: bool}"
    },
    {
      "name": "task.dependency.add",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api",
        "review::t4"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target, depends_on: Target, kind?: blocks|related = blocks, idempotency_key?: string}",
      "result": "{edge: object, note: string}"
    },
    {
      "name": "task.dependency.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api",
        "review::t4"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task?: Target}",
      "result": "{task: Target, dependencies: {depends_on: [{edge: object, title: string | null} | {hidden: true, title: string, edge: {kind: string}}], dependents: [{edge: object, title: string | null} | {hidden: true, title: string, edge: {kind: string}}], blocks_open_tasks: int, note: string}} | {edges: [object]}"
    },
    {
      "name": "task.dependency.remove",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api",
        "review::t4"
      ],
      "milestone": null,
      "spec": null,
      "params": "{edge: string} | {task: Target, depends_on: Target, kind?: blocks|related, idempotency_key?: string}",
      "result": "{removed: [object], removed_by: object}"
    },
    {
      "name": "task.effort.estimate",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api",
        "review::t4"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target}",
      "result": "{task: Target, effort: {set: string | null, heuristic: any, note: string}, model_estimate: {method: string, params: object, note: string}}"
    },
    {
      "name": "task.finish",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1; remote tasks M3; tracking per 15 T1–T4",
      "spec": "`{task, remove_worktree?: ask|true|false, delete_branch?: false}` → `{task}`",
      "params": "{task: Target, remove_worktree?: ask|bool = false, force?: bool = false, archive?: bool, status?: string}",
      "result": "{task: Task, job?: any}"
    },
    {
      "name": "task.get",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1; remote tasks M3; tracking per 15 T1–T4",
      "spec": "`{task}` → `{task, workspace, runs, previews, collisions[]}`",
      "params": "{task: Target}",
      "result": "{task: Task, branch_status: {branch: string|null, ahead: int, behind: int, dirty_files: int, upstream: string|null, compared_to: string|null}|null, pr?: PrLookup|null}"
    },
    {
      "name": "task.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1; remote tasks M3; tracking per 15 T1–T4",
      "spec": "`{status?, repo?}` → `{tasks}`",
      "params": "{status?: string, repo?: string}",
      "result": "{tasks: [Task]}"
    },
    {
      "name": "task.park",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "task_park"
      ],
      "milestone": "M1; remote tasks M3; tracking per 15 T1–T4",
      "spec": "`{task}` → `{task}` — park = stop agents gracefully, keep worktree",
      "params": "{task: Target}",
      "result": "{task: Task, stopped: [{run: string, handle: string, pane: string, harness: string, name: string|null, pane_closed: bool, resumable: bool}], note?: string}"
    },
    {
      "name": "task.pr",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target, refresh?: bool = false}",
      "result": "{task: string, pr: PrLookup}"
    },
    {
      "name": "task.reconcile",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{repo?: string}",
      "result": "{reports: [{repo: string, missing: [{task_id: string, path: string, reason: string}], branch_moved: [{task_id: string, path: string, expected: string|null, actual: string|null}], orphans: [{path: string, kind: string, branch: string|null}]}]}"
    },
    {
      "name": "task.resume",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "task_park"
      ],
      "milestone": "M1; remote tasks M3; tracking per 15 T1–T4",
      "spec": "`{task}` → `{task}` — park = stop agents gracefully, keep worktree",
      "params": "{task: Target}",
      "result": "{task: Task, resumed: [AgentRun], skipped: [{run: string, reason: string}]}"
    },
    {
      "name": "task.review.accept",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target, subject_id: string, intent_revision: int, expected_intent_revision?: int, package_revision?: int, expected_package_revision?: int, exceptions?: [{criterion: string, criterion_id?: string, reason?: string}], idempotency_key?: string}",
      "result": "{acceptance: object, label: string, label_text: string, task: Task, note: string}"
    },
    {
      "name": "task.review.candidates",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target}",
      "result": "{task: Target, current: string | null, candidates: [object], inspect_only: any, no_end_candidate: any, review_base: any, warnings: [string]}"
    },
    {
      "name": "task.review.diff",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target, subject?: string, path?: string, max_bytes?: int}",
      "result": "{task: Target, subject: string, base_sha: string, head_sha: string, content_sha: string, path: string | null, diff: string, truncated: bool, total_bytes: int, max_bytes: int}"
    },
    {
      "name": "task.review.get",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target, subject?: string}",
      "result": "{task: Target, task_title: string, package_revision: int, revision: int, intent_revision: int | null, intent: object | null, subject: object | null, subject_current: bool, accept_capable: bool, candidates: [object], inspect_only: any, no_end_candidate: any, review_base: any, baseline: any, warnings: [string], diff_stat: any, sources_verified: bool, historical_only: bool, observed_commands: [object], claims: [object], observed: [object], screenshots: [ScreenshotMeta], checks: [object], check_runs: [object], assessment: object, criteria: [object], blockers: any, label: string, label_text: string, readiness: {label: string, label_text: string}, acceptance: object | null, acceptance_history: [object], live: object, mappings_confirmed: any, review_notes: [object], reviewer_runs: [object], dependencies: object, effort: {set: string | null, heuristic: any, note: string}, snapshot: {available: bool, method: string, note: string}, actions: {accept: {available: bool, reason: string | null, requires_exceptions: any}}}"
    },
    {
      "name": "task.review.note.classify",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api",
        "review::t4"
      ],
      "milestone": null,
      "spec": null,
      "params": "{note: string, classification: blocking|not_blocking|dismissed, reason?: string, idempotency_key?: string}",
      "result": "{note: object}"
    },
    {
      "name": "task.review.notes",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api",
        "review::t4"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target}",
      "result": "{task: Target, notes: [object], reviewer_runs: [object]}"
    },
    {
      "name": "task.review.request_reviewer",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api",
        "review::t4"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target, harness?: string = claude, subject?: string, expected_subject?: string, prompt?: string, idempotency_key?: string}",
      "result": "{request: object, prompt: string, prompt_digest: string, harness: string, subject: string, requires_confirmation: true, label: string, uses_provider: string, confirm_with: {method: string, params: {request: string, prompt_digest: string}}}"
    },
    {
      "name": "task.review.snapshot",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api",
        "review::t4"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target, idempotency_key?: string}",
      "result": "{subject: object, snapshot: object, label: string, note: string}"
    },
    {
      "name": "task.review.snapshot.gc",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api",
        "review::t4"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target, include_unrecorded?: bool = false, dry_run?: bool = false} | {repo: string, include_unrecorded?: bool = false, dry_run?: bool = false}",
      "result": "{repo: string, task: Target | null, dry_run: bool, removed: [object], kept: [object], unrecorded: [object], note: string}"
    },
    {
      "name": "task.review.start_reviewer",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api",
        "review::t4"
      ],
      "milestone": null,
      "spec": null,
      "params": "{request: string, prompt_digest: string, pane?: Target, split_of?: Target, direction?: string = right, idempotency_key?: string}",
      "result": "{request: object, run: Target, binding: object, note?: string, replayed?: bool}"
    },
    {
      "name": "task.setup",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target, setup_script?: string}",
      "result": "{task: string, started: bool, pane: string|null, setup_status: string|null, commands: [{source: string, command: string}], needs_trust: bool}"
    },
    {
      "name": "task.sync",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "sandbox"
      ],
      "milestone": null,
      "spec": null,
      "params": "{task: Target, direction?: pull|push|both = pull, force?: bool = false}",
      "result": "{task: Target | null, synced: [{direction: string, status: string, commits: any, from: any, to: any, ref: any}]}"
    },
    {
      "name": "theme.get",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "parity",
        "theme"
      ],
      "milestone": "M1",
      "spec": "`{}` / `{mode: auto\\|light\\|dark\\|null}` → `{appearance, colorfgbg, reports?}` — `set_mode` is a runtime override, not persisted [M4]",
      "params": "{}",
      "result": "{appearance: Appearance, colorfgbg: string, reports?: any}"
    },
    {
      "name": "theme.set_mode",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "parity",
        "theme"
      ],
      "milestone": "M1",
      "spec": "`{}` / `{mode: auto\\|light\\|dark\\|null}` → `{appearance, colorfgbg, reports?}` — `set_mode` is a runtime override, not persisted [M4]",
      "params": "{mode: auto|light|dark|null}",
      "result": "{appearance: Appearance, colorfgbg: string, reports?: any}"
    },
    {
      "name": "workspace.close",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{workspace, force?: false}` → `{}` — refuses with `conflict:pane_busy` if a non-shell foreground process runs, unless `force`",
      "params": "{workspace?: Target, force?: bool = false}",
      "result": "{}"
    },
    {
      "name": "workspace.create",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{cwd, name?, group?, focus?: false, layout?: LayoutSpec, command?: argv}` → `{workspace, tab, root_pane}`",
      "params": "{cwd?: string, name?: string, group?: Target, focus?: bool = false, layout?: LayoutSpec, command?: [string]}",
      "result": "{workspace: Workspace, tab: Tab, root_pane: Pane}"
    },
    {
      "name": "workspace.focus",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{workspace, client?}` → `{workspace}`",
      "params": "{workspace: Target, client?: string}",
      "result": "{workspace: Workspace}"
    },
    {
      "name": "workspace.get",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{workspace}` → `{workspace}`",
      "params": "{workspace?: Target}",
      "result": "{workspace: Workspace}"
    },
    {
      "name": "workspace.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{group?}` → `{workspaces: [Workspace + {agent_summary: {working, needs_input, done, idle}, tab_count, pane_count}]}`",
      "params": "{group?: Target}",
      "result": "{workspaces: [Workspace]}"
    },
    {
      "name": "workspace.move",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{workspace, group?, index}` → `{workspaces}`",
      "params": "{workspace: Target, group?: Target|null, index?: int, delta?: int}",
      "result": "{workspaces: [Workspace]}"
    },
    {
      "name": "workspace.rename",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1",
      "spec": "`{workspace, name: string|null}` → `{workspace}` (null clears to auto-name)",
      "params": "{workspace?: Target, name: string|null}",
      "result": "{workspace: Workspace}"
    },
    {
      "name": "worktree.create",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1; remote tasks M3; tracking per 15 T1–T4",
      "spec": "`{repo|cwd, branch, path?, base?, open?: bool, focus?: false}` → `{worktree, workspace?}`",
      "params": "{repo?: string, cwd?: string, branch: string, path?: string, base?: string, open?: bool, focus?: bool = false}",
      "result": "{worktree: any, workspace?: Workspace}"
    },
    {
      "name": "worktree.list",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1; remote tasks M3; tracking per 15 T1–T4",
      "spec": "`{repo?: path, cwd?: path}` → `{worktrees: [{path, branch, head, task?, workspace?, locked, prunable}]}`",
      "params": "{repo?: string, cwd?: string}",
      "result": "{worktrees: [{path: string, branch: string|null, head: string, task?: string|null, workspace?: string|null, locked: bool, prunable: bool}]}"
    },
    {
      "name": "worktree.open",
      "mutating": true,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1; remote tasks M3; tracking per 15 T1–T4",
      "spec": "`{path, focus?: false}` → `{workspace}`",
      "params": "{path: string, focus?: bool = false}",
      "result": "{workspace: Workspace}"
    },
    {
      "name": "worktree.remove",
      "mutating": true,
      "scope": "full",
      "pane_scope": "forbidden",
      "gateway": "actor_required",
      "tables": [
        "api"
      ],
      "milestone": "M1; remote tasks M3; tracking per 15 T1–T4",
      "spec": "`{path, force?: false}` → `{job}` — Runs asynchronously. Reports progress through the `worktree.removed` event",
      "params": "{path: string, force?: bool = false, dry_run?: bool = false}",
      "result": "{job: any} | {dry_run: true, path: string, branch: string|null, dirty_files: int, unpushed_commits: int, would_remove: bool, force: bool}"
    },
    {
      "name": "worktree.repo_root",
      "mutating": false,
      "scope": "pane",
      "pane_scope": "open",
      "gateway": "open",
      "tables": [
        "api"
      ],
      "milestone": "M1; remote tasks M3; tracking per 15 T1–T4",
      "spec": "`{cwd}` → `{repo_root, vcs}`",
      "params": "{cwd: string}",
      "result": "{repo_root: string, vcs: string}"
    }
  ]
}
