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 |