HTTP API

Local apps/clankie service on http://127.0.0.1:4310. There is no HTML index: / is 404 and GET /health is the public probe.

Most other routes take an Authorization: Bearer <token> header. Pairing redeem/complete use their one-time offer secrets instead. Persistent tokens live in the credential broker (Keychain service bot.clankie.credentials):

Principal Keychain account Typical use
Operator clankie_operator TUI operator reads/writes, pairing, devices, play stop
Captain clankie_captain (also CLANKIE_CAPTAIN_TOKEN) /operator/v1/dispatch, /captain/v1/lanes
Discord text clankie_discord_bridge Discord channel turns, presence, person memory
Discord voice clankie_discord_voice_bridge Voice briefing; voice-lane channel turns
Discord user text clankie_discord_user_bridge Lab-user channel turns and presence
Discord user voice clankie_discord_user_voice_bridge Lab-user voice-lane turns
Device minted at pairing complete /v1/devices/self*

Discord-lane routes 403 if the bearer is the console captain token (steer source api). Import this file in Yaak (Settings → Import/Export) or run apps/clankie/scripts/setup-yaak.py.

Base URL http://127.0.0.1:4310 · version 0.2.0 · the raw document is openapi.yaml.

This is the service contract on Clankie’s host. The public network surface exposes a bounded subset through api.clankie.bot; the host still decides every device grant. Hosted account and billing endpoints are separate contracts.

Bearers

Bearer Where it lives
worker Individual short-lived grant issued by POST /v1/worker-grants/; never an operator or provider credential
operator Keychain clankie_operator
captain Keychain clankie_captain / CLANKIE_CAPTAIN_TOKEN
discord text Keychain clankie_discord_bridge or clankie_discord_user_bridge
discord voice Keychain clankie_discord_voice_bridge or clankie_discord_user_voice_bridge
device Device session token from pairing complete

Routes

Method Route Summary Bearer
GET /v1/operator/http-settings Read the shared core and relay browser-origin allowlist none
POST /v1/operator/http-settings Replace the exact browser-origin allowlist none
POST /v1/machine-joins/start Advertise a pending outbound machine with a five-minute approval window none
POST /v1/machine-joins/status Claim the approved registration with the initiating host secret none
POST /v1/machine-joins/approve Owner approves a pending host, ceiling and directory subset operator or device
POST /v1/joined-machines/challenge Fresh one-use machine request challenge none
POST /v1/joined-machines/channel Authenticated encrypted policy and one-shot work exchange none
POST /v1/joined-machines/leave Durably revoke this machine capability none
GET /v1/machines/access-refusals Read unresolved machine access refusals for the owner operator
GET /v1/machines/shell-audit Read Clankie's recent shell calls on joined machines operator
PATCH /v1/machines/{id}/access Set the owner-chosen machine capability ceiling operator
GET /v1/checkouts Inspect enrolled local owner checkouts against cached origin/main operator
POST /v1/checkouts/sync Fetch and safely fast-forward enrolled owner main checkouts operator
POST /v1/checkouts/reclaim-caches Reclaim verified caches in clean inactive enrolled linked worktrees operator
POST /v1/checkouts/prune Preserve evidence and remove one landed clean inactive enrolled worktree operator
POST /v1/checkouts/decide Record a judgment of one linked worktree's unlanded work operator
POST /v1/activity/shares Control owner-authorized Activity media shares operator
POST /v1/integrate Compose, gate and land an ordered approved commit batch operator
POST /v1/activity/viewer Read hosted Activity media with a live audience authorization none
GET /v1/runtime-update Read runtime-update status and current deploy holds operator
POST /v1/runtime-update Admit a local pinned-runtime deployment after the deploy-hold check operator
POST /v1/runtime-update/cutover Confirm an idle scheduled release cutover after staging operator
GET /v1/discord/settings Read Discord server roles, owners, room skills, fleet and tracking operator
POST /v1/discord/settings Save revision-fenced non-secret Discord settings operator
POST /v1/discord/setup/test-post Explicitly send one owner-requested setup message to a text room operator
POST /v1/discord/ingress Admit an encrypted Discord turn or scoped voice callback none
GET /v1/composer/transcription/status Read local or managed availability and included allowance device
POST /v1/composer/transcription/begin Begin one bounded composer recording device
POST /v1/composer/transcription/chunk Append one recording chunk at an exact byte offset device
POST /v1/composer/transcription/commit Transcribe a completed recording once device
POST /v1/composer/transcription/cancel Discard a recording and prevent late draft delivery device
POST /v1/composer/transcription/receipt Reconcile the same recording without repeating provider dispatch device
GET /v1/model-keys List supported providers, models, stored-key status and captain selection operator or device
GET /v1/model-keys/subscriptions List providers signed in through an account (OAuth or subscription) instead of an API key operator or device
GET /v1/model-keys/subscriptions/methods List currently supported provider subscription sign-in methods operator or device
POST /v1/model-keys/subscriptions/start Start a provider sign-in for the authenticated initiating principal operator or device
POST /v1/model-keys/subscriptions/status Read the initiating principal's sign-in interaction operator or device
POST /v1/model-keys/subscriptions/cancel Cancel a pending sign-in; an admitted credential write finishes as committing operator or device
GET /v1/model-keys/options List providers usable without key entry and the running model's reasoning effort operator or device
POST /v1/model-keys/effort Set or clear the running model's reasoning effort for the next turn operator or device
POST /v1/model-keys/set Store or replace a write-only provider API key operator or device
POST /v1/model-keys/validate Validate the stored key with a bounded provider call operator or device
POST /v1/model-keys/select Select the captain model for the next turn operator or device
POST /v1/model-keys/remove Remove a stored API key without removing OAuth or environment fallback operator or device
GET /v1/accounts/codex List discovered local Codex identities and their homes operator or device
POST /v1/accounts/codex Register or remove an owner's local Codex home operator or device
GET /v1/accounts Read the body-owned GitHub, Linear and Google account catalog operator or device
POST /v1/accounts/github/start Start a GitHub device flow; return the user code and verification URL operator or device
POST /v1/accounts/github/poll Poll a GitHub device flow; returns pending, connected or a closed error operator or device
POST /v1/accounts/linear/start Start registered Linear app OAuth with S256 PKCE; return the authorize URL operator or device
POST /v1/accounts/linear/complete Hand back Linear's redirect code; the body exchanges it with its verifier operator or device
POST /v1/accounts/linear/app Connect a workspace-owned Linear app for worker names and portraits operator or device
POST /v1/accounts/google/start Start body-owned Google consent with state and S256 PKCE operator or device
POST /v1/accounts/google/complete Exchange the one-time Google code on the tenant body operator or device
POST /v1/accounts/google/check Refresh and verify the selected Google account's authorized access operator or device
POST /v1/accounts/disconnect Disconnect locally and report actual provider revocation operator or device
POST /v1/accounts/email/connect Choose his Clankie mailbox in one step and return the email row operator or device
GET /v1/connections Inspect execution runtimes and verified Linear identity operator
GET /v1/runtime-connections Inspect the default fleet and named execution connections operator
POST /v1/runtime-connections Connect a Herdr runtime or configure owner execution policy operator
DELETE /v1/runtime-connections/{id} Disable a named execution connection while preserving workers and route identity operator
POST /v1/tracker/import/linear Mirror a Linear project into a named scratch built-in tracker none
POST /v1/tracker/mirror/linear Enable, disable or inspect a scratch import's Linear webhook mirror none
POST /v1/tracker/cutover/linear Cut a World project over from Linear to the built-in tracker, or switch it back none
POST /v1/work Read and write work items in the repo's own tracking convention operator
GET /v1/linear/routes Inspect configured Linear project lead chats operator
PUT /v1/linear/routes Replace Linear project destinations with existing ordinary global chats operator
GET /v1/linear/deliveries Inspect offered Linear wake batches, destinations and target consumption receipts operator
GET /v1/linear/target Inspect the ordinary chat selected for Linear activity operator
PUT /v1/linear/target Select an existing ordinary global chat without restarting operator
GET /v1/auto/rounds Read the Auto round record, newest first operator
GET /v1/linear/request-budget Read rolling provider request usage and background read throttling operator
GET /v1/linear/wake Inspect actor and activity wake rules operator or device
POST /v1/linear/wake Save validated settings with revision fencing operator or device
PUT /v1/linear/wake Save validated settings with revision fencing operator or device
GET /v1/linear/follow Inspect following and webhook readiness operator or device
POST /v1/linear/follow Save validated settings with revision fencing operator or device
PUT /v1/linear/follow Save validated settings with revision fencing operator or device
GET /v1/worker-grants/ List worker grant records without bearer tokens operator
POST /v1/worker-grants/ Issue a scoped grant for one verified connected account operator
DELETE /v1/worker-grants/{id} Durably revoke one worker grant and close its sessions operator
GET /v1/worker-grants/linear/account Inspect disconnected, unverified or verified Linear account identity operator
POST /v1/worker-grants/linear/account Verify the stored Linear account's provider user and workspace operator
GET /v1/worker-mcp MCP session stream worker
POST /v1/worker-mcp Initialize a worker MCP session or list/call its granted tools worker
DELETE /v1/worker-mcp Close an authenticated worker MCP session worker
POST /v1/hosted/operator Dispatch as an account-paired hosted operator device device
POST /v1/runtime-connections/{id}/prepare Prepare Clankie's own harness setup on an existing machine operator
GET /v1/operator/work-tracker Read the new-project default or one project's saved tracker operator or device
POST /v1/operator/work-tracker Read, preview or set the new-project default or a project's work tracker operator or device
GET /v1/operator/fleet-settings Read fleet size, model mode and owner working preferences operator or device
POST /v1/operator/fleet-settings Update fleet budget and working preferences with revision fencing operator or device
GET /v1/operator/fleet-settings/hire Read the fleet's hire defaults (harness and model; legacy effort read-only) operator or device
POST /v1/operator/fleet-settings/hire Set or clear fleet hire defaults operator or device
GET /v1/worker-accounts Read one machine's worker accounts and verified Pi profile operator or device
GET /v1/worker-accounts/holds Read held worker accounts and current revision operator or device
POST /v1/worker-accounts/holds Save validated settings with revision fencing operator or device
GET /v1/usage Read account usage, optional native fleet context spend and where the next hires go operator or device
GET /v1/usage/settings Read the usage overlay and run-out warning settings operator or device
POST /v1/usage/settings Save usage display and run-out warning settings with revision fencing operator or device
GET /v1/operator/fleet-settings/context Resolve current project policy and already-linked setup target operator or device
GET /v1/operator/reviews List landing review candidates, newest first operator
GET /v1/operator/reviews/{id} Read one landing review candidate operator
GET /v1/operator/reviews/landing Ask whether one exact patch may land operator
POST /v1/operator/reviews/waivers Land one exact patch without its project's review operator
POST /v1/operator/projects/update Update project policy while preserving independent inheritance operator or device
GET /v1/operator/projects Read owner project settings and their current revision operator or device
POST /v1/operator/projects/create Create a reviewed project with one canonical local workspace operator
POST /v1/operator/projects/remove-workspace Remove one exact owner-approved workspace registration operator
POST /v1/fleet/worker-tool-refresh Refresh worker catalogs through their original native controllers operator
POST /v1/fleet/worker-tool-restart Check admission for explicit same-thread worker restart operator
POST /v1/harness-refresh Refresh existing native worker plugin links locally and on enabled fleet machines operator
POST /v1/harness-plugin-version Tell a running service which worker version the installer shipped operator
GET /v1/runtime-connections/{id}/harnesses Inspect native harness registration on one registered remote fleet operator
GET /v1/runtime-connections/{id}/membership Inspect host-observed project eligibility on one registered remote fleet operator
GET /v1/operator/persona Read owner-authored character and talkativeness operator or device
POST /v1/operator/persona Save validated settings with revision fencing operator or device
GET /v1/operator/host-settings Read keep-awake and automatic update preferences operator or device
POST /v1/operator/host-settings Save validated settings with revision fencing operator or device
GET /v1/operator/appearance Read which bundled skin Clankie wears on the owner's surfaces operator or device
POST /v1/operator/appearance Choose Clankie's look with revision fencing operator or device
GET /v1/operator/maximum-trust-mode Read whether maximum trust mode is on operator or device
POST /v1/operator/maximum-trust-mode Turn maximum trust mode on or off operator or device
GET /v1/operator/runtime-health Read runtime CPU and health alarm settings and metadata operator or device
POST /v1/operator/runtime-health Change runtime health alarm thresholds without restarting operator or device
GET /v1/operator/voice Read stored and effective voice settings operator or device
POST /v1/operator/voice Save validated settings with revision fencing operator or device
GET /health Public liveness none
GET /v1/herdr Running service's worker-runtime binding operator
GET /v1/discord/presence-status Operator presence snapshot operator
GET /v1/discord/user-session/opt-in Current user-session opt-in captain or operator
POST /v1/discord/user-session/opt-in Record user-session ToS acceptance operator
DELETE /v1/discord/user-session/opt-in Revoke the active user-session opt-in operator
GET /v1/discord/stream-watch Latest observed Discord screen shares captain or operator
POST /v1/discord/stream-watch Bridge report of shares and optional stills captain
GET /v1/discord/readiness Discord captain readiness discord text or discord voice
POST /v1/discord/voice-briefing Compose the realtime voice briefing discord voice
POST /v1/discord/presence-session-events Apply a Discord presence phase event discord text or discord voice
GET /v1/discord/presence-sessions Full presence session records captain
GET /v1/discord/voice-history Completed voice stays captain
GET /v1/discord/voice-transcripts Page through retained Discord voice transcripts captain
POST /v1/discord/presence-actions Execute a policy-gated Discord action discord text or discord voice
POST /v1/captain/channel-turns One Discord message becomes one captain turn discord text or discord voice
GET /v1/captain/channel-turns/{deliveryId} Poll a Discord turn by its stable delivery ID discord text or discord voice
POST /v1/captain/presence Report captain lease heartbeat captain
GET /operator/v1/voice-call Device voice call (WebSocket) captain
POST /operator/v1/dispatch Operator conversation contract captain or operator or device
GET /captain/v1/lanes Observable captain lanes captain
GET /v1/captain/evaluator Independent evaluator status, queue and recent reports operator
POST /v1/captain/evaluator Enable, disable, focus or retry the independent evaluator operator
GET /v1/captain/issue-metrics Observed issue and fleet efficiency with explicit source coverage operator
GET /v1/captain/turn-metrics Recent settled captain turns operator
POST /v1/captain/seat-migrations Prepare, inspect, claim or complete an exact native session handoff operator or captain
GET /v1/captain/seat-bindings Inspect binding mode, live operator launcher inventory and recovery operator or captain
PUT /v1/captain/seat-bindings Bind a launcher's native harness to an operator conversation operator or captain
DELETE /v1/captain/seat-bindings Release the requesting launcher's operator seat binding operator or captain
GET /v1/captain/seat-context Resolve an operator seat to its service conversation and workspace operator or captain
POST /v1/captain/seat-context Create a separate workspace chat for a new native operator seat operator or captain
POST /v1/remote-leads/{action} Prepare, launch or revoke a Windows Claude project head operator
POST /v1/seat/transcript Append redacted native seat display records to its selected conversation operator or captain
GET /v1/captain/prompt The system prompt a lane's session starts from operator or captain
GET /v1/captain/memory-card The memory card that lane's next run injects operator or captain
GET /v1/mcp Server-to-client notification stream for an open session operator or captain or discord text or discord voice
POST /v1/mcp A lane's tool bank over streamable-HTTP MCP operator or captain or discord text or discord voice
DELETE /v1/mcp End an MCP session operator or captain or discord text or discord voice
GET /v1/seat/events Long-poll the seat's outbox operator or captain
POST /v1/seat/events/{id}/reply Answer an escalation from the seat operator or captain
GET /v1/fleet/metrics Read fixed-reason fleet proof and report counters operator
GET /v1/fleet/lead-restart Read the default lead seat's fresh-restart budget, last check and refused wait operator
GET /v1/fleet/seat-restarts Read hired-seat restart checks, durable refusals and original receipts operator
POST /v1/fleet/seats/{paneId}/messages/health Record a native worker's content-free receipt health operator
POST /v1/fleet/efficiency Inspect owned seats or record a worker review operator
POST /v1/fleet/tidy-worktrees List merged, clean worktree cleanup candidates operator
GET /v1/fleet/seats/{paneId}/events Long-poll a fleet seat's mailbox operator or captain
GET /v1/fleet/seats/{paneId}/peers List native seats in the calling worker's fleet none
GET /v1/fleet/seats/{paneId}/messages/{id}/status Read original sending seat's current durable delivery stage none
POST /v1/fleet/seats/{paneId}/peer-messages Send one same-fleet peer message through native seat delivery none
GET /v1/fleet/seats/{paneId}/peer-messages/{id} Inspect the original peer delivery receipt without resending none
POST /v1/fleet/seats/{paneId}/review-candidates Submit the seat's exact patch to its project's standing reviewer none
GET /v1/fleet/seats/{paneId}/review-candidates/{id} Read a candidate and its stored patch as its author or reviewer none
POST /v1/fleet/seats/{paneId}/review-verdicts Record APPROVE or CHANGES for one exact patch none
POST /v1/fleet/seats/{paneId}/hook Report a hired seat's lifecycle hook operator or captain
GET /v1/fleet/seats/{paneId}/tool-catalog Long-poll a fleet seat's catalog revision operator or captain
POST /v1/fleet/seats/{paneId}/tool-catalog Report the occupying native harness's accepted Clankie tools operator or captain
GET /v1/fleet/tool-catalog-health Read native catalog health for every current Claude and Codex seat operator
POST /v1/operator/projects/add-worktree-root Enroll a repository-bound linked-worktree root operator
POST /v1/operator/projects/remove-worktree-root Remove a linked-worktree root enrollment operator
GET /v1/memory Browse every memory note and Discord person fact operator
POST /v1/memory/discord-people/proposals Upsert a Discord person fact discord text or discord voice
GET /v1/memory/discord-people/{guildId}/{userId} Recall Discord person facts discord text or discord voice
DELETE /v1/memory/discord-people/{guildId}/{userId} Delete every fact for a Discord person operator
GET /v1/memory/discord-people/{guildId}/{userId}/export Operator export of a Discord person operator
PATCH /v1/memory/discord-people/{guildId}/{userId}/{factId} Edit one Discord person fact without changing its identity or provenance operator
DELETE /v1/memory/discord-people/{guildId}/{userId}/{factId} Forget one Discord person fact operator
GET /v1/memory/captain-episodes Recall memory notes for a lane captain
POST /v1/memory/captain-episodes Record a self-authored memory note captain
PATCH /v1/memory/captain-episodes/{lane}/{episodeId} Edit one memory note or its visibility operator
DELETE /v1/memory/captain-episodes/{lane}/{episodeId} Forget one memory note operator
GET /v1/games/extensions Discover registered game extension lifecycles operator
GET /v1/minecraft Read the current Minecraft body session operator
POST /v1/minecraft Join, choose a driver, act, inspect, pause, cancel or leave Minecraft operator
POST /v1/minecraft/host Configure, start, administer or back up Clankie's own Minecraft server operator
GET /v1/minecraft/configuration Read owner Minecraft profiles, destination allowlist and play settings operator
PUT /v1/minecraft/configuration Replace offline Minecraft profiles, public destination grants and play settings operator
GET /v1/games/configuration Pokémon play defaults operator or captain
PUT /v1/games/configuration Replace gameplay configuration for subsequent sittings operator or device
POST /v1/embodiment/intents Ask to start or stop play operator
GET /v1/embodiment/sessions/live Live play session operator or captain
POST /v1/embodiment/sessions/live/stop Operator kill-switch (ordinary stop intent) operator
POST /v1/embodiment/sessions/live/guide Suggest an objective or approach to the owning Pokémon mind operator
GET /v1/embodiment/sessions/live/activity Present-tense self-observation operator or captain
GET /v1/embodiment/sessions/live/still One still of the live play screen operator or captain
GET /v1/embodiment/sessions/live/story Bounded story of this playthrough operator or captain
GET /v1/embodiment/sessions/{id} One embodiment session captain
POST /v1/conversation-heads Designate or clear an explicit escalation head operator
GET /v1/body-leases Conversation ownership of Clankie's body resources operator or device
POST /v1/body-leases Explicitly acquire, renew, release, queue, ask or recover a body resource operator
POST /v1/computer/authority Recheck the owning conversation's computer authority operator
POST /v1/computer Drive the conversation-leased computer body operator
GET /v1/browser/harnesses Computer-use harnesses here and on linked Windows fleets operator
GET /v1/browser/tools Live browser tool catalog operator or captain
POST /v1/browser/call Call a browser tool operator or captain
POST /v1/media/images Generate or edit an image operator or captain
POST /v1/media/videos Start or resume a video render operator or captain
GET /v1/support/grants Read owner-issued support grants operator or device
POST /v1/support/grants Create a support window of at most 72 hours operator or device
POST /v1/support/grants/{id}/revoke Revoke support access operator or device
POST /v1/support/grants/{id}/pairing-offer Offer pairing for an active read-state support grant operator or device
POST /v1/hosted/support Apply an exact command authorized by a hosted account ticket none
POST /v1/pairing/local/offer Mint the same-UID Mac companion handoff through owner-private IPC operator
POST /v1/pairing/local/redeem Redeem the owner-local handoff once over native loopback none
POST /v1/pairing/local/trusted-apps List, add or remove the apps that may take the same-Mac handoff operator
POST /v1/pairing/offer Mint a one-time pairing offer operator
POST /v1/pairing/runs/{id}/end End an automation pairing run operator
POST /v1/pairing/redeem Redeem an offer into a pending device none
POST /v1/pairing/complete Activate a pending device none
GET /v1/captain/readiness Read secret-free chat setup readiness operator or device
GET /v1/devices/self/diagnostics-default Read the account diagnostics default operator or device
GET /v1/devices List paired devices operator or device
POST /v1/devices/{id}/revoke Revoke a device operator or device
GET /v1/devices/self Device reads its own registration device
POST /v1/hosted/pair-offer Mint an authenticated encrypted offer for the hosted account page none
POST /v1/devices/wake-key Register a paired device wake public key on a managed body device
POST /v1/devices/self/push Device records or clears its push delivery reference device
POST /v1/devices/self/session/refresh Renew a device session token device

Health

GET /health — Public liveness

Optional Herdr, gateway, host-power, runtime identity and runtimeHealth findings do not change service liveness. runtimeHealth contains fixed CPU percentage, health latency, duration, reason/alarm/delivery enums and incident timestamps; no conversation content. power says whether this host may sleep and when it last did (@clankie/protocol/host-power; docs/always-on.md). When available, runtime exposes only this service boot's pid, commit, root and instanceId; update transaction details are omitted.

Bearer: none

Status Meaning
200 Service is up (application/json)

Operator

GET /v1/operator/http-settings — Read the shared core and relay browser-origin allowlist

Requires an owner operator or current terminal-control device. CORS grants no authentication.

Bearer: none

Status Meaning
200 HttpSettingsSnapshotSchema from @clankie/protocol/owner-settings; schemaVersion, revision and http.allowedOrigins
401 Authentication required
403 Owner grant or browser origin refused

POST /v1/operator/http-settings — Replace the exact browser-origin allowlist

Empty disables browser access. No wildcard, credentials, paths, trailing slash or opaque origin; no restart required.

Bearer: none

Request body (required JSON)

A JSON object.

Status Meaning
200 Updated HttpSettingsSnapshotSchema
400 Invalid exact-origin list or malformed request
401 Authentication required
403 Owner grant or browser origin refused
409 Settings or owner authority changed; read before reviewing again
503 Settings unavailable

POST /v1/machine-joins/approve — Owner approves a pending host, ceiling and directory subset

Strict {code, accessLevel, directories}. CODE is the 43-character base64url approval secret copied from the joining host. Operator bearer or a current paired device with Take Control; authority rechecked before persistence. This route stays behind device-envelope encryption at the gateway.

Bearer: operator or device

Request body (required JSON)

A JSON object.

Status Meaning
200 ok
400 Code consumed/expired or directory selection refused
401 Authentication required
403 Current owner control required

PATCH /v1/machines/{id}/access — Set the owner-chosen machine capability ceiling

Cumulative portal, workers, shell and screen levels. Existing local installs retain screen; ungranted remote machines start at portal. Current enforcement is service-preference for ordinary local/SSH and joined-host for registered outbound receivers. A verified native macOS envelope reports os-sandbox, accessCeiling and approvedDirectories in machine inventory. Raising beyond that ceiling refuses until the owner removes the envelope and launches a new service. Actor and directory grants remain independent.

Bearer: operator

In Name Required Type Description
path id yes string

Request body (required JSON)

A JSON object.

Status Meaning
200 Persisted canonical machine ID, accessLevel and accessEnforcement (service-preference, joined-host or os-sandbox)
400 Unknown machine or invalid access request
401 Operator authentication required
413 Request too large
503 Operator authentication or machine registry unavailable

GET /v1/checkouts — Inspect enrolled local owner checkouts against cached origin/main

Bearer: operator

Status Meaning
200 Observation time, cached ref freshness, checkout branch, HEAD, ahead/behind, dirty state, stale/linked worktree counts, and unreconciled linked worktrees (commits not on main by content, uncommitted files) with owner, age and any recorded decision
401 Operator authentication required
503 Checkout maintenance unavailable

POST /v1/checkouts/sync — Fetch and safely fast-forward enrolled owner main checkouts

Preserves local commits and overlapping edits; blocked results name files and modification age. Never stashes or resets.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Per-checkout current, updated, blocked or unavailable results with blockers and ageSeconds
400 Invalid request
401 Operator authentication required
409 Repository enrollment refused

POST /v1/checkouts/reclaim-caches — Reclaim verified caches in clean inactive enrolled linked worktrees

Manual only. Six-hour retention; complete native process cwd and pane inventories. Removes ignored package-manager node_modules and CACHEDIR.TAG Rust target, at most 32 per sweep. Keeps commits, source edits and logs; unknown observations refuse.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Reclaimed cache paths and kept reasons, or unavailable census
400 Invalid request
401 Operator authentication required
409 Unregistered repository refused
503 Cache reclamation unavailable

POST /v1/checkouts/prune — Preserve evidence and remove one landed clean inactive enrolled worktree

Landed means merged, on main by content (git cherry), or a recorded safe_to_drop decision for its exact HEAD, whose commits stay under refs/clankie/dropped-worktrees/. Fetches main, copies ignored .local evidence, rechecks cwd and foreground cwd of local panes, and uses git worktree remove without force. Deletes only merged branches. Main and runtime trees stay protected.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Removed, kept or unavailable result with evidencePath and branchDeleted when applicable
400 Invalid request
401 Operator authentication required
409 Enrollment or nested-worktree protection refused

POST /v1/checkouts/decide — Record a judgment of one linked worktree's unlanded work

Records worth_landing or safe_to_drop with a one-line reason for the worktree's current HEAD. Doctor and tidy show it; a new commit invalidates it. Never removes anything.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 The recorded decision with HEAD, unlanded commit and uncommitted file counts
400 Invalid request
401 Operator authentication required
409 Not a registered linked worktree, or its state is unreadable

POST /v1/integrate — Compose, gate and land an ordered approved commit batch

Source-checkout service only. Run returns a durable request receipt immediately; poll status. Compatible requests waiting during a gate share batches of at most three. Conflicting members roll back; failed shared gates retry members individually, alternating with waiting work. Waiting and active isolating requests can be cancelled before landing; a gate containing a withdrawn input cannot land, even if green. Status exposes progress.queuePosition, progress.isolationChain and a conditional progress.estimatedCompletionAt based on recent completed gates (null without measurements). Status without an id returns running batches, waiting requests, the last result and interrupted work. Independent clones and detached core/app sibling worktrees install real packages and run pnpm check with private home, state, credentials and caches. Only the recorded zero-exit exact HEAD may land. Core pushes first; app failure retains partial core-landed/app-pending evidence. Revert selects a passed batch via restore and creates a new commit restoring its tree. No force push or automatic push retry. Each active attempt automatically holds runtime updates until its safe point, bounded at 60 minutes. Updates wait on these holds even past a deferred dueAt; update status names each integrationBatchId. Waiting and accepted deploys fence new attempts. Interrupted newly accepted requests recover once with the same approved commits and a lead notice. Recovery checks remote main before pushing and records an already-present candidate without another send. Historical requests without recovery metadata and second interruptions require review. Deploy holds protect the running service from runtime updates and never gate landing. A hold names its minutes (1-60) and lifts on its own at expiresAt with an expire receipt; the runtime canary's own holds end with their canary. Releases and expiries return receipts naming the holder, actor and reason. Only the authenticated operator can invoke this route.

Bearer: operator

Request body (required JSON)

A JSON value.

Status Meaning
200 Durable request receipt, queue or holds; inspect ok and batch.state for failures/partial landing (application/json)
400 Malformed request
403 Actual operator required
409 Unknown record
503 Repository integration unavailable

GET /v1/runtime-update — Read runtime-update status and current deploy holds

Bearer: operator

In Name Required Type Description
query ref no string Fetch and preview this target, including new commit count and latest summaries
Status Meaning
200 Runtime boot identity
403 Operator required
503 Runtime updater unavailable

POST /v1/runtime-update — Admit a local pinned-runtime deployment after the deploy-hold check

Bearer: operator

Request body (optional JSON)

A JSON object.

Status Meaning
202 Accepted durable update
400 Invalid update request
403 Operator required or revoked
409 Named deploy hold or other refusal; detail describes hold/admission failures; accepted false names blockedReason update-in-progress or runtime-maintenance-busy
503 Runtime updater unavailable

POST /v1/runtime-update/cutover — Confirm an idle scheduled release cutover after staging

Only the exact installing scheduled operation and running boot may act. Rechecks enabled and idle state. Waiting retains staging without stopping services. Ready closes turn admission and begins idle shutdown before the helper stops services and switches current. Uncertainty authorizes no stop.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Exact operation and boot with ready or waiting result (application/json)
400 Invalid cutover request
403 Operator required or revoked
409 Scheduled operation or running boot changed
503 Scheduled cutover unavailable

GET /v1/model-keys — List supported providers, models, stored-key status and captain selection

Owner operator bearer or active device with terminalControl only. Public gateway calls require the encrypted envelope. Shares the CLI model catalog and config. Returns no credentials or endpoint headers. Cache-Control no-store.

Bearer: operator or device

Status Meaning
200 Secret-free model catalog and selection (application/json)
401 authentication_required
403 forbidden — terminalControl required
503 unavailable

GET /v1/model-keys/subscriptions — List providers signed in through an account (OAuth or subscription) instead of an API key

Owner operator bearer or active device with terminalControl only. Public gateway calls require the encrypted envelope. Returns provider ids and names only; no tokens, expiry or account metadata. A separate read so clients parsing the strict model catalog never meet a new field. Cache-Control no-store.

Bearer: operator or device

Status Meaning
200 Providers signed in through an account (application/json)
401 authentication_required
403 forbidden — terminalControl required
503 unavailable

GET /v1/model-keys/subscriptions/methods — List currently supported provider subscription sign-in methods

Bearer: operator or device

Status Meaning
200 Policy-filtered providers and browser or device methods (application/json)
401 authentication_required
403 forbidden
503 unavailable

POST /v1/model-keys/subscriptions/start — Start a provider sign-in for the authenticated initiating principal

Reuses console sign-in helpers. Poll status for the URL and optional code, then open it in the initiating client's browser. Browser callbacks reach this Mac; phones use the device method. Credentials and the selected catalog model are committed together after a fresh authority check. Claude subscription login remains unsupported. No-store; no raw provider errors.

Bearer: operator or device

Request body (required JSON)

A JSON object.

Status Meaning
200 New pending interaction (application/json)
400 malformed or unsupported provider/model
401 authentication_required
403 forbidden
409 busy
503 unavailable

POST /v1/model-keys/subscriptions/status — Read the initiating principal's sign-in interaction

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Pending URL/code, committing write, or terminal result (application/json)
400 malformed
401 authentication_required
403 forbidden
404 session_not_found
503 unavailable

POST /v1/model-keys/subscriptions/cancel — Cancel a pending sign-in; an admitted credential write finishes as committing

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Cancelled or already committing/terminal interaction (application/json)
400 malformed
401 authentication_required
403 forbidden
404 session_not_found
503 unavailable

GET /v1/model-keys/options — List providers usable without key entry and the running model's reasoning effort

Owner operator bearer or active device with terminalControl only. Public gateway calls require the encrypted envelope. Returns provider ids and effort levels only; no credentials. A separate read so clients parsing the strict model catalog never meet a new field. Cache-Control no-store.

Bearer: operator or device

Status Meaning
200 Usable providers and the running model's effort (application/json)
401 authentication_required
403 forbidden — terminalControl required
503 unavailable

POST /v1/model-keys/effort — Set or clear the running model's reasoning effort for the next turn

Owner operator bearer or active device with terminalControl only. Public gateway calls require the encrypted envelope. Writes the same config as clankie effort set; null returns the model to its default. An effort the model does not accept, or no running model, is unsupported_model. Cache-Control no-store.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Success (application/json)
400 Malformed input, or an effort the running model does not accept (application/json)
401 authentication_required
403 forbidden — terminalControl required
413 malformed — body exceeds 16 KiB
503 unavailable

POST /v1/model-keys/set — Store or replace a write-only provider API key

On a self-hosted Mac, device key entry returns forbidden when shared Clankie readiness is true. Operator key management and hosted behavior remain unchanged. The write rechecks readiness and authority. Owner operator bearer or active device with terminalControl only. Public gateway calls require the encrypted envelope. No key, provider error text, or generated text is returned or logged. Cache-Control no-store. Validation uses a fixed prompt, 16 output tokens, no retries and a 15-second deadline; the provider may bill this request. Set does not validate implicitly.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Success (application/json)
400 Malformed input, unsupported provider/model, missing key, failed or timed-out validation (application/json)
401 authentication_required
403 forbidden — terminalControl required
413 malformed — body exceeds 16 KiB
503 unavailable

POST /v1/model-keys/validate — Validate the stored key with a bounded provider call

Owner operator bearer or active device with terminalControl only. Public gateway calls require the encrypted envelope. No key, provider error text, or generated text is returned or logged. Cache-Control no-store. Validation uses a fixed prompt, 16 output tokens, no retries and a 15-second deadline; the provider may bill this request. Set does not validate implicitly.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Success (application/json)
400 Malformed input, unsupported provider/model, missing key, failed or timed-out validation (application/json)
401 authentication_required
403 forbidden — terminalControl required
413 malformed — body exceeds 16 KiB
503 unavailable

POST /v1/model-keys/select — Select the captain model for the next turn

Owner operator bearer or active device with terminalControl only. Public gateway calls require the encrypted envelope. No key, provider error text, or generated text is returned or logged. Cache-Control no-store. Validation uses a fixed prompt, 16 output tokens, no retries and a 15-second deadline; the provider may bill this request. Set does not validate implicitly.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Success (application/json)
400 Malformed input, unsupported provider/model, missing key, failed or timed-out validation (application/json)
401 authentication_required
403 forbidden — terminalControl required
413 malformed — body exceeds 16 KiB
503 unavailable

POST /v1/model-keys/remove — Remove a stored API key without removing OAuth or environment fallback

Owner operator bearer or active device with terminalControl only. Public gateway calls require the encrypted envelope. No key, provider error text, or generated text is returned or logged. Cache-Control no-store. Validation uses a fixed prompt, 16 output tokens, no retries and a 15-second deadline; the provider may bill this request. Set does not validate implicitly.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Success (application/json)
400 Malformed input, unsupported provider/model, missing key, failed or timed-out validation (application/json)
401 authentication_required
403 forbidden — terminalControl required
413 malformed — body exceeds 16 KiB
503 unavailable

GET /v1/accounts/codex — List discovered local Codex identities and their homes

Owner-authorized. The same identity-keyed discovery as worker accounts and usage. Native account/read uses refreshToken:false; identity, plan and usage only. Multiple homes signed into one identity share one account. Missing or stale usage is unknown.

Bearer: operator or device

Status Meaning
200 Stable identity keys, signed-in email, current homes, rate windows and headroom
401 Authentication required
403 Owner authority required

POST /v1/accounts/codex — Register or remove an owner's local Codex home

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Registration updated; credentials and home are unchanged
400 Invalid or duplicate account
401 Authentication required
403 Owner authority required

GET /v1/accounts — Read the body-owned GitHub, Linear and Google account catalog

Owner operator bearer or active device with terminalControl only (ADR 0232). Public gateway calls require the encrypted envelope. Never returns or logs a token or provider error text. Cache-Control no-store. Includes service purpose, permission disclosure, account identity, granted scopes, recovery status and selected Drive file IDs. An unconfigured Google row needs operator OAuth client setup; it does not request a customer credential.

Bearer: operator or device

Status Meaning
200 Success (application/json)
401 authentication_required
403 forbidden — terminalControl required
503 unavailable

POST /v1/accounts/github/start — Start a GitHub device flow; return the user code and verification URL

Owner operator bearer or active device with terminalControl only (ADR 0232). Public gateway calls require the encrypted envelope. Never returns or logs a token or provider error text. Cache-Control no-store. The device code stays on the body. Unconfigured without a GitHub OAuth client ID.

Bearer: operator or device

Request body (required JSON)

A JSON object.

Status Meaning
200 Success (application/json)
400 A closed error code (malformed, unconfigured, unknown_flow, expired, denied, provider_rejected) (application/json)
401 authentication_required
403 forbidden — terminalControl required
503 unavailable

POST /v1/accounts/github/poll — Poll a GitHub device flow; returns pending, connected or a closed error

Owner operator bearer or active device with terminalControl only (ADR 0232). Public gateway calls require the encrypted envelope. Never returns or logs a token or provider error text. Cache-Control no-store. Polls faster than GitHub's interval are answered by the body without calling GitHub.

Bearer: operator or device

Request body (required JSON)

A JSON object.

Status Meaning
200 Success (application/json)
400 A closed error code (malformed, unconfigured, unknown_flow, expired, denied, provider_rejected) (application/json)
401 authentication_required
403 forbidden — terminalControl required
503 unavailable

POST /v1/accounts/linear/start — Start registered Linear app OAuth with S256 PKCE; return the authorize URL

Owner operator bearer or active device with terminalControl only (ADR 0232). Public gateway calls require the encrypted envelope. Never returns or logs a token or provider error text. Cache-Control no-store. The PKCE verifier stays on the body. Tokens use the separate linear-api broker entry and GraphQL tracker, never MCP. Unconfigured without a redirect URI.

Bearer: operator or device

Request body (required JSON)

A JSON object.

Status Meaning
200 Success (application/json)
400 A closed error code (malformed, unconfigured, unknown_flow, expired, denied, provider_rejected) (application/json)
401 authentication_required
403 forbidden — terminalControl required
503 unavailable

POST /v1/accounts/linear/complete — Hand back Linear's redirect code; the body exchanges it with its verifier

Owner operator bearer or active device with terminalControl only (ADR 0232). Public gateway calls require the encrypted envelope. Never returns or logs a token or provider error text. Cache-Control no-store. state is single use.

Bearer: operator or device

Request body (required JSON)

A JSON object.

Status Meaning
200 Success (application/json)
400 A closed error code (malformed, unconfigured, unknown_flow, expired, denied, provider_rejected) (application/json)
401 authentication_required
403 forbidden — terminalControl required
503 unavailable

POST /v1/accounts/linear/app — Connect a workspace-owned Linear app for worker names and portraits

Verifies an app actor and workspace before replacing the Linear credential. Owner operator bearer or active device with terminalControl only. Public gateway calls require the encrypted envelope. Client credentials and tokens stay in the broker and are never returned or logged. Cache-Control no-store. Enable client credentials tokens on the workspace's Linear OAuth application.

Bearer: operator or device

Request body (required JSON)

A JSON object.

Status Meaning
200 Verified connection with actor and workspace; no credentials (application/json)
400 malformed or provider_rejected; previous connection retained (application/json)
401 authentication_required
403 forbidden — terminalControl required
503 unavailable

POST /v1/accounts/google/start — Start body-owned Google consent with state and S256 PKCE

Owner operator bearer or active device with terminalControl only. Public gateway calls require the encrypted envelope. The body retains the verifier and keeps all client secrets and tokens in its broker. Cache-Control no-store. Gmail requests gmail.readonly plus openid email. Calendar requests calendar.calendarlist.readonly and calendar.events.readonly plus openid email. Drive requests only drive.file and opens Google Picker with prompt consent, trigger_onepick true and include_granted_scopes false. Google's selected-file grant permits editing; Clankie's implemented tools only read selected files. All flows request offline access. Client setup and browser consent are required.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 One-time state, registered redirect, consent URL and expiry; no token or verifier (application/json)
400 Closed failure code, including malformed, unconfigured or unavailable (application/json)
401 authentication_required (application/json)
403 forbidden — terminalControl required (application/json)
413 malformed — body exceeds 16 KiB (application/json)
503 unavailable — body, broker or current owner authority could not be verified (application/json)

POST /v1/accounts/google/complete — Exchange the one-time Google code on the tenant body

Owner operator bearer or active device with terminalControl only. Public gateway calls require the encrypted envelope. State is single use, bound to this body's pending provider, OAuth application and expiry. The body verifies provider identity and granted scopes before storing credentials; no tokens or provider errors escape. Gmail and Calendar accept provider, state and code only. Drive also requires a nonempty unique pickedFileIds array, validated from Google Picker's picked_file_ids callback. These IDs bound the files the implemented Drive read tools can access. Cache-Control no-store. Authorization codes belong in the JSON body, never API request URLs or logs.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Verified account connection and granted permissions; no credential (application/json)
400 Closed failure code, including malformed, unknown_flow, expired, unconfigured, provider_rejected or unavailable (application/json)
401 authentication_required (application/json)
403 forbidden — terminalControl required (application/json)
413 malformed — body exceeds 32 KiB (including selected file IDs) (application/json)
503 unavailable — body, broker or current owner authority could not be verified (application/json)

POST /v1/accounts/google/check — Refresh and verify the selected Google account's authorized access

Owner operator bearer or active device with terminalControl only. Public gateway calls require the encrypted envelope. The body refreshes the selected grant under the credential-store lock and verifies its identity, scopes and disconnect epoch. Returns catalog metadata and last-check status without exposing credentials. Invalid grants require renewed consent; provider outages do not imply revocation. Cache-Control no-store.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Current verified account connection and check metadata; no credential (application/json)
400 Closed failure code, including malformed, unconfigured, denied, provider_rejected or unavailable; list accounts for recovery status (application/json)
401 authentication_required (application/json)
403 forbidden — terminalControl required (application/json)
413 malformed — body exceeds 16 KiB (application/json)
503 unavailable — body, broker or current owner authority could not be verified (application/json)

POST /v1/accounts/disconnect — Disconnect locally and report actual provider revocation

Owner operator bearer or active device with terminalControl only (ADR 0232). Public gateway calls require the encrypted envelope. Never returns or logs a token or provider error text. Cache-Control no-store. revoked is false when the provider could not confirm revocation; local access is disabled either way and manageUrl names where to review the grant. Disconnecting any Google provider disables all three Google connections on this body. Its broker may retain a refresh credential solely for bounded revocation retries; catalog revocationPending remains true until Google confirms revocation. Hosted GitHub disconnect never uses a developer app secret and reports revoked false. Owner-run self-hosted GitHub revocation deletes only the stored token, never an app grant.

Bearer: operator or device

Request body (required JSON)

A JSON object.

Status Meaning
200 Success (application/json)
400 A closed error code (malformed, unconfigured, unknown_flow, expired, denied, provider_rejected) (application/json)
401 authentication_required
403 forbidden — terminalControl required
503 unavailable

POST /v1/accounts/email/connect — Choose his Clankie mailbox in one step and return the email row

Owner operator bearer or active device with terminalControl only (ADR 0232). Public gateway calls require the encrypted envelope. Cache-Control no-store (ADR 0242). Asks Clankie's mail service first; only when it answers this install's Clankie account with his address does settings.email.provider become clankie, with that address as the from-address. A stored IMAP password is kept, so choosing IMAP again needs no new sign-in. account_required: not signed in to a Clankie account, or the service refused it (clankie login); unavailable: the service could not be reached; unconfigured: this install has no Clankie mail service. Settings are unchanged then.

Bearer: operator or device

Request body (required JSON)

A JSON object.

Status Meaning
200 Switched; the email row as it now stands (application/json)
400 A closed error code (malformed, unconfigured, unavailable, account_required) (application/json)
401 authentication_required
403 forbidden — terminalControl required
503 unavailable

GET /v1/connections — Inspect execution runtimes and verified Linear identity

Bearer: operator

Status Meaning
200 Current runtime health and recorded account identity
401 Operator authentication required
503 Operator authentication unavailable

GET /v1/runtime-connections — Inspect the default fleet and named execution connections

Bearer: operator

Status Meaning
200 Configured endpoints and freshly probed health
401 Operator authentication required
503 Operator authentication unavailable

POST /v1/runtime-connections — Connect a Herdr runtime or configure owner execution policy

Resolves an explicit session or socket and pins that endpoint to the ID. Reconnection cannot retarget an existing ID. action=workspaces replaces additional repository/directory approvals for a named or default runtime; it never starts or stops workers. action=capacity sets one runtime limit; Unset limits default to 16; null clears a limit to unlimited; zero pauses new admission.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Persisted connection
400 Invalid connection
401 Operator authentication required
409 Endpoint unavailable, identity conflict or coordinator synchronization failed; inspect state before retrying
503 Execution management or authentication unavailable

DELETE /v1/runtime-connections/{id} — Disable a named execution connection while preserving workers and route identity

Bearer: operator

In Name Required Type Description
path id yes string
Status Meaning
200 Connection disabled and coordinator routes synchronized
401 Operator authentication required
409 Unknown connection or synchronization unconfirmed; inspect state before retrying
503 Execution management or authentication unavailable

POST /v1/tracker/import/linear — Mirror a Linear project into a named scratch built-in tracker

Read-only on the broker-connected Clankie Linear app. Every collection is paginated, including archived issues. Imports provider IDs and VUH keys, comments/replies, history, labels, relations, milestones, documents, updates and team cycles. Uploads enter the evidence store with rewritten links. Shares the background request budget. Scratch stores live under tracker-imports, separate from the live tracker. Writes import-report.json and returns counts, skips, actor mappings and created/updated/unchanged totals. Does not switch the active backend. Multi-team mappings are refused.

Bearer: none

Request body (required JSON)

A JSON object.

Status Meaning
200 Import report; an unchanged rerun writes no tracker records
400 Invalid project UUID or scratch name
401 Operator authentication required
422 Import failed; detail includes any request-budget retry time
503 Import capability unavailable

POST /v1/tracker/mirror/linear — Enable, disable or inspect a scratch import's Linear webhook mirror

Owner-enabled only; nothing mirrors by default. Enabling requires a scratch store imported from the named project. Accepted signed Linear webhooks for that project then apply through the import mapper once per Linear event id, attributed to the original actor. The mirror refuses built-in writes until cutover. Drift (an event naming an unknown record) triggers a scoped re-read through the connected account within the background request budget and is reported. Status returns counters, the applied event count and drift reports.

Bearer: none

Request body (required JSON)

A JSON object.

Status Meaning
200 The mirror binding
400 Invalid project UUID
401 Operator authentication required
409 No matching scratch import
503 Mirror capability unavailable

POST /v1/tracker/cutover/linear — Cut a World project over from Linear to the built-in tracker, or switch it back

Mirror 3 (VUH-1987). A dry run reads only (Linear included) and returns the plan: per-type counts against a fresh read-only Linear capture, the mirror's state, the store, binding and convention changes with backup paths, refusals and the switch-back command. Without dryRun the plan is applied (mirror disabled, scratch import promoted to the live store, trackerProjectId bound, convention switched to builtin) or refused with HTTP 409 and nothing changed. switchBack restores the exact pre-cutover convention, binding and store and keeps the pilot store.

Bearer: none

Request body (required JSON)

A JSON object.

Status Meaning
200 The plan (dry run) or the applied plan with its steps
400 Invalid request; a cutover names its scratch import and Linear project
401 Operator authentication required
409 Refused; the body is the plan with its refusals
422 A step failed; the active record names the steps already applied
503 Cutover capability unavailable

POST /v1/work — Read and write work items in the repo's own tracking convention

One contract over Linear, GitHub issues, the repo's own Markdown directory, or .clankie/work/ (ADR 0191). action is repos, discover, init, list, show, project, create, update, attach, write or write_receipt. The two narrow owner operations take request {repoId,itemId,requestId,command}; receipt reads omit command. The command assigns work-metadata owner, adds/removes a role label or appends a blocker. Their applied/refused/uncertain receipt always carries the UUID; repeated IDs and receipt reads never replay a write. A path names and registers a local repo; registered repos are readable from paired devices through the work_repos, work_items and work_project operator ops. work_items statusVersion=2 opts into backlog and native milestone metadata; older requests receive backlog as todo. project reads planned milestones, shipped v* tags/published versions and Linear initiative goals. init accepts releaseSource (tags, milestones, both; default both) and releaseLane (default repository). Unavailable facts are explicit; store builds are not inferred. list takes optional status, owner and label (case-insensitive) filters; items carry the backend's labels (ADR 0208).

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 The repos
400 Invalid request
401 Operator authentication required
404 Unknown repo or work item
409 The repo needs its convention decided
502 The backend refused or failed the request

GET /v1/linear/routes — Inspect configured Linear project lead chats

Bearer: operator

Status Meaning
200 Project destinations; unconfigured projects use global-default with their name (application/json)
401 Operator authentication required

PUT /v1/linear/routes — Replace Linear project destinations with existing ordinary global chats

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Saved project destinations
400 Malformed or duplicate project destinations
401 Operator authentication required
409 A destination is not an existing ordinary global chat

GET /v1/linear/deliveries — Inspect offered Linear wake batches, destinations and target consumption receipts

Offered batches may have failed before delivery. receivedAt is set only by the target chat confirming its original wake; native transport ACKs alone do not mark Linear notifications read. Recoveries list missing-receiver holds, pending event IDs and durable per-event rerouted or already_handled resolutions to current lead destinations. Uncertain native takes remain pinned to their original recipient.

Bearer: operator

Status Meaning
200 Up to 100 recent offered batches and receipts (application/json)
401 Operator authentication required

GET /v1/linear/target — Inspect the ordinary chat selected for Linear activity

Bearer: operator

Status Meaning
200 Current live wake target (application/json)
401 Operator authentication required
503 Operator authentication unavailable

PUT /v1/linear/target — Select an existing ordinary global chat without restarting

Sets linearWebhook.wakeConversationId, default global-default. The target must be an existing ordinary global chat; its attached native operator seat may drive it. Changing the target applies to new activity without moving or replaying history. Selecting a target grants no additional authority.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Persisted live wake target (application/json)
400 Invalid target
401 Operator authentication required
409 Target is not an available ordinary global chat
503 Settings or operator authentication unavailable

GET /v1/auto/rounds — Read the Auto round record, newest first

Each Auto round's measured velocity per project (ADR 0270) and whether its wake was delivered. Closures since the last milestone split owner-facing, tooling, unlinked and unclassified; started issues (cap null until a WIP cap exists); churn by bucket; per-day facts for the window and the last seven local days. Any part the service could not measure is {state:"unknown", reason}, never zero. A round whose wake never settled has a null delivery. Reads the service-local record only; no tracker or git calls.

Bearer: operator

In Name Required Type Description
query includeStaffing no value Include additive staffing facts and totals (VUH-2335); historical rounds may omit them.
query includeAutoUpdates no value Include automatic-update policy and evidenced progress candidates and requests
query project no string
query limit no integer, 1–200, default 20
Status Meaning
200 Recorded rounds, filtered to one project when asked (application/json)
400 Invalid project or limit
401 Operator authentication required
503 Round record or operator authentication unavailable

GET /v1/linear/request-budget — Read rolling provider request usage and background read throttling

Counts actual HTTP attempts across MCP and the API tracker per workspace and actor. The default 5000/hour cap reserves one request; provider remaining/reset headers can lower available headroom. At 50% a native runtime warning is emitted once until usage recovers; at 80% background reads share a one-minute minimum interval. Writes and webhook context retain priority within the hard cap. This diagnostic makes no provider calls.

Bearer: operator

Status Meaning
200 Service-local rolling counts and available provider rate-limit observations (application/json)
401 Operator authentication required
503 Budget or operator authentication unavailable

GET /v1/linear/wake — Inspect actor and activity wake rules

Live rules apply to new signed activity without replay. The follow switch still gates wakes. Relayed GET/POST retain the original device authority.

Bearer: operator or device

Status Meaning
200 Current snapshot and SHA-256 revision; Cache-Control no-store (application/json)
401 Authentication required
403 Current owner or Take Control authority required
503 Settings unavailable

POST /v1/linear/wake — Save validated settings with revision fencing

The expectedRevision from GET is required. Validation and current owner authority are checked before persistence. No automatic conflict retry.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Saved snapshot and revision (application/json)
400 Invalid or unfenced settings update
401 Authentication required
403 Owner authority required
409 Stale revision
503 Settings unavailable

PUT /v1/linear/wake — Save validated settings with revision fencing

PUT is the local compatibility alias; devices use POST. The expectedRevision from GET is required. Validation and current owner authority are checked before persistence. No automatic conflict retry.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Saved snapshot and revision (application/json)
400 Invalid or unfenced settings update
401 Authentication required
403 Owner authority required
409 Stale revision
503 Settings unavailable

GET /v1/linear/follow — Inspect following and webhook readiness

Following requires the configured signed webhook. Missing URL or secret refuses enablement. Passive activity remains visible without waking.

Bearer: operator or device

Status Meaning
200 Current snapshot and SHA-256 revision; Cache-Control no-store (application/json)
401 Authentication required
403 Current owner or Take Control authority required
503 Settings unavailable

POST /v1/linear/follow — Save validated settings with revision fencing

The expectedRevision from GET is required. Validation and current owner authority are checked before persistence. No automatic conflict retry.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Saved snapshot and revision (application/json)
400 Invalid or unfenced settings update
401 Authentication required
403 Owner authority required
409 Stale revision
503 Settings unavailable

PUT /v1/linear/follow — Save validated settings with revision fencing

PUT is the local compatibility alias; devices use POST. The expectedRevision from GET is required. Validation and current owner authority are checked before persistence. No automatic conflict retry.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Saved snapshot and revision (application/json)
400 Invalid or unfenced settings update
401 Authentication required
403 Owner authority required
409 Stale revision
503 Settings unavailable

GET /v1/worker-grants/ — List worker grant records without bearer tokens

Bearer: operator

Status Meaning
200 Grant records including account identity and revocation status
401 Operator authentication required
503 Worker access service unavailable

POST /v1/worker-grants/ — Issue a scoped grant for one verified connected account

Work ID is provenance. Exact top-level argument restrictions enforce resource boundaries; omitted arguments remain unrestricted. A fleet grant binds access to an authenticated fleet link until revoked; a manual grant requires private bearer delivery.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
201 Grant record and private worker bearer token; Cache-Control no-store
400 Invalid grant request
401 Operator authentication required
409 Account unverified or tool unavailable
503 Worker access service unavailable

DELETE /v1/worker-grants/{id} — Durably revoke one worker grant and close its sessions

Bearer: operator

In Name Required Type Description
path id yes string
Status Meaning
200 Revoked grant record
401 Operator authentication required
404 Grant unavailable

GET /v1/worker-grants/linear/account — Inspect disconnected, unverified or verified Linear account identity

Bearer: operator

Status Meaning
200 Account status and verified identity when available
401 Operator authentication required

POST /v1/worker-grants/linear/account — Verify the stored Linear account's provider user and workspace

Verifies API keys via GraphQL and OAuth via Linear's official MCP identity tools. Credentials are never migrated automatically.

Bearer: operator

Status Meaning
200 Verified account identity
401 Operator authentication required
409 Verification unavailable or failed

POST /v1/hosted/operator — Dispatch as an account-paired hosted operator device

Encrypted gateway carrier required remotely. Checks active device session, server-recorded operator pairing purpose and Take Control grant. No operator bearer is exported. The shared hosted-device allowlist permits chat, fleet, terminal, model, keys, persona and connections. Restart, reset and deprovision require account authority, including through the legacy device relay. The inner route keeps its own validation. Revocation is rechecked before returning a parked page.

Bearer: device

Request body (required JSON)

A JSON object.

Status Meaning
200 Inner operator route response
400 Invalid inner request or forbidden route
401 Missing
403 Not an account-paired operator device

POST /v1/runtime-connections/{id}/prepare — Prepare Clankie's own harness setup on an existing machine

Resolves policy from the verified service-local source workspace and checks the target's current link independently. Lead setup requires an already-linked target. Owner policy or a newly supplied source script requires the caller's ownerApproved consent claim. The service records that claim without verifying human confirmation. expectedMachineRevision pins the exact registered target shown to the caller; omission claims the alias's current target. This retains operator authority and never restarts or steers existing lanes.

Bearer: operator

In Name Required Type Description
path id yes string Existing runtime connection ID

Request body (required JSON)

A JSON object.

Status Meaning
200 Harness preparation result and the caller's consent claim (application/json)
400 Malformed request
401 Operator authentication required
403 Owner approval or existing linked target required
409 Preparation or context verification failed

GET /v1/operator/work-tracker — Read the new-project default or one project's saved tracker

Bearer: operator or device

In Name Required Type Description
query projectId no string, matching ^[a-z][a-z0-9_-]{0,63}$
Status Meaning
200 WorkTrackerSettingsSnapshotSchema with current selection, default, effect and connection status
403 Owner authority required
409 Project or workspace unavailable

POST /v1/operator/work-tracker — Read, preview or set the new-project default or a project's work tracker

Owner-only API shared by every surface. Built-in and repo files need no account; Linear and GitHub use existing connected accounts. Project changes require a matching preview revision and confirmRetainItems. Existing items stay in their old tracker; nothing migrates or is deleted. Discord forum remains a future built-in view (VUH-2531).

Bearer: operator or device

Request body (required JSON)

A JSON object.

Status Meaning
200 WorkTrackerSettingsSnapshotSchema; revision, default, current selection/source, proposed selection, connection status, effect on existing items and confirmation requirement
400 Malformed selection or command
401 Authentication required
403 Owner authority required
409 Stale preview, explicit confirmation required, disconnected account or unavailable target/workspace; no items migrated
503 Settings are read-only or unavailable

GET /v1/operator/fleet-settings — Read fleet size, model mode and owner working preferences

Closure, machineSetup, commit and push default to lead; official releases default to owner, verification to change_run_read, reporting to Short and plain. workingPreferences=true advertises the five new controls; old responses may omit them. Existing owner or Take Control device authority is required; preferences confer no credentials or new access.

Bearer: operator or device

Status Meaning
200 Current fleet settings and SHA-256 revision (application/json)
401 Owner authentication required
403 Caller lacks owner authority

POST /v1/operator/fleet-settings — Update fleet budget and working preferences with revision fencing

Omitted leaves retain their value. A null autonomy leaf restores its global default. Release mode and rule are replaced together. Retired size, models, verification, reportingStyle and hire.effort edits are rejected. Saved values remain in the read-only includeWorkPolicy=true receipt.

Bearer: operator or device

Request body (required JSON)

A JSON object.

Status Meaning
200 Updated fleet snapshot and revision
400 Malformed request
401 Owner authentication required
403 Caller lacks owner authority
409 Settings or owner authority changed before commit

GET /v1/operator/fleet-settings/hire — Read the fleet's hire defaults (harness and model; legacy effort read-only)

An omitted field is "no preference"; Clankie chooses per hire. The SHA-256 revision covers the whole stored hire profile, so an account, subagent, delegation or placement change also fences writes. Owner or Take Control device authority (FleetHireDefaultsSnapshotSchema).

Bearer: operator or device

Status Meaning
200 schemaVersion=1, revision and hire {harness?, model?, effort?}
401 Authentication required
403 Owner authority required

POST /v1/operator/fleet-settings/hire — Set or clear fleet hire defaults

Accepts schemaVersion=1, expectedRevision and changes {harness?, model?}. The value auto clears a field; effort accepts only auto to clear a retired saved value. Any field patch removes legacy global effort while preserving it in the retirement receipt and retaining other profile fields (UpdateFleetHireDefaultsSchema).

Bearer: operator or device

Request body (required JSON)

A JSON object.

Status Meaning
200 Updated hire defaults snapshot
400 Malformed change
401 Authentication required
403 Owner authority required
409 Stale revision or authority changed during the write

GET /v1/worker-accounts — Read one machine's worker accounts and verified Pi profile

Discovered identity-keyed accounts and their homes, sign-in, email, plan, usage headroom, re-sign notices, verified Pi model references, holds and whether Clankie would hire now (MachineWorkerAccountsSchema). Duplicate homes share one account; preferences remain with the identity after a home re-signs. Omit fleet for this machine; fleet names a runtime connection, the only query accepted. Owner or Take Control device authority.

Bearer: operator or device

In Name Required Type Description
query fleet no string, matching ^[a-z][a-z0-9-]{0,63}$
Status Meaning
200 The machine's accounts
400 Invalid fleet
401 Authentication required
409 The machine could not be read
503 Worker accounts unavailable

GET /v1/worker-accounts/holds — Read held worker accounts and current revision

Holding prevents automatic selection; naming the account explicitly still permits a hire. Hold and release update one account and return all current holds.

Bearer: operator or device

Status Meaning
200 Current snapshot and SHA-256 revision; Cache-Control no-store (application/json)
401 Authentication required
403 Current owner or Take Control authority required
503 Settings unavailable

POST /v1/worker-accounts/holds — Save validated settings with revision fencing

The expectedRevision from GET is required. Validation and current owner authority are checked before persistence. No automatic conflict retry.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Saved snapshot and revision (application/json)
400 Invalid or unfenced settings update
401 Authentication required
403 Owner authority required
409 Stale revision
503 Settings unavailable

GET /v1/usage — Read account usage, optional native fleet context spend and where the next hires go

Each registered Claude profile and Codex account with identity, plan, headroom and its usage windows (percent used, length, reset, source and observation age), read through each harness's own CLI and shared for a minute across surfaces; refresh=1 reads again now. allocation.accounts ranks each eligible account per harness by spare capacity per day (planWeight, tier, remaining, sparePerDay, window, burnPerDay, resetsAt, runsOut, rank, reason); allocation.recommendations names the next automatic hire per harness with its reason (ADR 0261). settings carries the overlay and run-out warning settings with their revision. Never credentials (UsageReportSchema). fleet=1 adds an on-demand local native-transcript ledger in fleet, cached for one minute independently of account polling. Each session and UTC day reports modelCalls, contextTokens, medianContextTokens, aboveBudgetContextTokens, aboveBudgetTokenShare, above400KContextTokens, compactions and foregroundSleepCalls. Claude input includes cache reads and writes; Codex uses token_count input (cached input is already included). Native message/response IDs deduplicate streaming records and retained copies; older Codex responses use repeated cumulative snapshot identity. Children have separate subagent rows. Role attribution comes from the native census, hire journal and lead relaunch journal; unknown historical roles use the 300K worker review budget and are labeled unknown. Lead budget is 250K. Above-budget share is the fraction of context tokens in calls strictly above that seat budget. Warnings preserve unreadable/malformed sources and unknown attribution. These are raw token volumes; vendor account windows remain independent. days defaults to 7 (1..366); since and days are mutually exclusive; until defaults to now, with a positive interval no longer than 366 days. Ordinary meter reads never scan transcripts.

Bearer: operator or device

In Name Required Type Description
query refresh no string, one of 1
query fleet no string, one of 1
query days no integer, 1–366 Fleet ledger only; rolling days ending at until
query since no string Fleet ledger only; inclusive start
query until no string Fleet ledger only; exclusive end
Status Meaning
200 Usage report with allocation and optional fleet ledger; Cache-Control no-store
400 Invalid fleet ledger query or interval
401 Authentication required
403 Current owner or Take Control authority required
409 The accounts could not be read
503 Usage unavailable on this body

GET /v1/usage/settings — Read the usage overlay and run-out warning settings

display.overlay, allocation.runOutWarning and allocation.runOutWarningHours with their SHA-256 revision (UsageSettingsSnapshotSchema).

Bearer: operator or device

Status Meaning
200 Current settings and revision; Cache-Control no-store
401 Authentication required
403 Current owner or Take Control authority required

POST /v1/usage/settings — Save usage display and run-out warning settings with revision fencing

expectedRevision from GET is required, with display.overlay and/or allocation.runOutWarning (boolean) and allocation.runOutWarningHours (0-168): the lead is woken once per window reset when an account's weekly limit is on pace to run out at least that many hours before it resets (UpdateUsageSettingsSchema).

Bearer: operator or device

Status Meaning
200 Saved settings and revision
400 Invalid or empty settings update
401 Authentication required
403 Owner authority required
409 Stale revision or changed owner authority
503 Settings unavailable

GET /v1/operator/fleet-settings/context — Resolve current project policy and already-linked setup target

Verifies a local source directory and Git worktree separately from the registered target machine. Returns a nonsecret targetRevision hashing the resolved execution descriptor, including transport and session, so consent can be pinned across requests. Machine aliases hash their registration set rather than selecting an arbitrary runtime. Invalid or ambiguous project evidence fails closed. This filesystem route is excluded from hosted-device forwarding.

Bearer: operator or device

In Name Required Type Description
query workingDirectory yes string Existing absolute source directory on the service host
query machine yes string Existing runtime or machine ID
query projectId no string Optional project assertion; must match verified directory membership
Status Meaning
200 Effective policy, matched project and current target observation (application/json)
400 Malformed query
401 Owner authentication required
403 Caller lacks owner authority
409 Context could not be verified or settings changed

GET /v1/operator/reviews — List landing review candidates, newest first

The standing review gate's candidates (ADR 0287) with status, author, reviewer, verdict and any waiver. At most 500. An operator bearer reads and waives but never records a verdict.

Bearer: operator

In Name Required Type Description
query project no string
Status Meaning
200 Candidates (application/json)
400 Malformed query
401 Operator authentication required
403 Caller lacks owner authority
503 Reviews unavailable

GET /v1/operator/reviews/{id} — Read one landing review candidate

With patch=true, also the stored patch bytes, base64.

Bearer: operator

In Name Required Type Description
path id yes string
query patch no string, one of true
Status Meaning
200 The candidate and, when asked, its patch (application/json)
401 Operator authentication required
403 Caller lacks owner authority
404 Unknown candidate
503 Reviews unavailable

GET /v1/operator/reviews/landing — Ask whether one exact patch may land

The landing gate's question (ADR 0287). The service maps the checkout directory to its project. landable is true when the project names no reviewer, the change is empty, or the patch-id is approved or waived. Otherwise status is not_submitted, awaiting_review or changes. clankie review status and pnpm check:landing ask this; the gate exits 3 while landable is false.

Bearer: operator

In Name Required Type Description
query directory yes string
query patchId yes string git patch-id --verbatim of the committed change, or empty.
Status Meaning
200 The landing decision (application/json)
400 Malformed query
401 Operator authentication required
403 Caller lacks owner authority
503 Reviews unavailable

POST /v1/operator/reviews/waivers — Land one exact patch without its project's review

Owner only. Records the owner, the reason and the time on the candidate for exactly this patch-id, and the landing gate then lets that patch land. The service recomputes the patch-id from the bytes and refuses a mismatch. The lead's waive_review tool does the same on the operator lane. Rare by design.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 The waived candidate
400 Malformed waiver or invalid patch
401 Operator authentication required
403 Caller lacks owner authority
409 Patch-id mismatch
503 Reviews unavailable

POST /v1/operator/projects/update — Update project policy while preserving independent inheritance

Each autonomy.fleet leaf overrides its global default independently; null clears only that override and omission retains it. Release mode and rule are one atomic leaf. Responses omit autonomy fields unless includeAutonomy=true; workingPreferences=true then advertises support for the new controls. The expectedRevision fences full project settings even for legacy projections. linearProjectBinding names a connected Linear project by exact UUID, independently of the built-in trackerProjectId. It never changes a saved tracker backend; null clears only the Linear reference. The autonomy-aware view advertises linearProjectBindings=true. review names the standing landing reviewer (ADR 0287); it appears only with includeReview=true.

Bearer: operator or device

In Name Required Type Description
query includeAutonomy no string, one of true Opt into project autonomy overrides and global autonomyDefaults
query includeWorkPolicy no string, one of true Opt into work policy response fields
query includeAutoUpdates no string, one of true Opt into automatic project update settings and capability
query includeReview no string, one of true Opt into the project's standing reviewer (ADR 0287) and projectReview=true

Request body (required JSON)

A JSON object.

Status Meaning
200 Updated project snapshot and revision
400 Malformed request or Linear project not found
401 Owner authentication required
403 Caller lacks owner authority
409 Project settings or owner authority changed
503 Connected Linear project validation unavailable

GET /v1/operator/projects — Read owner project settings and their current revision

Legacy responses omit autonomy and work-policy fields. includeAutonomy=true adds autonomy overrides and defaults. includeWorkPolicy=true adds wipCap, ownerLoop, hiring, projectWorkPolicy=true and a read-only retiredWorkingPreferences receipt. includeAutoUpdates=true adds autoUpdates and projectAutoUpdates=true. includeReview=true adds each project's standing reviewer as review and projectReview=true. Revision always covers the full stored settings.

Bearer: operator or device

In Name Required Type Description
query includeAutonomy no string, one of true Opt into project autonomy overrides and global autonomyDefaults
query includeWorkPolicy no string, one of true Opt into project work policy and retired-value receipt
query includeAutoUpdates no string, one of true Opt into automatic project update settings and capability
query includeReview no string, one of true Opt into the project's standing reviewer (ADR 0287) and projectReview=true
Status Meaning
200 Project settings and SHA-256 revision
401 Owner authentication required
403 Caller is not the owner

POST /v1/operator/projects/create — Create a reviewed project with one canonical local workspace

Owner only. Strict fields are projectId, name, workspacePath, expectedRevision, roles, workerCap, trackerRef, trackerSetup, productPaths, wipCap, ownerLoop, autoUpdates and hiring. The service supplies primary/local workspace identity and its platform. Nullable worker caps inherit; zero is preserved. Retired fleet preferences cannot be created. Optional trackerRef must name primary and .clankie/tracking.json, an existing valid canonical convention unless trackerSetup supplies reviewed work-init inputs for a missing convention. Tracker save precedes settings save; a partial failure can leave only the convention. No automatic retry, account choice, provider project/label creation, remote enrollment, assignments, hires or grants. Rechecks canonical directory/tracker identity, settings revision and owner authority before the existing SettingsStore rename. These asynchronous observations are not cross-process compare-and-swap or atomic authority/filesystem checks. This documents the source contract, not an installed CLI or running-service update.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
201 Saved project settings and current revision
400 Malformed or unsupported creation fields
401 Owner authentication required
403 Caller is not the owner
409 project_create_conflict or project_tracker_unavailable; no automatic retry
413 Request exceeds 16 KiB
503 Settings writes unavailable

POST /v1/operator/projects/remove-workspace — Remove one exact owner-approved workspace registration

Preserves roles, grants and assignments. Refuses tracker-bound workspaces, stale revisions, changed owner authority and concurrent settings changes. Does not delete a directory.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Updated project settings and revision
400 Malformed request
401 Owner authentication required
403 Caller is not the owner
409 Removal conflicts with current settings or authority

POST /v1/fleet/worker-tool-refresh — Refresh worker catalogs through their original native controllers

Without paneId, selects only seats led or hired by the default owner conversation and lists others as skipped-not-owned. Cross-conversation refresh requires explicit paneId and owner authentication. Preserves original threads, receipts and controller identity. Never starts a proof turn, restarts a harness or replays a report. Local Codex catalog-refreshed means its MCP catalog is connected and complete; next-turn model tools and new report delivery remain unverified. Have that same worker call clankie_tools and send one new message_clankie report to prove delivery. Busy requests defer under their original authority; unsupported controllers refuse explicitly.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Per-seat catalog evidence, deferral or refusal; catalog-refreshed is not end-to-end tool delivery proof (application/json)
400 Malformed request
403 Operator authority required or revoked
409 Original catalog refresh failed; inspect its retained evidence before retrying
413 Request exceeds 1 KiB
503 Original-controller catalog refresh unavailable

POST /v1/fleet/worker-tool-restart — Check admission for explicit same-thread worker restart

Explicit operator action. Requires saved results, settled report receipts, known ownership, no draft and a verified native exit controller. Rechecks the original occupant before exit and journals close/resume. Unknown exit or resume receipts remain held; inspect tidy history before retrying. Current local Codex lacks verified native exit and refuses before any close intent; successful automatic restart remains unsupported. Remote workers and Claude are unsupported.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Restarted, refused or failed; a failed original may remain held in tidy history (application/json)
400 Malformed request
403 Operator authority required or revoked
413 Request exceeds 8 KiB
503 Restart unavailable or reply failed; inspect the original operation before retrying

POST /v1/harness-refresh — Refresh existing native worker plugin links locally and on enabled fleet machines

Uses the native harness installer without enrolling new profiles, changing channel policy or restarting panes. The canonical source workspace selects current machineSetup policy; owner mode requires the caller's ownerApproved consent claim, and automatic lead refresh requires an already-linked target. The service records the claim without verifying human confirmation. Current operator authority, source context and each captured fleet destination are revalidated before refresh. Returns per-profile and per-fleet outcomes; ok is false for incomplete installation, missing source setup or unreachable machines.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Plugin refresh receipts, including incomplete outcomes (application/json)
400 Invalid refresh context request
403 Operator required or revoked
409 Source context
503 Harness refresh or policy context unavailable

POST /v1/harness-plugin-version — Tell a running service which worker version the installer shipped

Updates display-only restart flags at the next admitted native client request. Client version reports confer no tool authority, and nothing is restarted.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Announcement accepted for the next native client request
400 Invalid plugin version
403 Operator required or revoked
503 Plugin notices unavailable

GET /v1/runtime-connections/{id}/harnesses — Inspect native harness registration on one registered remote fleet

Reports profile activation, service versus installed version, bridge, hooks and skill presence. Static registration never establishes live process membership or receiver proof.

Bearer: operator

In Name Required Type Description
path id yes string
Status Meaning
200 Per-machine and per-profile harness diagnostics
401 Owner authentication required
403 Caller is not the owner
503 Fleet unavailable or inspector not yet prepared

GET /v1/runtime-connections/{id}/membership — Inspect host-observed project eligibility on one registered remote fleet

Reports bounded per-pane process, native session, hire and actual cwd observations. Host eligibility does not verify a bridge socket, native tool catalog or delivery. Rechecks the configured fleet, settings, hire, native observations and caller authority before returning.

Bearer: operator

In Name Required Type Description
path id yes string
Status Meaning
200 Per-pane host observations with native tools explicitly unverified
401 Current owner authentication required
403 Caller lacks owner control
503 Fleet or native observations unavailable

GET /v1/operator/persona — Read owner-authored character and talkativeness

Full operators receive persona and image diagnostics. A Take Control device projection may read and change only chattiness and replyPolicy; its revision still fences the full persona. Images are service-host paths and changes require restart to apply.

Bearer: operator or device

Status Meaning
200 Current snapshot and SHA-256 revision; Cache-Control no-store (application/json)
401 Authentication required
403 Current owner or Take Control authority required
503 Settings unavailable

POST /v1/operator/persona — Save validated settings with revision fencing

The expectedRevision from GET is required. Validation and current owner authority are checked before persistence. No automatic conflict retry.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Saved snapshot and revision (application/json)
400 Invalid or unfenced settings update
401 Authentication required
403 Owner authority required
409 Stale revision
503 Settings unavailable

GET /v1/operator/host-settings — Read keep-awake and automatic update preferences

Shared labels are HOST_SETTINGS_WORDING in protocol. keepAwakeSupported is false on hosted or non-Mac hosts. Managed hosting keeps autoUpdate enabled; it cannot be disabled. A saved preference does not grant deployment or restart authority.

Bearer: operator or device

Status Meaning
200 Current snapshot and SHA-256 revision; Cache-Control no-store (application/json)
401 Authentication required
403 Current owner or Take Control authority required
503 Settings unavailable

POST /v1/operator/host-settings — Save validated settings with revision fencing

The expectedRevision from GET is required. Validation and current owner authority are checked before persistence. No automatic conflict retry.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Saved snapshot and revision (application/json)
400 Invalid or unfenced settings update
401 Authentication required
403 Owner authority required
409 Stale revision
503 Settings unavailable or runtime application failed after save; saved=true and settings carries the persisted snapshot

GET /v1/operator/appearance — Read which bundled skin Clankie wears on the owner's surfaces

leadSkin is a client skin id; "pack" keeps the selected skin pack's own lead. The service validates only its form, and clients fall back to "pack" for an id they do not bundle.

Bearer: operator or device

Status Meaning
200 Current snapshot and SHA-256 revision; Cache-Control no-store (application/json)
401 Authentication required
403 Current owner or Take Control authority required

POST /v1/operator/appearance — Choose Clankie's look with revision fencing

The expectedRevision from GET is required. No automatic conflict retry.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Saved snapshot and revision (application/json)
400 Invalid or unfenced update
401 Authentication required
403 Owner authority required
409 Stale revision or changed owner authority
503 Settings unavailable

GET /v1/operator/maximum-trust-mode — Read whether maximum trust mode is on

While on, every harness Clankie launches next starts without its own permission and command guardrails, through its native flag (Claude --dangerously-skip-permissions, Codex approval_policy=never with sandbox_mode=danger-full-access, Grok --permission-mode bypassPermissions). Running seats keep the mode they launched with. Separate from the autonomy dial.

Bearer: operator or device

Status Meaning
200 Current mode; Cache-Control no-store (application/json)
401 Authentication required
403 Current owner or Take Control authority required

POST /v1/operator/maximum-trust-mode — Turn maximum trust mode on or off

Owner-only. Applies to the next launches of the operator seat, hires and remote project leads.

Bearer: operator or device

Request body (required JSON)

A JSON object.

Status Meaning
200 Saved mode (application/json)
400 Malformed update
401 Authentication required
403 Owner authority required
409 Changed owner authority
503 Settings unavailable

GET /v1/operator/runtime-health — Read runtime CPU and health alarm settings and metadata

Owner or Take Control device authority. Returns schemaVersion=1, a SHA-256 settings revision, settings, and the fixed RuntimeHealthObservation from packages/protocol/src/runtime-health.ts. Process CPU is wall-time-normalized process.cpuUsage; 100% is one fully busy core. No conversation content.

Bearer: operator or device

Status Meaning
200 Current settings revision and live observation
401 Authentication required
403 Owner authority required

POST /v1/operator/runtime-health — Change runtime health alarm thresholds without restarting

Accepts schemaVersion=1, expectedRevision and a strict partial changes object. Defaults are enabled=true, cpuPercent=50, healthLatencyMs=1000, sustainedMs=300000, sampleIntervalMs=15000 and cooldownMs=1800000. Settings apply on the next sample. Native global-default delivery emits one alarm and one recovery with incident duration; it creates no service model turn. The schema and bounded ranges live in @clankie/protocol.

Bearer: operator or device

Request body (required JSON)

{
  "schemaVersion": 1,
  "expectedRevision": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "changes": {
    "cpuPercent": 50,
    "healthLatencyMs": 1000,
    "sustainedMs": 300000
  }
}
Status Meaning
200 Saved revision and live observation
400 Malformed or out-of-range settings
401 Authentication required
403 Owner authority required
409 Settings revision or owner authority changed
503 Settings unavailable

GET /v1/operator/voice — Read stored and effective voice settings

Provider, model and public voice identifiers only; credentials remain in the broker. Device forwarding requires Take Control. Changes need the active Discord body restart to apply and do not contact providers or restart bodies.

Bearer: operator or device

Status Meaning
200 Current snapshot and SHA-256 revision; Cache-Control no-store (application/json)
401 Authentication required
403 Current owner or Take Control authority required
503 Settings unavailable

POST /v1/operator/voice — Save validated settings with revision fencing

The expectedRevision from GET is required. Validation and current owner authority are checked before persistence. No automatic conflict retry.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Saved snapshot and revision (application/json)
400 Invalid or unfenced settings update
401 Authentication required
403 Owner authority required
409 Stale revision
503 Settings unavailable

GET /v1/herdr — Running service's worker-runtime binding

Without a connection ID, pending default-fleet settings apply on service restart. Named connections resolve their pinned endpoint and current health. No unavailable connection falls back to the default fleet.

Bearer: operator

In Name Required Type Description
query connection no string Named runtime connection, or default
Status Meaning
200 Selected local worker runtime (application/json)
401 Operator authentication required
503 Operator authentication or runtime binding unavailable

GET /v1/discord/presence-status — Operator presence snapshot

Phase and counts only. What clankie status reads.

Bearer: operator

Status Meaning
200 Present-tense presence (application/json)

POST /v1/discord/user-session/opt-in — Record user-session ToS acceptance

Bearer: operator

Request body (required JSON)

{
  "schemaVersion": 1,
  "characterId": "clankie",
  "acknowledgement": "I accept Discord user-session transport risk on my account.",
  "guildIds": [
    "123456789012345678"
  ],
  "channelIds": [
    "123456789012345678"
  ],
  "dmPolicy": "deny"
}
Status Meaning
201 Recorded

DELETE /v1/discord/user-session/opt-in — Revoke the active user-session opt-in

Bearer: operator

Status Meaning
200 Revoked
409 Nothing active to revoke

GET /v1/discord/stream-watch — Latest observed Discord screen shares

Metadata plus up to four chronological stills. Raw video is never stored.

Bearer: captain or operator

Status Meaning
200 Current share projection

GET /v1/discord/voice-transcripts — Page through retained Discord voice transcripts

Captain bearer only. Exact speech is returned only while discord.voiceTranscriptLoggingEnabled is enabled; otherwise the route returns an empty page with enabled: false. Includes legacy human recognition and assistant generated wording (role: assistant, speakerId: clankie, itemId, optional playbackId/responseId, textSource, textComplete, audioStarted, playbackMs, outcome). Outcomes are played, interrupted, suppressed, failed, or truncated. Generated text may include an unheard ending after a cutoff; no raw audio or word-aligned audible transcript is retained.

Bearer: captain

In Name Required Type Description
query cursor no string, matching ^[0-9]{12}$ Exclusive cursor from a previous page.
query limit no integer, 1–200, default 100
Status Meaning
200 Bounded transcript page (application/json)

POST /v1/remote-leads/{action} — Prepare, launch or revoke a Windows Claude project head

Owner-only management. Launch uses a stable requestId; repeated requests return the original journal without redispatch. Dispatched is a transport handoff, not native readiness. Unconfirmed launches need reconciliation. The separate process-bound delegation never authenticates owner routes. Restart recovery requires the original host-pinned process/session/chat. Private records contain token hashes only; explicit revoke survives restart.

Bearer: operator

In Name Required Type Description
path action yes string, one of prepare, launch, revoke

Request body (required JSON)

A JSON value.

Status Meaning
200 Preparation receipt, original launch journal, or revocation result
400 Invalid action or input
401 Owner operator authentication required
503 Remote lead service unavailable

GET /v1/fleet/metrics — Read fixed-reason fleet proof and report counters

Operator-only, content-free counts since service start and five/sixty-minute rates. Proof terminal admissions/refusals, receipt observations, native retries and transport failures are separate. Bounded five-minute caller windows use claimedPane request labels, not authenticated identities. No PIDs, paths, argv or report bodies. Contract: FleetHealthMetricsSnapshotSchema in packages/protocol/src/fleet-health-metrics.ts.

Bearer: operator

Status Meaning
200 Current no-store metrics snapshot
401 Operator authentication required
503 Authentication or fleet metrics unavailable

GET /v1/fleet/lead-restart — Read the default lead seat's fresh-restart budget, last check and refused wait

Operator-only. The ADR 0271 budget (context tokens and session age), the latest known check since service start (context, session start, whether a restart is due), optional unknownCheck metadata if source or usage is unknown (the legacy optional check is then absent), and the refused wait: when it began, the latest refusal and a count per refusal reason, and when the owner was told. The wait lasts across service restarts until the seat relaunches or is no longer due. Contract: LeadRestartStatusSchema in packages/protocol/src/fleet-settings.ts.

Bearer: operator

Status Meaning
200 Current no-store lead restart status
401 Operator authentication required
503 Authentication or the lead restart status unavailable

GET /v1/fleet/seat-restarts — Read hired-seat restart checks, durable refusals and original receipts

Operator-only, no-store. Reports the default-on seatRestarts setting, 450K token budget, checks and refusal counts for each exact native session, and handoff/restart receipt IDs. Unknown native state refuses an exit. Contract: SeatRestartStatusSchema in packages/protocol/src/seat-restarts.ts.

Bearer: operator

Status Meaning
200 Current no-store hired-seat restart status
401 Operator authentication required
503 Authentication or hired-seat restart status unavailable

POST /v1/fleet/seats/{paneId}/messages/health — Record a native worker's content-free receipt health

Requires the current admitted native session. This observation does not send or replay a report and does not grant tool authority. Unknown panes, changing native bindings and fields beyond the strict status are refused.

Bearer: operator

In Name Required Type Description
path paneId yes string

Request body (required JSON)

A JSON object.

Status Meaning
202 Observation recorded independently of tool readiness
400 Invalid strict status
401 Authentication required
403 Current native session required
503 Worker health observation unavailable

POST /v1/fleet/efficiency — Inspect owned seats or record a worker review

show returns every seat led by the exact conversation, including linked fleets, with optional factual efficiency evidence. review records inspected scope, tracker status or substantive progress for one exact owned native session. A review can record a reassigned deliverable or ownedIssues explicitly reported live on that session or its native children; an empty list clears those claims. Explicit deliverables carry deliverableAssignedAt, which ordinary messages cannot refresh. It changes no tracker state, harness settings, native seat ownership or report receipts. Unknown telemetry is omitted, never treated as healthy. Flags are observations for the lead skill; they do not prescribe or perform worker actions. Every watch wake calls for reviewing all owned seats; periodic lead rounds default to 30 minutes and coalesce while a review turn is outstanding. Prompts carry bounded summaries; use show for full details and every-owned inspection. Original report acceptance or attempt remains progress after acknowledgment; acknowledgment creates no new progress. Context percentage is the latest native Codex model-input snapshot and may age between responses. Claude context/effort and OpenCode or remote telemetry remain unknown.

Bearer: operator

Request body (required JSON)

show

{
  "action": "show",
  "conversationId": "global-default"
}

review

{
  "action": "review",
  "conversationId": "global-default",
  "seatId": "worker-seat",
  "assignmentStatus": "active",
  "deliverable": "VUH-1662",
  "evidence": "Reviewed the assigned issue and current worker report."
}
Status Meaning
200 Current owned roster, after recording the review when requested (application/json)
400 Invalid strict request (invalid_request)
401 Operator authentication required (operator_authentication_required)
409 Conversation, native ownership or review observation unavailable (refused)
503 Fleet efficiency service unavailable (fleet_efficiency_unavailable)

POST /v1/fleet/tidy-worktrees — List merged, clean worktree cleanup candidates

Read-only listing from the exact canonical repository root and locally saved merge ref (origin/main by default); it never fetches refs or removes worktrees. Main, locked, prunable, dirty, unmerged and live-pane worktrees are excluded. Idle agents and shells also protect their directories. Unverified paths, unavailable or changing refs, and an incomplete or changing local pane inventory return outcome unavailable with no candidates. Candidate status does not prove ownership; the tidy skill verifies ownership, preserved results and fresh landing evidence before any separately authorized removal.

Bearer: operator

Request body (required JSON)

A JSON value.

Status Meaning
200 Read-only candidates and exclusions, or an unavailable listing with no candidates (application/json)
400 Invalid strict request (invalid_request)
401 Operator authentication required (operator_authentication_required)
503 Worktree listing service unavailable (tidy_worktrees_unavailable)

GET /v1/fleet/tool-catalog-health — Read native catalog health for every current Claude and Codex seat

Includes the operator head. Reports from a previous occupant are never reused.

Bearer: operator

Status Meaning
200 Session-bound catalog health and remediation in seats
401 Operator authentication required

POST /v1/operator/projects/add-worktree-root — Enroll a repository-bound linked-worktree root

Owner only. Requires projectId, machineId, platform, path, repoPath and expectedRevision. The service observes canonical root/repository paths and Git common-directory identity, then rechecks native facts, authority and revision before saving. The repo must exactly match an approved workspace in the project. This confers no tool grant.

Bearer: operator

Status Meaning
200 Project snapshot and new revision
400 Malformed request
403 Owner authority required
409 Unverified root, namespace conflict, or changed authority/settings

POST /v1/operator/projects/remove-worktree-root — Remove a linked-worktree root enrollment

Owner only. Requires projectId, rootId and expectedRevision. Rechecks authority and revision before persistence. Deletes no filesystem content.

Bearer: operator

Status Meaning
200 Project snapshot and new revision
400 Malformed request
403 Owner authority required
409 Unknown root or changed authority/settings

GET /v1/games/extensions — Discover registered game extension lifecycles

Read-only local metadata and lifecycle health. Does not join a game, probe credentials or call a model. Ready does not prove live gameplay or media. Registration and removal are trusted in-process composition, not model-authored manifests.

Bearer: operator

Status Meaning
200 Bounded catalog, without credentials, endpoints or action history (application/json)
401 Operator authentication required
503 Authentication or registered catalog unavailable

GET /v1/minecraft — Read the current Minecraft body session

Operator-authenticated read of the approved offline Java body. Account material and raw endpoints are excluded. x-clankie-conversation-id selects an existing owning conversation.

Bearer: operator

Status Meaning
200 Current exact session and bounded action state
403 Operator authority required
503 Minecraft unavailable

POST /v1/minecraft — Join, choose a driver, act, inspect, pause, cancel or leave Minecraft

Joining starts the configured continuous play mind. Use driver to hand off to owner, mind or a chosen admitted worker; it quiesces prior motor work without transferring the conversation play lease. Direct act requires owner driver. Long work returns a handle. The shared play lease is retained until exact confirmed disconnect. Completion is distinct from server-verified effects.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Session or action handle with settlement and evidence
400 Invalid typed command
403 Operator authority required
409 Busy play lease
503 Motor unavailable

POST /v1/minecraft/host — Configure, start, administer or back up Clankie's own Minecraft server

Integration-owned on-demand Paper host and broker-backed playit claim. claim starts background agent preparation and returns preparing immediately; claim_status reads preparation progress and returns the official approval URL when pending and claim_complete polls once and stores an approved secret only in the broker. Tunnel claiming requires owner/admin authority. Hosting is off by default, idle-stops after at most 15 minutes, and has a maximum uptime watchdog. x-clankie-conversation-id selects an existing operator conversation. Typed administration has no op, raw RCON or secret arguments. Enrollment approval uses a previously verified Discord requester; operator arguments cannot select a Discord subject.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Safe status
400 Invalid typed hosting command
403 Operator authority required
503 Hosting adapter unavailable

GET /v1/minecraft/configuration — Read owner Minecraft profiles, destination allowlist and play settings

Offline host, port, version, username and explicit public destination grants. This operator configuration does not appear in model tools.

Bearer: operator

Status Meaning
200 Offline profiles and public allowlist
403 Operator authority required

PUT /v1/minecraft/configuration — Replace offline Minecraft profiles, public destination grants and play settings

Owner-only settings write. DNS and SRV destinations are checked again before dial; model calls cannot supply raw host or authentication arguments.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Updated offline profiles and public allowlist
400 Invalid settings
403 Operator authority required
503 Settings unavailable

POST /v1/pairing/local/offer — Mint the same-UID Mac companion handoff through owner-private IPC

Self-hosted macOS only. The CLI uses the protected Unix socket, never unverified TCP. Local native transport and operator bearer are required. The five-minute offer is not published to the gateway or generic store. A new mint invalidates its predecessor. No-store; secrets never enter logs.

Bearer: operator

Status Meaning
200 Single-use offer for the private handoff file (application/json)
401 operator_authentication_required
403 native_loopback_required
404 not_found
503 device_authentication_unavailable

POST /v1/pairing/local/redeem — Redeem the owner-local handoff once over native loopback

Refuses browser pages, forwarded requests, the gateway and the LAN device doorway. Only a process whose running code satisfies an owner-trusted code requirement may redeem (VUH-2604); any other app is refused without consuming the offer and recorded as pairing.local_companion.refused. Reuses the active companion's durable device ID and grants on reinstall. Revoked identities never revive. Session uses the existing device signer and includes host, grants and loopback control/relay routes.

Bearer: none

Request body (required JSON)

A JSON object.

Status Meaning
200 Existing device-session fields plus host name and loopback directRoute (application/json)
400 malformed
403 native_loopback_required
404 not_found
409 consumed
410 expired
503 device_authentication_unavailable

POST /v1/pairing/local/trusted-apps — List, add or remove the apps that may take the same-Mac handoff

Self-hosted macOS only, native loopback and operator bearer. Each entry is a code requirement in Apple's requirement language, as codesign -d -r- prints an app's designated requirement. The list starts empty, which refuses every companion redeem. Changes are recorded as pairing.local_companion.trust_changed.

Bearer: operator

Request body (required JSON)

A JSON value.

Status Meaning
200 The trusted apps after the change (application/json)
400 malformed
401 operator_authentication_required
403 native_loopback_required
404 not_found
503 settings_unavailable or device_authentication_unavailable

Captain

POST /v1/captain/channel-turns — One Discord message becomes one captain turn

Bearer: discord text or discord voice

In Name Required Type Description
header Prefer no string, one of respond-async Return 202 while the turn runs, then poll the delivery ID. Without this header, the request waits for the result.

Request body (required JSON)

{
  "schemaVersion": 1,
  "deliveryId": "yaak-delivery-1",
  "identity": {
    "presenceSessionId": "replace-me",
    "correlationId": "yaak-1",
    "profileHash": "unversioned",
    "characterId": "clankie",
    "credentialRef": "discord_bot",
    "transportKind": "bot"
  },
  "trigger": {
    "kind": "message",
    "id": "1",
    "channelId": "123456789012345679",
    "actorId": "123456789012345680",
    "body": "hello from Yaak"
  }
}
Status Meaning
200 Settled turn
202 Turn accepted and still running

GET /v1/captain/channel-turns/{deliveryId} — Poll a Discord turn by its stable delivery ID

Bearer: discord text or discord voice

In Name Required Type Description
path deliveryId yes string
Status Meaning
200 Settled turn
202 Turn still running
404 Turn unavailable after a service restart; resubmit the original delivery

POST /v1/captain/presence — Report captain lease heartbeat

Bearer: captain

Request body (required JSON)

{
  "schemaVersion": 1,
  "type": "captain.heartbeat",
  "eventId": "yaak-hb-1",
  "leaseId": "replace-me",
  "generationId": "replace-me",
  "occurredAt": "2026-08-15T20:00:00.000Z"
}
Status Meaning
202 Accepted

GET /operator/v1/voice-call — Device voice call (WebSocket)

WebSocket upgrade the relay opens for an authorized device (VUH-2682, ADR 0288). Binary frames are 24 kHz mono s16le PCM both ways: microphone up, his speech down. Text frames are VoiceCallClientEvent (playback acknowledgements, hangup) and VoiceCallServerEvent (state, playback start/finish/stop, transcript lines, ended) from @clankie/protocol. The call runs the Discord rooms' realtime voice session; ask_clankie becomes a queued turn in the main conversation, each closed transcript line is recorded there without a turn (VUH-2752), and the call holds his voice body lease.

Bearer: captain

Status Meaning
101 Call open
403 Not the relay's operator bearer
503 Voice calls are not set up on this host

POST /operator/v1/dispatch — Operator conversation contract

One route, discriminated op: list, roster, get, create, fork, close, send, cancel, pending_messages, stop_task, replay, subagent_replay, tail, autonomy, terminal_tail, readopt_seat, worker_reports, and acknowledge_worker_reports. worker_reports optionally selects 1–100 exact UUID deliveryIds within the requested conversation, with the existing full-page byte budget and offered-only acknowledgment. Without that selector it remains oldest-first. Unknown, read and foreign IDs are omitted. Worker ownership/report operations require current operator authority and an exact conversationId. Re-adoption proves the original owner and same native thread. Worker reads return complete bounded unread payloads and ackDeliveryIds without acknowledging; only fully offered IDs may be marked read, and the result lists unanswered IDs whose worker has had no reply from that conversation. Roster/fleet report summaries survive disappeared panes, and delivery receipts never establish reading. The TUI and relay both speak this. Built-in tracker sync uses additive op tracker_sync: bootstrap, batch, subscribe, list_issue_views, list_issue_view_issues and keyed atomic transaction commands. Saved-view reads name an exact storeId and project UUID; apply also names the saved view id. They delegate to canonical current list/apply tools and return issue_views or issue_view_issues with hasNextPage and an optional cursor (limit 1–250, default 50). Reads require current device chat or operator authority; writes require terminalControl/owner authority and stamp the authenticated actor. Bootstrap returns JSON lines in result.ndjson ending in cursor/count metadata; the relay emits them as NDJSON. Subscribe returns ordered commits after (storeId,lastSyncId) and waits on publication for at most 20 seconds. The existing relay tail route streams these pages. A cursor/store gap requires partial bootstrap. Each commit and its receipt share the existing atomic tracker write. Owner asks use input_list (optional status and conversationId) to return {questions: [ConversationQuestionResult, ...]}, input_get to read an immutable target, and input_answer or input_cancel to resolve it. All require authenticated operator or active terminalControl device authority; a captain bearer receives 403 question_owner_required. Decision, approval, owner_action, verify and gate asks carry their source conversation, waitingOn, recommendation, options and exact steps as applicable. Built-in tracker gate asks name a run and block it until the owner chooses Approve. Decline, cancellation and free text leave it blocked; item/run references link the same ADR 0245 record rather than another ask store. Escalated worker questions pin native session/request/question IDs; worker answers use an ID-keyed answers map, never terminal typing. Duplicate answers reconcile the original receipt and never send twice. Informational owner mail uses owner_update_list (optional conversationId and unread/read/dismissed/all state; default nondismissed) to return {updates: [OwnerUpdate, ...]}, newest first up to 1000 records. owner_update_read and owner_update_dismiss select an exact update UUID and return {status, update?, reason?}. These use the same owner authority as asks; captain-only callers receive 403. Reading/dismissing is idempotent and never resumes a conversation. Updates are created only when Clankie deliberately calls mail_owner_update; no automatic event feed. Updates carry title, short body, source, timestamp, read/dismissed state, and optional links/media. Asks and updates carry optional issue: {tracker, key, url} for navigation without tracker authority. Each source conversation retains active updates and 32 dismissed records within 256 total records and 512000 bytes; capacity refuses new mail. Native message controls require owner operator authority or an active terminalControl device. pending_messages takes conversationId and a command: list; edit with original messageId, expectedVersion and text; remove or send_now with original messageId and expectedVersion. It returns ordered messages (messageId, version, text, createdAt, state) and an explicit outcome. New native Queue messages are host-owned until pickup; edits, removal and send-now cannot replace a dispatched or uncertain original. Restart retains queued records for explicit send-now and marks interrupted dispatch uncertain. stop_task takes conversationId and returns stopped, already_finished, unsupported, unavailable or uncertain, with taskId when known. Controller-owned Codex uses exact turn/interrupt plus observed native completion. Interactive Claude sends one guarded Esc only with an empty input line. A confirmed unsent draft returns unavailable with typed reason unsent_draft, without sending a key or clearing the text; open the agent's terminal to review it. Clients match reason, never diagnostic detail. Other native stop controls currently return unsupported. Typed reasons require request includeReason: true; absent or false preserves the legacy result shape. Old strict services or relays reject that field with HTTP 400 before dispatch; retry only that schema refusal once without the field, never a lost response or other failure. After Stop dispatch, unexpected errors return uncertain, never HTTP 400. The canonical schemas are in packages/protocol/src/operator-conversations.ts and packages/protocol/src/operator-service.ts. Project onboarding uses project_proposal_get for one defaults-first proposal, project_proposal_tweak for exactly one reviewed field, and project_proposal_confirm for explicit acceptance. Tweak requires the current immutable target and change: { field, value } (name, roles, workerCap, or tracker); it returns a fresh proposal target without saving project/tracker settings. Accepting an old target refuses. These operations require the original owner; captain bearers and preference answers cannot save a project. Acceptance uses the durable CREATE boundary, saves confirmed roles, and never hires workers. The autonomy command reads or sets the master Auto switch for unprompted work (projects on Auto and self-wakes, ADR 0264) and clears a pending self-wake. Turning Auto on requires an operator credential or active terminalControl device authority; a captain bearer alone receives 403 goal_owner_required. Service goals were retired by ADR 0264. Seat scopes identify Herdr direct-send/projection threads. cancel interrupts one accepted run: the captain aborts the live model turn and the durable log settles that run as cancelled. fork clones the current Pi leaf into an ephemeral child conversation. Pane-scoped send and state_stance and state_work requests qualify their pane ID with the source socket. A mismatched send loses its pane association; a mismatched stance returns 409 without changing a worker. Seat-control operations return 503 with herdr_unavailable when the default runtime is unavailable; ordinary conversations and their durable records remain accessible. presence returns a strict snapshot with mood (needs_you, thinking, in_voice, playing, leading, idle, in that precedence), detail, since (source start timestamp or null when unknown), activeSeats (working seats in the last completed fleet projection; a read never waits for a fresh one), and optional pendingOwnerItem (oldest unanswered owner ask: conversationId, questionId, title, since). It uses optional cursor and waitMs (0–30000); an absent or changed cursor returns immediately. A current cursor parks until the projected sources change, sampled within 500 ms, or the wait expires. Unreachable is a client transport state, never a mood. Paired hosted devices may read it. includeFace true opts in to an optional face (legacy reads omit it). It drives the desktop screen separately from mood/body: needs_you, error, new_message, working or voice, in that precedence. Working follows thinking/leading or observed native captain/child work; voice follows in_voice. Otherwise idle/play omit the override. Live committed captain replies in owner conversations show new_message for 10s; failed owner turns show error for 30s or until the same conversation completes successfully. History, room, worker and fork activity do not raise these transient faces. Face expiry changes the cursor; clients honor Reduce Motion with a static face. Optional expression is a transient desktop action with UUID id and ISO expiresAt: kind emote adds animation (a hero sprite tag), kind say adds text (1–200 characters), and kind move adds x/y (normalized 0–1 on the current display, left-to-right/top-to-bottom). Expiry or owner quiet hours removes it and changes the cursor without changing the mood. Clients discard expired actions even while disconnected, honor Focus, and never take keyboard focus to show an expression. fleet prefers one cursor-coherent snapshot, with one retry and a five-second display observation budget. An incomplete snapshot carries optional readWarnings: {source, reason, message}[], where reason is timeout or changed_during_read. Sources name the pending Herdr fleet (herdr:FLEET_ID), native_fleet_projection, checkout_observations, or fleet_consistency. Seats and personas reflect the last available observation, never fresh admission or ownership proof. The returned cursor remains the cursor from before the read so the next poll can catch changes. roster answers within three seconds; a projection still running leaves its seats as the last completed projection and adds the same optional readWarnings. Optional view: home omits historical personas that are neither seated contacts nor channel participants. Seats, channels, tallies and edges are unchanged. Omitting the selector preserves the full directory; personas and conversation IDs still address retained history. set_persona_role (personaId, role: a built-in such as planner, designer, builder, tester, reviewer or researcher, or a custom role of 1-24 letters, digits, spaces and hyphens; null clears) returns the updated persona and rides the steer grant (ADR 0208). Roles are trimmed and whitespace-collapsed, built-ins fold to lowercase, and custom roles keep their casing and compare case-insensitively. roles returns the built-ins, then custom roles in use, as { role, builtIn, count }. Fleet seats may carry subagents (running count and up to eight recent labels) for local Claude, Codex and registered OpenCode seats that were hired or whose chat is open. Recent entries optionally carry native id, startedAt and endedAt; absent means unknown. work_items takes an optional case-insensitive label; items may carry optional backend-native parent metadata. work_item_write requires the original owner with terminalControl and request {repoId,itemId, requestId UUID,command}. Commands assign work-metadata owner, add/remove a role label, or append a dependency. work_item_write_receipt takes repoId,itemId,requestId and reads the original scoped result. Both return an accepted envelope with receipt {requestId,outcome:applied|refused|uncertain, message,item?}. Repeated IDs and receipt reads never replay a write. subagent_replay takes replay with the parent's existing seat/persona conversationId, a native subagentId, surfaceClientId and the ordinary replay paging options. It needs only the chat grant and returns subagentId plus the ordinary normalized replay result. It reads a bounded local child window through the parent's native source without creating a conversation or granting send, resume or terminal control. Missing locators, changed parents and remote children return typed recovery. Older hosts may reject this operation while their fleet remains readable. replay optionally takes direction: backward, turnLimit (1..40, default 20) and limit (1..500, default 500 for backward). Omit cursor to open the newest window; pass the page's previousCursor as the next exclusive upper bound to load older history. Events remain chronological. hasOlder and hasMore say whether more retained history precedes the backward page. nextCursor is still the newest event in that page and can resume an ordinary forward tail. The event ceiling wins when one turn exceeds 500 events. Omitted direction preserves forward replay and tail behavior. Clients keep distinct older-history and live-tail cursors. terminal_catalog lists up to 48 panes per execution connection (16 connections). Each row carries runtime identity separately from Herdr workspace/tab IDs. Named terminal addresses pin their endpoint; tail, control and input refuse disabled or changed connections with a typed unavailable result, without falling back to the default fleet. Terminal catalog/tail require the relay's terminalObserve grant; control/input require terminalControl. connections reads bounded runtime and account metadata or manages named runtime connections. Commands are list, connect_runtime (id, session), reconnect_runtime, disconnect_runtime (id). It requires the operator captain lane; the device relay requires steer. No provider credential, socket path or session capability is returned.

Bearer: captain or operator or device

In Name Required Type Description
header x-clankie-herdr-socket no string Caller Herdr session's exact socket path, required for pane identity.

Request body (required JSON)

List conversations

{
  "op": "list",
  "schemaVersion": 1
}

List live Herdr seats

{
  "op": "roster",
  "schemaVersion": 1,
  "includeCheckouts": true
}

Create a global conversation

{
  "op": "create",
  "schemaVersion": 1,
  "scope": {
    "kind": "global"
  },
  "title": "Yaak probe"
}

Get one conversation

{
  "op": "get",
  "schemaVersion": 1,
  "conversationId": "replace-me"
}

Fork an ephemeral side conversation

{
  "op": "fork",
  "schemaVersion": 1,
  "parentConversationId": "replace-me"
}

Close a non-default conversation or discard a side fork

{
  "op": "close",
  "schemaVersion": 1,
  "conversationId": "replace-me"
}

Send a message turn

{
  "op": "send",
  "schemaVersion": 1,
  "turn": {
    "schemaVersion": 1,
    "kind": "message",
    "conversationId": "replace-me",
    "surfaceClientId": "yaak",
    "expectedRevision": 0,
    "message": "ping from Yaak"
  }
}

Replay a page

{
  "op": "replay",
  "schemaVersion": 1,
  "replay": {
    "schemaVersion": 1,
    "conversationId": "replace-me",
    "surfaceClientId": "yaak",
    "limit": 50
  }
}

Open the newest 20 turns

{
  "op": "replay",
  "schemaVersion": 1,
  "replay": {
    "schemaVersion": 1,
    "conversationId": "replace-me",
    "surfaceClientId": "yaak",
    "direction": "backward",
    "turnLimit": 20,
    "limit": 500
  }
}

Read autonomy state for one conversation

{
  "op": "autonomy",
  "schemaVersion": 1,
  "conversationId": "replace-me",
  "command": {
    "action": "status"
  }
}
Status Meaning
200 Discriminated result
403 goal_owner_required for activation without owner/device authority

GET /captain/v1/lanes — Observable captain lanes

Bearer: captain

Status Meaning
200 Lane listing

GET /v1/captain/evaluator — Independent evaluator status, queue and recent reports

Bearer: operator

Status Meaning
200 Enabled state, harness, pane, errors, queue count and up to 50 recent jobs
401 Operator authentication required

POST /v1/captain/evaluator — Enable, disable, focus or retry the independent evaluator

Bearer: operator

Request body (required JSON)

A JSON value.

Status Meaning
200 Current evaluator status; operational startup errors appear in error
400 Invalid command
401 Operator authentication required
409 Conflicting command or unavailable pane

GET /v1/captain/issue-metrics — Observed issue and fleet efficiency with explicit source coverage

Read-only projection of retained exact local native bindings, native transcripts, settled turn metrics, seat ledger edges and unresolved hire receipts. Unknown totals are null and partial/unsupported sources are explicit in coverage. No transcript, command or credential is returned. Window selects observed landing, otherwise approval time or latest unfinished observation; totals cover the selected episode. Passed seat edges never establish approval.

Bearer: operator

In Name Required Type Description
query issue no string, matching ^(?:LOCAL-)?[A-Z][A-Z0-9]*-[0-9]+$
query worker no string Exact worker label, terminal ID or native session reference.
query project no string Exact saved hire project ID; also scopes the present-time tracker/seat census.
query since no string ISO timestamp; defaults to 24 hours before until.
query until no string Exclusive ISO end; defaults to now. Maximum window 366 days.
Status Meaning
200 schemaVersion, window, issues, workers, sessions, summary and coverage.
400 Invalid filter or time window.
401 Operator authentication required.
503 Operator authentication unavailable.

GET /v1/captain/turn-metrics — Recent settled captain turns

Counters, execution identity and reported usage for recent settled operator and Discord turns, newest first, from the durable turn-settled.jsonl the captain appends. Never a transcript, tool argument, tool output or credential.

execution is the model, provider and effort that actually ran the turn, captured as it executed rather than read back from configuration. usage is totalTokens summed over the assistant messages the provider reported plus reports, the number that contributed. Both are null when unknown — a turn settled before the capture existed, or a provider that reported nothing. Null never means zero, and contextTokensStart / contextTokensEnd are context occupancy, never usage or a charge.

Bearer: operator

In Name Required Type Description
query limit no integer, 1–100, default 20 1–100; clamped, never refused. Defaults to 20.
query runId no string Narrow to one run.
Status Meaning
200 Bounded settled-turn metrics, newest first
401 Operator authentication required

POST /v1/captain/seat-migrations — Prepare, inspect, claim or complete an exact native session handoff

Preparation persists a conversation execution hold and original process lifetimes. Claim proves every old process exited and matches the exact session, profile and cwd, then records one launch attempt. Unknown receipts or uncertain launches stay held; no action replays a call or signals a process. Completion requires that same session/profile/cwd to be bound and ready. Other conversations continue normally.

Bearer: operator or captain

Request body (required JSON)

A JSON object.

Status Meaning
200 Original migration identity, state and unresolved original call receipt IDs
400 Invalid migration request
401 Authentication required
403 lane_forbidden
409 Migration held; exact identity, exit, receipts or readiness is unproven
503 Migration service unavailable

GET /v1/captain/seat-bindings — Inspect binding mode, live operator launcher inventory and recovery

Read-only operator-lane diagnostics. Includes local launcher PIDs and kernel lifetimes, bound/unbound status and exact migration recovery; never contains launch secrets. Observe admission records the same refusal while preserving preparation-release access. An incomplete census or unbound seat holds an enforcing update.

Bearer: operator or captain

Status Meaning
200 Binding diagnostics; unavailable helpers are represented in the body (application/json)
401 Authentication required
403 lane_forbidden
503 Authentication unavailable

PUT /v1/captain/seat-bindings — Bind a launcher's native harness to an operator conversation

Local process proof is required in addition to operator authentication. The request socket identifies the controller. The harness's bridge must present x-clankie-bridge-claim on subsequent MCP and seat mailbox requests. Remote relay and bearer-only clients cannot establish this local binding. Registry refusals include an error code and human-readable recovery text.

Bearer: operator or captain

Request body (required JSON)

A JSON object.

Status Meaning
200 Registered; JSON object with ok true
400 invalid_seat_binding or seat_binding_invalid
401 Authentication required
403 lane_forbidden, seat_process_unproven, seat_harness_not_child or seat_binding_helper_missing
409 seat_binding_conflict; a different live controller owns the conversation
413 Request body exceeds 4 KiB
503 seat_binding_unavailable

DELETE /v1/captain/seat-bindings — Release the requesting launcher's operator seat binding

Only the registered controller process may remove its binding.

Bearer: operator or captain

In Name Required Type Description
query conversationId yes string
Status Meaning
200 Removed or already absent; JSON object with ok true
401 Authentication required
403 lane_forbidden, seat_binding_conversation_required or seat_process_unproven
409 seat_binding_conflict; caller is not the registered controller
503 seat_binding_unavailable

GET /v1/captain/seat-context — Resolve an operator seat to its service conversation and workspace

Bearer: operator or captain

In Name Required Type Description
query conversationId no string Existing global or workspace conversation; defaults to the global head.
Status Meaning
200 The service-owned conversationId, cwd, and whether a live native seat holds it (application/json)
400 Invalid conversation ID
403 Operator lane required
404 Unknown conversation or a scope that does not run Clankie

POST /v1/captain/seat-context — Create a separate workspace chat for a new native operator seat

Bearer: operator or captain

Request body (required JSON)

A JSON object.

Status Meaning
201 A fresh service-owned conversationId and cwd; repeated launches create separate chats (application/json)
400 Invalid workspace conversation creation request
401 Authentication required
403 Operator lane required

POST /v1/seat/transcript — Append redacted native seat display records to its selected conversation

Bearer: operator or captain

In Name Required Type Description
query conversationId no string Existing global or workspace conversation; defaults to the global head.

Request body (required JSON)

A JSON object.

Status Meaning
200 Accepted; repeated native entry IDs do not append duplicate events (application/json)
400 Invalid transcript or conversation ID
401 Authentication required
403 Operator lane required
404 Unknown captain conversation
409 Native session is pinned to another conversation or retired by reset
413 Request exceeds 1 MiB

GET /v1/captain/prompt — The system prompt a lane's session starts from

Plain text, for a seat launcher in another harness. sections is a comma-separated subset of identity, persona, reach, fleet, address, model; omitted, it is the session's standard sections (model is the per-run card, asked for by name). The lane must be the bearer's own — the operator credential and the console captain token are operator, a Discord bridge bearer is the lane it serves. An explicit conversationId adds that workspace's agent instructions with source paths.

Bearer: operator or captain

In Name Required Type Description
query conversationId no string Existing operator global/workspace conversation; omitted selects the global head.
query lane no string, one of operator, discord_voice, discord_presence, gameplay Defaults to the bearer's own lane.
query sections no string, e.g. persona,model
Status Meaning
200 The assembled prompt (text/plain)
400 Unknown lane or section name
403 Lane is not the bearer's own

GET /v1/captain/memory-card — The memory card that lane's next run injects

Plain text, for a per-turn hook. Filtered by lane the same way the pi session's own injection is: operator-private notes reach only the operator lane. An empty store still returns a labeled card. The lane must be the bearer's own.

Bearer: operator or captain

In Name Required Type Description
query lane no string, one of operator, discord_voice, discord_presence, gameplay Defaults to the bearer's own lane.
Status Meaning
200 The lane's recall card (text/plain)
400 Unknown lane
403 Lane is not the bearer's own

GET /v1/mcp — Server-to-client notification stream for an open session

Requires mcp-session-id; the bearer must resolve to the session's lane.

Bearer: operator or captain or discord text or discord voice

Status Meaning
200 SSE stream
400 No session id
403 Native seat binding refused, or session belongs to another lane or conversation
404 Unknown or expired session
409 seat_bridge_claimed; another live bridge holds the binding

POST /v1/mcp — A lane's tool bank over streamable-HTTP MCP

Streamable-HTTP MCP over Clankie's authored tool registry. The bearer selects the lane and the lane selects the tools: the operator credential and the console captain token are operator, a Discord bridge bearer is the lane it serves, and a connection lists exactly that lane's authority plan (authored tools, the browser catalog, and the connected-service tools that lane may reach). An initialize POST opens a session and returns its id in mcp-session-id; every later request must carry that header and resolve to the same lane and conversation. DELETE ends the session. clankie mcp is the stdio bridge to this route (ADR 0152). An operator request without conversationId opens a stateless session: connected-service tools remain available on the bearer, with no default conversation. Conversation-scoped lead tools refuse with a typed conversation_binding_required tool result and perform no lead operation. An operator request naming a conversation requires the local native binding registered by its launcher and the bridge's x-clankie-bridge-claim. Seat event polling, acknowledgment and reply always require that binding. Joined seats use their authenticated delegated /v1/fleet/lead/mcp route; the device relay does not expose operator MCP or local seat bindings.

Bearer: operator or captain or discord text or discord voice

Status Meaning
200 JSON-RPC response; an unbound conversation-scoped tool returns isError with conversation_binding_required
400 No session id on a non-initialize request
403 Native seat binding refused, or session belongs to another lane or conversation
404 Unknown or expired session
409 seat_bridge_claimed; another live bridge holds the binding

DELETE /v1/mcp — End an MCP session

Bearer: operator or captain or discord text or discord voice

Status Meaning
200 Session closed
403 Native seat binding refused, or session belongs to another lane or conversation
404 Unknown or expired session
409 seat_bridge_claimed; another live bridge holds the binding

GET /v1/seat/events — Long-poll the seat's outbox

Wakes, herdr completion watches, and room escalations queued for a bound head (ADR 0152). The launcher registers the native seat binding before polling; clankie mcp asks again when a poll returns and pushes each event into the session as a channel notification. Operator bearer only; a Discord bridge bearer is 403. wait is capped at 30000 ms. The loaded bridge advertises capabilities through x-clankie-seat-capabilities. No handshake means the strict legacy wake/watch/escalation/message schema; owner turns use a message with content attribution and no ownerOrigin field. The original ID and receipt remain the same. Only declared wire kinds and fields are dispatched. A stale bridge or unacknowledged owner turn produces a visible /mcp reconnect notice in the conversation, without replay. The operator seat_bridges dispatch read exposes the same loaded capabilities used by doctor and status; installed files are not proof of loaded code. A recently interrupted bridge reports reconnecting, then current when its original head resumes current-protocol polling; recovery never changes authority. Host-authenticated owner sends on capable bridges arrive as kind: turn, with ownerOrigin recording the verified device/operator principal and self-reported surface. The seat answers normally in the synced conversation; these events have no separate reply target. Room escalations retain their reply routing.

Bearer: operator or captain

In Name Required Type Description
header x-clankie-seat-capabilities no string JSON declaration from the loaded bridge; absence is the legacy wire contract.
query conversationId no string Explicit registered operator global/workspace conversation; required for operator-lane callers.
query wait no integer, 0–30000, default 0
Status Meaning
200 Events taken from the outbox, possibly none (application/json)
400 Invalid capability declaration; reconnect the bridge with /mcp
403 Not the operator lane

POST /v1/seat/events/{id}/reply — Answer an escalation from the seat

The reply lands in the escalating conversation as his own message and settles that run.

Bearer: operator or captain

In Name Required Type Description
query conversationId no string Explicit registered operator global/workspace conversation; required for operator-lane callers.
path id yes string

Request body (required JSON)

{
  "schemaVersion": 1,
  "text": "On it — the build is green."
}
Status Meaning
200 Replied
404 Nothing is waiting on that event

GET /v1/fleet/seats/{paneId}/events — Long-poll a fleet seat's mailbox

A DM or room turn queued for a bound fleet seat (ADR 0161). Polling is what binds the mailbox: clankie mcp --seat asks again the moment a poll returns and pushes each event into the session as a channel notification. Operator bearer only; a Discord bridge bearer is 403. wait is capped at 30000 ms. unknown_seat (404) is the pane before herdr has classified the harness; the bridge retries.

Bearer: operator or captain

In Name Required Type Description
path paneId yes string
query wait no integer, 0–30000, default 0
Status Meaning
200 Events taken from the mailbox, possibly none (application/json)
403 Not the operator lane
404 No messageable agent in that pane

GET /v1/fleet/seats/{paneId}/peers — List native seats in the calling worker's fleet

Requires the local process listener or registered remote relay's exact native pane/session proof. Operator and fleet bearers alone do not identify a peer sender. Returns sender and recipient seat IDs, panes, harnesses, titles and native binding hashes. The owner setting fleet.peerMessages=off refuses discovery. No workspace or account authority is granted by a peer message (ADR 0213 amendment).

Bearer: none

In Name Required Type Description
path paneId yes string
Status Meaning
200 Current same-fleet native seat bindings
403 Peer messaging off or native sender proof unavailable

GET /v1/fleet/seats/{paneId}/messages/{id}/status — Read original sending seat's current durable delivery stage

Read-only; never resends, acknowledges a report or reconciles a send fence. Requires the original pane and native binding. Unknown status does not prove nothing was sent.

Bearer: none

In Name Required Type Description
path paneId yes string
path id yes string
query definitive no string, one of 1 Set to 1 to receive definitive. Older bridges reject unknown keys, so it is opt-in.
Status Meaning
200 Current ADR 0211 delivery stage (application/json)
400 Invalid delivery ID
403 Native sender proof unavailable or revoked
404 No retained receipt for this original sending seat

POST /v1/fleet/seats/{paneId}/peer-messages — Send one same-fleet peer message through native seat delivery

Uses the same native delivery path as message_seat, with server-authored sender attribution and agent-output framing. Requires native process admission, the sender binding, and the exact same-fleet recipient binding returned by peers. Rechecks the owner switch and native bindings before dispatch. Persists the original delivery UUID before sending. Uncertain attempts reconcile through GET only; neither a duplicate UUID nor a new follow-up replays the original. Records exchanges and receipts in the service audit and Clankie's agent-role transcript without an owner turn.

Bearer: none

In Name Required Type Description
path paneId yes string

Request body (required JSON)

{
  "schemaVersion": 1,
  "seatId": "pc/recipient-terminal",
  "recipientBinding": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
  "text": "The shared interface is ready.",
  "delivery": {
    "id": "10000000-0000-4000-8000-000000000001",
    "binding": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
  }
}
Status Meaning
200 Exact receipt with deliveryId, bindings, fingerprint, outcome and deliveryStage
400 Invalid peer message
403 Native peer sender proof unavailable

GET /v1/fleet/seats/{paneId}/peer-messages/{id} — Inspect the original peer delivery receipt without resending

Requires the original sender's native process/session, original binding, delivery UUID and fingerprint. The fingerprint covers recipient seat, recipient binding and normalized text. Available while peer messaging is off. May match the original native transcript or exact channel/hook acknowledgment; absence of proof remains uncertain while the original recipient is bound. A lost recipient binding settles to recipient_gone with outcome unconfirmed: delivery remains unknown, never resends, and no longer blocks fresh messages. An original still unproven after 15 minutes settles to superseded with outcome unconfirmed: delivery remains unknown and is never resent, and the sender's next message to that seat goes out as a new message labelled as following it. An unresolved original blocks only new messages to its own recipient. Older settled bodies are pruned after 100 messages; exact compact receipts and unresolved originals are retained.

Bearer: none

In Name Required Type Description
path paneId yes string
path id yes string
query binding yes string, matching ^[a-f0-9]{64}$
query fingerprint yes string, matching ^[a-f0-9]{64}$
Status Meaning
200 Original receipt, with no new send attempt
400 Invalid original receipt reference
403 Native peer sender proof unavailable
404 No exact original receipt available; delivery remains uncertain

POST /v1/fleet/seats/{paneId}/review-candidates — Submit the seat's exact patch to its project's standing reviewer

Requires the same native process/session proof as peer messages; the author is attributed from that proof, never from the body. The body carries git diff --binary bytes (base64, at most 4 MiB) and the bridge's git patch-id --verbatim; the service recomputes the hash over the bytes it stores and refuses a mismatch. It sends a review packet to the first live reviewer seat that is not the author. An author's earlier candidate for the same issue becomes superseded. ADR 0287.

Bearer: none

In Name Required Type Description
path paneId yes string

Request body (required JSON)

A JSON object.

Status Meaning
200 The stored candidate
400 Invalid submission or patch
403 Native seat proof unavailable
409 Patch-id mismatch
503 Reviews or the review store unavailable

GET /v1/fleet/seats/{paneId}/review-candidates/{id} — Read a candidate and its stored patch as its author or reviewer

Requires native seat proof. Only the author and a seat that currently holds the project's reviewer setting may read the patch; others get not_reviewer.

Bearer: none

In Name Required Type Description
path paneId yes string
path id yes string
Status Meaning
200 The candidate and its patch
403 Native seat proof unavailable
404 Unknown candidate

POST /v1/fleet/seats/{paneId}/review-verdicts — Record APPROVE or CHANGES for one exact patch

Requires native seat proof from a seat that currently holds the project's reviewer setting; the author's seat or occupant is refused. patchId must equal the candidate's stored hash. CHANGES needs at least one finding. The verdict reaches the author's seat and, as a notice that asks for no action, the author's lead. A superseded or already decided candidate refuses. The record flags sameHarness when author and reviewer share a harness. ADR 0287.

Bearer: none

In Name Required Type Description
path paneId yes string

Request body (required JSON)

A JSON object.

Status Meaning
200 The candidate with its verdict
400 Invalid verdict
403 Native seat proof unavailable
404 Unknown candidate
409 Superseded

POST /v1/fleet/seats/{paneId}/hook — Report a hired seat's lifecycle hook

The clankie-worker plugin's hooks, forwarded by clankie seat-hook from inside the seat's pane (VUH-1458). A Stop or StopFailure settles the seat's turn for its adapter and any completion watch, with the harness's own final text as lastMessage. The session must be the Claude session herdr reports in that pane. Lifecycle reports accept the operator or bound fleet lane. Only native process proof from the request transport can register or drain a next-turn receiver. UserPromptSubmit may return additionalContext and messageIds, with deliveryStage uncertain until the hook writes stdout and posts deliveredMessageIds on the same session. That acknowledgment confirms bridge delivery, never model consumption. Held mail expires within 24 hours; an uncertain take is never replayed. NativeActivity is a separate original-native child-activity report: it requires transport process admission and the exact native producer PID, session, instance timestamp and increasing sequence. It expires after fifteen seconds and never settles a turn, drains mail or grants authority. Its bounded children list carries exact local agent IDs, native state and original state-change time. Claude root turns remain unsupported by this activity projection; a root turn's generated agent ID is not a root proof.

Bearer: operator or captain

In Name Required Type Description
path paneId yes string

Request body (required JSON)

{
  "schemaVersion": 1,
  "event": "Stop",
  "sessionId": "10000000-0000-4000-8000-000000000001",
  "lastMessage": "Tests pass."
}
Status Meaning
200 Recorded
400 Not a seat hook
403 Not the operator lane
404 That pane holds no Claude seat with this session

GET /v1/fleet/seats/{paneId}/tool-catalog — Long-poll a fleet seat's catalog revision

For a worker bridge without the seat channel, such as a Codex seat (VUH-2390). With revision equal to the seat's current catalog revision it parks for up to wait ms (capped at 30000) and returns early when a refresh request, a deploy or the fleet tool and peer settings change it; otherwise it answers at once. The bridge lists its tools only when the revision differs from the one it listed. Never reads or binds the seat's mailbox, and grants nothing. Same pane admission as the mailbox. A service before this route answers 404; the bridge then keeps its five-second check.

Bearer: operator or captain

In Name Required Type Description
path paneId yes string
query wait no integer, 0–30000, default 0
query revision no string
Status Meaning
200 The seat's current catalog revision, also in the x-clankie-catalog-revision header (application/json)
403 Fleet admission or native pane identity refused
503 Worker catalog unavailable (worker_catalog_unavailable)

POST /v1/fleet/seats/{paneId}/tool-catalog — Report the occupying native harness's accepted Clankie tools

A linked Claude mod or Codex startup probe reports raw Clankie bridge names from the actual native session catalog. The service verifies the current pane, harness and session against Herdr, compares the bridge's served expectations and retains a matched/mismatch/unverified diagnostic. This report never grants tools or routes messages. Native probe failures carry error and remain unverified; process liveness is separate evidence.

Bearer: operator or captain

In Name Required Type Description
path paneId yes string

Request body (required JSON)

A JSON object.

Status Meaning
200 Session-bound status
400 Invalid native catalog report
403 Fleet admission or native pane/session identity refused

POST /v1/conversation-heads — Designate or clear an explicit escalation head

Operator only. Owner must be an existing runnable or canonical room conversation; head must be a writable global/workspace conversation. Rejects self/cycles. Grants no room authority.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Updated conversation projection
400 Invalid strict request
401 Operator authentication required
409 Owner/head unavailable or cycle

GET /v1/body-leases — Conversation ownership of Clankie's body resources

Operator or active paired device observe grant. Read-only public projection; no incarnation, actor, room text or request content.

Bearer: operator or device

Status Meaning
200 Public body lease status (application/json)
403 Observe authority required

POST /v1/body-leases — Explicitly acquire, renew, release, queue, ask or recover a body resource

Computer ownership uses /v1/computer; this endpoint refuses computer mutations. Strict BodyLeaseRequest protocol union. Operator bound to a selected runnable conversation. Renew/release require the acquisition incarnation. Ordinary release is owner-only and confirms termination; explicit recover uses the current private host claim under operator authority. Queue/ask are bounded notifications and never run body effects.

Bearer: operator

Request body (required JSON)

{
  "action": "queue",
  "resource": "voice",
  "conversationId": "conversation-1",
  "request": "Notify me when voice is free",
  "ttlMs": 300000
}
Status Meaning
200 Typed acquired, renewed, released, queued or asked result
409 Typed busy with public holder and queue/ask choices, or rejected reason; no silent takeover

POST /v1/computer/authority — Recheck the owning conversation's computer authority

Native observation hosts delegate their existing operator bearer and bound conversation to this service before each operation. Uses the same identity and grant checks as /v1/computer, even without a local adapter. A conversation ID is not a grant. Nothing is captured, driven or leased.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Matching conversationId and authorized true
400 Invalid strict request
401 Absent or revoked operator conversation authority
413 Request exceeds 4 KiB

POST /v1/computer — Drive the conversation-leased computer body

Strict ComputerRequestSchema (conversationId, optional joined machineId and command) from @clankie/interactive-environment. Operator authority bound to an existing runnable conversation, rechecked at each input. Actions: status, acquire, renew, release, revoke, recover, inventory, capture, frame, input. Capture returns fresh screenshot metadata and image-pixel coordinate mapping; frame returns bounded PNG media separately. Input is ordered and uses screenshotId plus a persistent requestId; identical retries reconcile, never replay. Failed and uncertain are distinct from confirmed. Expiry/restart/uncertainty retain the lease until host stop proof. An expired local macOS lease also permits explicit operator recover with ownerRecovery {reason, expectedHolder, expectedExpiresAt}. This independently reauthorizes the same operator, requires no service-tracked holder work or computer operation, and syncs a decision audit before exact-incarnation release. It accepts unknown native drain; it does not prove termination. Refusals provide detail and next guidance. Windows and joined screens refuse this override. Local macOS Peekaboo and an explicitly attached Windows native-harness host, read-only unless its owner explicitly sets allowInput true before acquisition; lease and status record that choice. Opted-in full Windows clients capture native accessibility strings and accept one foreground primitive per fresh observation, with an exact changed accessibility postcondition (input.expect.field/equals); scroll also needs an image-pixel at point. Native dispatch alone cannot confirm an effect. Host Win32 person activity is rechecked before input; shell/system targets and system-switching shortcuts refuse. Every native error retires the host. Input release requires James's W8 live stop proof. Observation-only clients remain read-only. No additional model loop starts. A registered joined machineId selects a lent screen without fallback, including from a hosted service. The host requires fresh screen policy within the original join ceiling and local per-session consent; input is off until locally allowed. Its visible pet Stop fences queued input. Authored Mac and Windows hosts support accessibility press/text and bounded navigation key/drag/scroll with exact changed-field receipts. Keys use a named allowlist; scroll requires an image-pixel anchor and 1-10 ticks. Native observer acknowledgments never release a post-input lease; true queue drain remains unknown. Frame chunks share the authenticated join carrier within existing caps. Real Mac/PC driving and native stop proof are live gaps.

Bearer: operator

Request body (required JSON)

{
  "conversationId": "global-default",
  "command": {
    "action": "status"
  }
}
Status Meaning
200 Command result or typed busy/rejected receipt
400 Invalid strict request
401 Operator conversation authority required
409 Stale reference
413 Request exceeds 2 MiB
503 Computer body unavailable on this host

GET /v1/captain/readiness — Read secret-free chat setup readiness

Any active paired device or owner operator may read this. A live native operator bridge reports ready independently of the fallback model. Otherwise the shared captainReadiness rule reports no_model or no_credential, with model and provider ids when known. No credential material or authentication method leaves the body. Responses are no-store.

Bearer: operator or device

Status Meaning
200 Ready boolean, optional model/providerId, and reason when unready
401 Authentication required
503 Readiness unavailable

Discord

GET /v1/discord/settings — Read Discord server roles, owners, room skills, fleet and tracking

Operator-authorized non-secret settings, their revision and the shared setup definition. Normal setup connects a server with participant or admin, fleetEnabled and trackingLevel (off, project_updates, project_activity, all_issues). Raw IDs and machine grants stay under Advanced. The role-correct invitation and gateway checks are read-only.

Bearer: operator

Status Meaning
200 settings, revision and optional setup definition, role invite and permission checks
403 Operator authority required

POST /v1/discord/settings — Save revision-fenced non-secret Discord settings

Requires settings and expectedRevision. servers records role and owners (me, everyone or role with ownerRoleId); roomSkills records a serverId, channelId and known skill. houseHuntingAuthorBindings records explicit household, userId, legacyAuthor and ownerConfirmed=true entries; display names never establish identity. Each household/legacy label binds to one ID. Binding alone changes no feedback; only new ID-attributed reconsiderations record legacy targets. Omitted ownership/binding fields from older clients are preserved. Legacy guild/channel machine grants are retired. Connecting a server projects its ingress, presence and voice scope while preserving machine grants and lab opt-in. Stale writes are refused. Saving never posts to Discord. Admin actions refuse server deletion and ownership transfer at the body.

Bearer: operator

Status Meaning
200 Saved settings, new revision and setup metadata
400 Invalid or unknown settings
403 Operator authority required or revoked
409 Settings revision changed

POST /v1/discord/setup/test-post — Explicitly send one owner-requested setup message to a text room

Settings-level operator authority is required; Observe or Steer cannot post. The current settings revision, connected account and Send Messages evidence are checked before dispatch. Reads, setup opening and picker edits never call this operation. Missing native receipts are unconfirmed and never retried.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 posted with messageId, unavailable with reason, or unconfirmed with post_receipt_unavailable
400 Invalid request
403 Operator authority required or revoked
409 Settings or active account configuration changed

POST /v1/discord/ingress — Admit an encrypted Discord turn or scoped voice callback

Remote connection API, not an operator bearer. P-256 ECDH and AES-GCM protect request and response; a 60-second Ed25519 fleet permit binds the tenant, installation, event digest and ephemeral response recipient. Durable delivery dedupe prevents repeated captain effects. Voice callbacks use the existing briefing, attributed captain handoff and three voice self-tools. See docs/discord-ingress.md.

Bearer: none

Request body (required JSON)

A JSON object.

Status Meaning
200 Sealed pending, reply, voice operation, silent or failed result
401 Invalid, expired, unsealed or wrongly scoped event
409 Delivery id already binds another event
413 Envelope exceeds the byte limit
429 Durable inbox is at capacity
503 Durable admission unavailable

GET /v1/discord/user-session/opt-in — Current user-session opt-in

Bearer: captain or operator

Status Meaning
200 Opt-in or null

POST /v1/discord/stream-watch — Bridge report of shares and optional stills

Bearer: captain

Status Meaning
204 Report accepted

GET /v1/discord/readiness — Discord captain readiness

Requires a Discord text or voice bridge bearer.

Bearer: discord text or discord voice

Status Meaning
200 Ready
503 A required check is down

POST /v1/discord/voice-briefing — Compose the realtime voice briefing

Voice-bridge bearer only. Request carries ids; persona is owner-authored.

Bearer: discord voice

Request body (required JSON)

{
  "schemaVersion": 1,
  "guildId": "123456789012345678",
  "channelId": "123456789012345679",
  "consentedUserIds": [
    "123456789012345680"
  ]
}
Status Meaning
200 Bounded instructions + briefing

POST /v1/discord/presence-session-events — Apply a Discord presence phase event

Bearer: discord text or discord voice

Request body (required JSON)

A JSON object.

Status Meaning
200 Accepted or idempotent replay

GET /v1/discord/presence-sessions — Full presence session records

Bearer: captain

Status Meaning
200 Session list

GET /v1/discord/voice-history — Completed voice stays

Bearer: captain

In Name Required Type Description
query limit no integer, 1–32, default 5
Status Meaning
200 Recent stays

POST /v1/discord/presence-actions — Execute a policy-gated Discord action

Needs a live-session claim in headers: x-clankie-discord-presence-session, x-clankie-discord-presence-phase, x-clankie-discord-presence-revision. reconcile=1 performs a read-only reply-history check for the original admitted message. Returns {reply: result} when found, or {reply: null} only after complete history proves absence. Unknown or stale authority refuses; it never posts or clears an active predecessor's write.

Bearer: discord text or discord voice

In Name Required Type Description
query reconcile no integer, one of 1 Read-only reconciliation instead of executing the action
header x-clankie-discord-presence-session yes string
header x-clankie-discord-presence-phase yes string
header x-clankie-discord-presence-revision yes integer

Request body (required JSON)

{
  "schemaVersion": 1,
  "idempotencyKey": "yaak-typing-1",
  "action": "discord.presence.typing_start",
  "identity": {
    "presenceSessionId": "replace-me",
    "correlationId": "yaak-1",
    "profileHash": "unversioned",
    "characterId": "clankie",
    "credentialRef": "discord_bot",
    "transportKind": "bot"
  },
  "payload": {
    "kind": "typing_start",
    "channelId": "123456789012345679"
  }
}
Status Meaning
200 Action result
409 Stale live claim or action unavailable

Memory

GET /v1/memory — Browse every memory note and Discord person fact

Notes persist until forgotten. Catalog retention fields remain legacy compatibility metadata and no longer impose a count quota.

Bearer: operator

Status Meaning
200 Complete operator-only memory catalog

POST /v1/memory/discord-people/proposals — Upsert a Discord person fact

Bearer: discord text or discord voice

Request body (required JSON)

{
  "schemaVersion": 1,
  "proposalId": "yaak-proposal-1",
  "fact": {
    "schemaVersion": 1,
    "factId": "yaak-fact-1",
    "subject": {
      "guildId": "123456789012345678",
      "userId": "123456789012345680"
    },
    "kind": "person-fact",
    "body": "Prefers short replies.",
    "visibility": {
      "scope": "guild"
    },
    "provenance": {
      "correlationId": "yaak-1",
      "sourceEventId": "yaak-src-1",
      "sourceSurface": "discord_text",
      "rawTranscript": false
    },
    "confidence": 0.8,
    "createdAt": "2026-08-15T20:00:00.000Z",
    "updatedAt": "2026-08-15T20:00:00.000Z"
  }
}
Status Meaning
201 Stored

GET /v1/memory/discord-people/{guildId}/{userId} — Recall Discord person facts

Bearer: discord text or discord voice

In Name Required Type Description
path guildId yes string
path userId yes string
query channelId no string
query query no string
Status Meaning
200 Facts and optional recall card

DELETE /v1/memory/discord-people/{guildId}/{userId} — Delete every fact for a Discord person

Bearer: operator

In Name Required Type Description
path guildId yes string
path userId yes string
Status Meaning
200 Deleted ids

GET /v1/memory/discord-people/{guildId}/{userId}/export — Operator export of a Discord person

Bearer: operator

In Name Required Type Description
path guildId yes string
path userId yes string
Status Meaning
200 Export bundle

PATCH /v1/memory/discord-people/{guildId}/{userId}/{factId} — Edit one Discord person fact without changing its identity or provenance

Bearer: operator

In Name Required Type Description
path guildId yes string
path userId yes string
path factId yes string

Request body (required JSON)

{
  "body": "Prefers concise replies.",
  "confidence": 0.9
}
Status Meaning
200 Updated fact
404 Fact not found

DELETE /v1/memory/discord-people/{guildId}/{userId}/{factId} — Forget one Discord person fact

Bearer: operator

In Name Required Type Description
path guildId yes string
path userId yes string
path factId yes string
Status Meaning
204 Forgotten

GET /v1/memory/captain-episodes — Recall memory notes for a lane

Without query, the bounded recent card. With one, on-demand search over every persistent note, filtered by what that lane may see. Both branches answer with a rendered card and never with note records, so no caller reads another memory's provenance ids.

Bearer: captain

In Name Required Type Description
query lane yes string, one of operator, discord_voice, discord_presence, gameplay
query query no string Search terms; every term must appear in the note or the room it happened in.
query limit no integer, 1–… Matches to return (default 8, capped at 32).
Status Meaning
200 Recall card — the recent one, or the search's when a query was given

POST /v1/memory/captain-episodes — Record a self-authored memory note

Recording only ever adds. An id the store already holds is a conflict, not an update; a byte-identical retry returns the original. Editing an existing note goes through PATCH. A Discord bearer may only write the lane it serves (discord_text writes discord_presence, discord_voice writes its own). The trusted authenticator must also supply an exact admitted episodeSource. A generic bearer alone is refused. The host stamps sourceConversationId and provenance; request-supplied source identifiers confer no authority. Notes persist until forgotten. The optional retained field is legacy compatibility metadata and does not control lifetime or a count quota.

Bearer: captain

Request body (required JSON)

{
  "schemaVersion": 1,
  "episodeId": "yaak-ep-1",
  "lane": "operator",
  "targetId": "self",
  "summary": "Tried the HTTP API from Yaak.",
  "visibility": "operator_private",
  "provenance": {
    "characterId": "clankie",
    "sessionId": "captain",
    "selfAuthored": true,
    "rawTranscript": false
  },
  "occurredAt": "2026-08-15T20:00:00.000Z"
}
Status Meaning
200 Recorded id
403 Missing exact host source binding, or lane/target does not match that source
409 The note id already exists with different content. Nothing was changed.

PATCH /v1/memory/captain-episodes/{lane}/{episodeId} — Edit one memory note or its visibility

Explicit operator management can edit notes across source conversations. The retained field remains accepted as legacy compatibility metadata; every note persists until forgotten regardless of its value.

Bearer: operator

In Name Required Type Description
path lane yes string, one of operator, discord_voice, discord_presence, gameplay
path episodeId yes string

Request body (required JSON)

{
  "summary": "Corrected note about what happened.",
  "visibility": "operator_private"
}
Status Meaning
200 Updated note
404 Note not found
409 Legacy capacity refusal; persistent notes no longer use retention quotas

DELETE /v1/memory/captain-episodes/{lane}/{episodeId} — Forget one memory note

Bearer: operator

In Name Required Type Description
path lane yes string, one of operator, discord_voice, discord_presence, gameplay
path episodeId yes string
Status Meaning
204 Forgotten

Embodiment

GET /v1/games/configuration — Pokémon play defaults

Bearer: operator or captain

Status Meaning
200 Gameplay settings and restart instruction. An absent token override defaults to 250000 charged tokens.

PUT /v1/games/configuration — Replace gameplay configuration for subsequent sittings

Owner operator or a device with Take Control. Restart Clankie to apply defaults. Usage caps include mind, commentary and interrupted decisions; the last call can cross a threshold. Missing usage reserves 16000 tokens and makes estimated cost unknown, which stops a dollar-capped session.

Bearer: operator or device

Request body (required JSON)

A JSON object.

Status Meaning
200 Updated gameplay configuration and restart instruction
400 Invalid configuration
401 Authentication required
403 Owner authority required
503 Settings unavailable

POST /v1/embodiment/intents — Ask to start or stop play

Select an existing writable captain conversation with conversationId. The operator identity is authenticated separately; originLane and requestedBy are host-stamped. A competing body lease returns a typed refusal. In-process captain tools carry their own admitted conversation identity. Budget accepts maxTokens (default 250000), maxCostUsd, maxTurns and maxDurationMs. Terminal receipts distinguish stopped, budget_exhausted, mind_unavailable and world_ended.

Bearer: operator

Request body (required JSON)

start

{
  "kind": "start",
  "schemaVersion": 1,
  "intentId": "yaak-start-1",
  "conversationId": "replace-with-selected-conversation",
  "originLane": "operator",
  "requestedBy": "local-operator",
  "requestedAt": "2026-08-15T20:00:00.000Z",
  "environmentId": "pokemon-firered",
  "budget": {
    "maxTokens": 250000,
    "maxCostUsd": 1
  }
}

stop

{
  "kind": "stop",
  "schemaVersion": 1,
  "intentId": "yaak-stop-1",
  "conversationId": "replace-with-selected-conversation",
  "originLane": "operator",
  "requestedBy": "local-operator",
  "requestedAt": "2026-08-15T20:00:00.000Z",
  "sessionId": "replace-me"
}
Status Meaning
200 Accepted, refused, or stop requested. A stop request does not prove that the executor has ended.
409 Body lease refusal with bodyLease naming the held conversation or missing authority; queue or ask rather than taking over.

GET /v1/embodiment/sessions/live — Live play session

Captain or operator.

Bearer: operator or captain

Status Meaning
200 { session } or { session: null }

POST /v1/embodiment/sessions/live/stop — Operator kill-switch (ordinary stop intent)

Bearer: operator

Status Meaning
200 Stop submitted
404 Not playing

POST /v1/embodiment/sessions/live/guide — Suggest an objective or approach to the owning Pokémon mind

Requires the selected conversation's live play ownership and current authority. Direction is bounded context; the play mind chooses its own objective and action. Does not start play.

Bearer: operator

Request body (required JSON)

A JSON object.

Status Meaning
200 Queued direction or not_playing refusal
400 Invalid direction
401 Operator authentication required
403 Selected conversation authority required
409 Play ownership or authority changed
503 Play direction unavailable

GET /v1/embodiment/sessions/live/activity — Present-tense self-observation

Bearer: operator or captain

Status Meaning
200 not_playing, pending, or snapshot

GET /v1/embodiment/sessions/live/still — One still of the live play screen

Read-only glance. PNG as base64. No controller.

Bearer: operator or captain

Status Meaning
200 not_playing, pending, or still

GET /v1/embodiment/sessions/live/story — Bounded story of this playthrough

Journal projection — objective, maps, last notable moments. Not the raw log.

Bearer: operator or captain

Status Meaning
200 not_playing, pending, or card

GET /v1/embodiment/sessions/{id} — One embodiment session

Bearer: captain

In Name Required Type Description
path id yes string
Status Meaning
200 Session
404 Unknown

Browser

GET /v1/browser/harnesses — Computer-use harnesses here and on linked Windows fleets

Re-probes which installed harnesses (Codex computer use, Claude in Chrome) are signed in and configured for the owner's apps or Chrome (ADR 0199), including Codex on linked Windows fleets. Optional platform and machineId identify those reports; signed-out, disabled and unavailable probes remain explicit. Configuration does not prove app grants or input. Detection only; nothing is started. detected is false on a hosted body.

Bearer: operator

Status Meaning
200 Harness list (application/json)
401 Operator bearer required

GET /v1/browser/tools — Live browser tool catalog

Browser Use Pi tools; native JavaScript is listed only for operators.

Bearer: operator or captain

Status Meaning
200 Catalog
503 Browser host unavailable

POST /v1/browser/call — Call a browser tool

Calls one Browser Use Pi tool in the selected conversation’s tabs and JavaScript workspace, serialized within that conversation only. Conversations share the signed-in Chrome profile; browser_use_open accepts isolated:true for a disposable logged-out context. Browser use has no exclusive body lease. Existing machine authority remains required. Direct captain requests without a host-admitted conversation binding are refused.

Bearer: operator or captain

In Name Required Type Description
header x-clankie-conversation-id yes string Exact selected runnable operator conversation

Request body (required JSON)

{
  "schemaVersion": 1,
  "tool": "browser_use_snapshot",
  "arguments": {}
}
Status Meaning
200 Result or typed refusal

Media

POST /v1/activity/shares — Control owner-authorized Activity media shares

Projects existing play or an exact hash-bound delivered PNG/GIF/MP4/WAV/MP3. Tenant and installation scope are service-assigned. No source path/URL or new capture permission is accepted. Hosted owner controls use the existing encrypted paired-device operator bridge; the private edge verifies the destination and returns a scoped launch/stop receipt. A confirmed invite is not evidence that an audience opened it. Local delegated shares retain their separate read grants; official local admission is a pending decision. Source switch advances generation and invalidates old media/grants. Stop, expiry and producer loss are terminal. Controls never retry; uncertainty carries operation and share/generation when known. Successful responses use Cache-Control no-store. See docs/cli.md#activity-shares.

Bearer: operator

Request body (required JSON)

A JSON value.

Status Meaning
200 List returns sessions; image/switch returns session; grant returns grant and expiresAt; stop returns stopped true
400 Invalid request or PNG media
401 Current owner operator authentication required
404 Exact artifact or active share unavailable
409 Stale generation
429 Local owner share request queue is at capacity
503 Activity unavailable or possibly dispatched private control with typed uncertain outcome

POST /v1/activity/viewer — Read hosted Activity media with a live audience authorization

Internal outbound-body route. Requires a fleet-signed media-only permit bound to the exact session and opaque live edge authorization. The body independently revalidates current audience authority and destination, including on quiet streams. Neither operator nor captain bearer grants this route. The gateway exposes read-only media to an admitted SDK viewer; it never exposes controller credentials or chooses a host from browser input.

Bearer: none

Request body (required JSON)

A JSON object.

Status Meaning
200 Bounded read-only session and PNG/PCM lifecycle envelopes; live authority required throughout (application/x-ndjson)
403 Invalid
503 Hosted Activity unavailable

POST /v1/media/images — Generate or edit an image

Set personaReference true for self-depiction using only owner appearance references, never vibe images or frames. Mutually exclusive with sourceRef. OpenAI and Google support multiple references; the current Grok adapter supports one.

Bearer: operator or captain

Request body (required JSON)

{
  "schemaVersion": 1,
  "prompt": "a small robot sitting at a terminal",
  "aspectRatio": "1:1"
}
Status Meaning
200 ok or refused
503 Media plane unconfigured

POST /v1/media/videos — Start or resume a video render

Bearer: operator or captain

Request body (required JSON)

{
  "schemaVersion": 1,
  "prompt": "a small robot waving",
  "durationSeconds": 6
}
Status Meaning
200 ok, pending, or refused

Pairing

POST /v1/pairing/offer — Mint a one-time pairing offer

The offer secret appears once in the response. Do not log it. Automation may supply run {runId, purpose, ttlSeconds}: purpose is test, proof, simulator or gateway-probe; TTL is 60–3600 seconds (default 900). Redemption persists the fixed run expiry. Cannot combine with review.

Bearer: operator

Request body (optional JSON)

{
  "run": {
    "runId": "capture-123",
    "purpose": "simulator",
    "ttlSeconds": 900
  }
}
Status Meaning
200 Offer wire (deep link + code); ordinary offers also include the existing single-use localCode for same-Mac direct pairing; review offers omit localCode

POST /v1/pairing/runs/{id}/end — End an automation pairing run

Operator-only, idempotent teardown. Cancels unredeemed offers and revokes pending and active devices explicitly marked with this run ID and minted by the authenticated operator. Ordinary owner devices are never selected. Run expiry also revokes after a crash, survives replay and denies auth immediately at the deadline; a 15-second sweep records durable revocation.

Bearer: operator

In Name Required Type Description
path id yes string, matching ^[A-Za-z0-9_-]{1,128}$
Status Meaning
200 revokedDeviceIds array
400 malformed
401 Operator authentication required

POST /v1/pairing/redeem — Redeem an offer into a pending device

Unauthenticated. The offer secret or typed code is the capability.

Bearer: none

Request body (required JSON)

{
  "code": "123-456",
  "device": {
    "name": "Yaak",
    "platform": "macos"
  }
}
Status Meaning
200 Pending device + completion token; a configured gateway also returns the host-scoped base URL

POST /v1/pairing/complete — Activate a pending device

Bearer: none

Request body (required JSON)

{
  "completionToken": "replace-me",
  "acceptedGrants": {
    "chat": true,
    "steer": true,
    "terminalObserve": true,
    "terminalControl": false
  }
}
Status Meaning
200 Device token issued; relayUrl is the host-scoped gateway base when configured; optional directRoute carries explicitly configured controlPlaneUrl and relayUrl origins

POST /v1/hosted/pair-offer — Mint an authenticated encrypted offer for the hosted account page

Managed bodies only. Plain gateway exchange carrying a single-use signed fleet ticket, not an account bearer. Version 2 binds the browser P-256 public-key hash and nonce into the ticket. The body signs the encrypted answer with its fleet-registered Ed25519 key. Replay refusal and the five-per-minute rate limit survive a service restart. See the hosted deployment README for the exact transcript and key derivation.

Bearer: none

Request body (required JSON)

A JSON object.

Status Meaning
200 Signed encrypted offer, with no plaintext link
401 Invalid, expired, misbound, or consumed ticket
404 Self-hosted body
429 Too many offers; Retry-After is 60 seconds
503 Pairing publication or replay persistence unavailable

Devices

GET /v1/composer/transcription/status — Read local or managed availability and included allowance

Active ordinary paired device with chat access only; captain/operator bearers and support devices are refused. Gateway calls preserve the existing encrypted device envelope. No-store; never logs audio or text.

Bearer: device

Status Meaning
200 Availability and bounds (application/json)
400 Invalid request or PCM WAV audio
401 Active paired device session required
403 Forbidden
404 Request does not belong to this device
409 Recording id
413 Request exceeds the bounded chunk envelope
429 Capacity or rate limit reached
503 Managed transcription unavailable

POST /v1/composer/transcription/begin — Begin one bounded composer recording

Active ordinary paired device with chat access only; captain/operator bearers and support devices are refused. Gateway calls preserve the existing encrypted device envelope. No-store; never logs audio or text.

Bearer: device

Request body (required JSON)

A JSON value.

Status Meaning
200 Device-scoped draft receipt; only complete carries text (application/json)
400 Invalid request or PCM WAV audio
401 Active paired device session required
403 Forbidden
404 Request does not belong to this device
409 Recording id
413 Request exceeds the bounded chunk envelope
429 Capacity or rate limit reached
503 Managed transcription unavailable

POST /v1/composer/transcription/chunk — Append one recording chunk at an exact byte offset

Active ordinary paired device with chat access only; captain/operator bearers and support devices are refused. Gateway calls preserve the existing encrypted device envelope. No-store; never logs audio or text.

Bearer: device

Request body (required JSON)

A JSON value.

Status Meaning
200 Device-scoped draft receipt; only complete carries text (application/json)
400 Invalid request or PCM WAV audio
401 Active paired device session required
403 Forbidden
404 Request does not belong to this device
409 Recording id
413 Request exceeds the bounded chunk envelope
429 Capacity or rate limit reached
503 Managed transcription unavailable

POST /v1/composer/transcription/commit — Transcribe a completed recording once

Active ordinary paired device with chat access only; captain/operator bearers and support devices are refused. Gateway calls preserve the existing encrypted device envelope. No-store; never logs audio or text.

Bearer: device

Request body (required JSON)

A JSON value.

Status Meaning
200 Device-scoped draft receipt; only complete carries text (application/json)
400 Invalid request or PCM WAV audio
401 Active paired device session required
403 Forbidden
404 Request does not belong to this device
409 Recording id
413 Request exceeds the bounded chunk envelope
429 Capacity or rate limit reached
503 Managed transcription unavailable

POST /v1/composer/transcription/cancel — Discard a recording and prevent late draft delivery

Active ordinary paired device with chat access only; captain/operator bearers and support devices are refused. Gateway calls preserve the existing encrypted device envelope. No-store; never logs audio or text.

Bearer: device

Request body (required JSON)

A JSON value.

Status Meaning
200 Device-scoped draft receipt; only complete carries text (application/json)
400 Invalid request or PCM WAV audio
401 Active paired device session required
403 Forbidden
404 Request does not belong to this device
409 Recording id
413 Request exceeds the bounded chunk envelope
429 Capacity or rate limit reached
503 Managed transcription unavailable

POST /v1/composer/transcription/receipt — Reconcile the same recording without repeating provider dispatch

Active ordinary paired device with chat access only; captain/operator bearers and support devices are refused. Gateway calls preserve the existing encrypted device envelope. No-store; never logs audio or text.

Bearer: device

Request body (required JSON)

A JSON value.

Status Meaning
200 Device-scoped draft receipt; only complete carries text (application/json)
400 Invalid request or PCM WAV audio
401 Active paired device session required
403 Forbidden
404 Request does not belong to this device
409 Recording id
413 Request exceeds the bounded chunk envelope
429 Capacity or rate limit reached
503 Managed transcription unavailable

GET /v1/devices/self/diagnostics-default — Read the account diagnostics default

Returns only diagnosticsDefault. A hosted body reads it through its signed fleet settings request; unavailable account authority returns 503. Self-hosted bodies use the existing true default. No-store.

Bearer: operator or device

Status Meaning
200 Object with diagnosticsDefault boolean only
401 Authentication required
503 Account settings unavailable

GET /v1/devices — List paired devices

Owner operators and active paired devices may read these secret-free rows. With grouped=true, shared push registrations on the same platform become one row with pairingIds and the maximum lastSeenAt. The exact GET query is also supported through encrypted gateway transport; other query forms remain refused there. Active registrations take precedence over revoked ones, then newest creation. Automation rows stay separate and include run metadata. Revoke every pairingId explicitly to remove a grouped device's access; listing never revokes a device. Optional lastSeenAt records successful authenticated device activity, at most once per minute per device. push carries the device's last delivery state — { registrationId, sequence, enabled } — so the listing is truthful about a device that turned notifications off or whose registration the gateway invalidated. The APNs token and delivery key are never here (ADR 0159).

Bearer: operator or device

In Name Required Type Description
query grouped no boolean, default false
Status Meaning
200 Secret-free device rows

POST /v1/devices/{id}/revoke — Revoke a device

Paired callers require Take Control. Local revocation is durable before the hosted security and wake-key updates. A 503 does not confirm success; retry the same device id. Fleet tombstones defeat restored old disks.

Bearer: operator or device

In Name Required Type Description
path id yes string
Status Meaning
200 Revoked row
403 Take Control required
404 Unknown
503 Hosted revocation could not be confirmed

GET /v1/devices/self — Device reads its own registration

Bearer: device

Status Meaning
200 Self row, including optional directRoute with explicitly configured controlPlaneUrl and relayUrl origins

POST /v1/devices/wake-key — Register a paired device wake public key on a managed body

Managed bodies only; self-hosted installations answer 404. The gateway carries this route inside the encrypted device envelope. The live device session selects deviceId; callers cannot select a different device. Registration and device revocation are serialized. Revocation disables local access immediately, then removes the fleet key, retrying failures.

Bearer: device

Request body (required JSON)

A JSON object.

Status Meaning
200 Registered; returns deviceId
400 Malformed public key request
401 Device session is unknown, expired, or revoked
404 Self-hosted body
503 Fleet registration unavailable; retry later

POST /v1/devices/self/push — Device records or clears its push delivery reference

Body is { registrationId, sequence, enabled }. The host stores only the reference, its version and whether delivery is on — never the APNs token or the delivery key, which the app registers with the gateway directly (ADR 0159). Disabling records that state at its version rather than forgetting it, so ordering survives it.

An older sequence is 409 stale_push_registration. The same sequence is accepted only when it restates what was already recorded: a different registrationId, or the same one with enabled flipped, is 409 conflicting_push_registration. That is also what refuses a re-enable at the version a gateway invalidation was recorded against.

Bearer: device

Status Meaning
200 Accepted reference, echoed with its enabled state
400 Malformed body
401 Device session is unknown, expired, or revoked
409 Stale or conflicting registration version

POST /v1/devices/self/session/refresh — Renew a device session token

Bearer: device

Status Meaning
200 New token; relayUrl republishes the host-scoped gateway base when configured; optional directRoute carries explicitly configured controlPlaneUrl and relayUrl origins

Support

GET /v1/support/grants — Read owner-issued support grants

Exact active owner device with terminalControl or the local operator; captain and support-device authority are refused. Hosted inner requests require the hosted account operator device and cannot fall back to local operator authority.

Bearer: operator or device

Status Meaning
200 Grant history with body-only support references (application/json)
403 Owner authority required

POST /v1/support/grants — Create a support window of at most 72 hours

Owner authority only. Mandatory audit failure refuses creation on hosted bodies; 1024 concurrent unexpired original windows includes revoked tombstones until their original expiry.

Bearer: operator or device

Request body (required JSON)

A JSON value.

Status Meaning
200 Active grant (application/json)
400 Invalid support grant
403 Owner authority required
409 Support window capacity reached
503 Support audit or storage unavailable

POST /v1/support/grants/{id}/revoke — Revoke support access

Owner authority only. Durable terminal state closes support reads before audit retries and remains closed after restart.

Bearer: operator or device

In Name Required Type Description
path id yes string
Status Meaning
200 Current revoked or expired grant (application/json)
403 Owner authority required
404 Grant not found

POST /v1/support/grants/{id}/pairing-offer — Offer pairing for an active read-state support grant

Owner authority only. Offers expire no later than five minutes or the grant window. All four ordinary device grants are false; the relay admits only the closed state/history read allowlist. Shell grants refuse pairing. Publishing rechecks owner authority and live grant before installing the offer.

Bearer: operator or device

In Name Required Type Description
path id yes string
Status Meaning
200 Read-state pairing offer wire
403 Owner authority required
409 support_pairing_requires_read_state
410 Grant inactive or expired
503 Public gateway unavailable

POST /v1/hosted/support — Apply an exact command authorized by a hosted account ticket

Separate support crypto domain and durable one-use ticket fence. The signed ticket binds account, tenant, installation, exact command digest, browser key and nonce, with at most 120 seconds lifetime. No bearer fallback. Replies use authenticated Ed25519 plus ECDH/HKDF/AES-GCM; support references remain outside fleet metadata and central audit.

Bearer: none

Request body (required JSON)

A JSON object.

Status Meaning
200 Encrypted version-2 response with ephemeralPublicKey
401 Invalid
404 Hosted pairing unavailable on this body
429 Support ticket rate limit reached
503 Durable ticket admission or command unavailable

Workers

POST /v1/machine-joins/start — Advertise a pending outbound machine with a five-minute approval window

Strict body {name, platform: darwin|win32|linux, directories, claimSecret, approvalHash}. claimSecret is a fresh 32-byte base64url status claim, not execution authority. The client generates a separate 32-byte approval CODE locally and sends only its SHA-256 approvalHash; never send CODE through the gateway bootstrap. No identity or execution rights are accepted from the sender. At most 32 pending tickets, 64 registered machines; maximum body 16 KiB. Production gateway routing/admission remains a clankie-ops dependency.

Bearer: none

Request body (required JSON)

A JSON object.

Status Meaning
200 joinId and expiresAt; no approval secret or execution capability
400 Invalid advertisement or capacity exceeded
503 Join registry unavailable

POST /v1/machine-joins/status — Claim the approved registration with the initiating host secret

Strict {joinId}; Authorization Bearer claimSecret. Only the original initiating claim can retrieve sealedLease. The lease {machineId, token, accessLevel, directories} is AES-256-GCM sealed under the locally generated approval CODE and bound to joinId; the gateway cannot read or forge it. Unknown, expired or mismatched claims return expired.

Bearer: none

Request body (required JSON)

A JSON object.

Status Meaning
200 pending
400 Malformed claim

POST /v1/joined-machines/challenge — Fresh one-use machine request challenge

Strict {machineId}. Returns a 32-byte base64url challenge bound to a registered canonical join identity, expiring in 60 seconds. At most 512 live challenges. No capability or execution authority is returned.

Bearer: none

Request body (required JSON)

A JSON object.

Status Meaning
200 challenge
403 Revoked or unknown registration
503 Challenge unavailable

POST /v1/joined-machines/channel — Authenticated encrypted policy and one-shot work exchange

Strict {machineId, challenge, requestId, sealedRequest}. No bearer. AES-256-GCM request key derives from the broker-owned scoped capability; AAD binds request direction, machineId, requestId and the one-use challenge. Encrypted payload is {op: poll, results: [...], responseSecret} with at most 16 results. Worker/shell output remains 8,192 characters with a truncated flag. Structured screenOutput is separately bounded to 65,536 characters and never truncated. Screen frames use 49,152-character chunks; the sender measures result batches within a 750,000-byte JSON budget. Response sealedResponse encrypts current policy and at most 16 requests under the fresh independent responseSecret and response-direction AAD. Challenge is consumed before dispatch; neither ciphertext nor lost work delivery is replayable. Maximum body 2 MiB. The receiver independently checks current policy intersected with the original approved ceiling and canonical directory intersection. Raising beyond original consent needs a new owner-approved join. Native worker adapters remain unavailable; a screen host requires local session consent. Gateway routing reveals only metadata; the gateway cannot read or forge capabilities or work.

Bearer: none

Request body (required JSON)

A JSON object.

Status Meaning
200 sealedResponse containing current policy and one-shot requests
403 Revoked or invalid machine envelope; retain credential unless revoked
503 Join registry unavailable

POST /v1/joined-machines/leave — Durably revoke this machine capability

Same authenticated envelope as channel, with encrypted {op: leave, results: [], responseSecret}. No bearer. Fresh challenge consumed before revocation; sealedResponse acknowledges removal. Revoked tokens cannot resume; a new owner approval is required. Maximum body 16 KiB.

Bearer: none

Request body (required JSON)

A JSON object.

Status Meaning
200 sealedResponse containing ok acknowledgement
403 Already revoked
503 Leave unconfirmed; retain credential

GET /v1/machines/access-refusals — Read unresolved machine access refusals for the owner

Bearer: operator

Status Meaning
200 Durable observations, coalesced by machine and required level; resolved grants disappear (application/json)
401 Owner authentication required
503 Machine inventory or authentication unavailable

GET /v1/machines/shell-audit — Read Clankie's recent shell calls on joined machines

Each call is recorded before anything reaches the joined machine and updated with its outcome. The command is kept here only as a SHA-256 digest (its text remains in the session transcript); the exit code is as the joined machine's receiver reported it. unknown means no result arrived in time.

Bearer: operator

Status Meaning
200 The most recent calls, oldest first (application/json)
401 Owner authentication required
503 Machine inventory or authentication unavailable

GET /v1/worker-mcp — MCP session stream

Bearer: worker

Status Meaning
200 MCP stream
403 Worker grant unavailable

POST /v1/worker-mcp — Initialize a worker MCP session or list/call its granted tools

Standard Streamable HTTP MCP. Every request validates expiry, durable revocation and account binding. MCP sessions are bound to one grant. No operator tools or channel capabilities are exposed.

Bearer: worker

Status Meaning
200 MCP response
202 MCP notification accepted
401 Worker bearer required
403 Grant unavailable or session belongs to another grant
404 MCP session unavailable

DELETE /v1/worker-mcp — Close an authenticated worker MCP session

Bearer: worker

Status Meaning
200 Session closed
403 Worker grant unavailable