{"openapi":"3.1.0","info":{"title":"Hey Taby Local Integrations API","version":"1.2.0-preview","summary":"Per-connection local REST capabilities for the running Hey Taby desktop app.","description":"Developer Preview. This contract describes the inbound local loopback server embedded in the Hey Taby desktop app, not an API hosted at heytaby.com. Enable it in Settings > Integrations > Local API & MCP, then create a named connection with only the permissions it needs. App-managed mode binds to 127.0.0.1:43123. A connection's opaque Bearer token is revealed only when created or rotated; Settings also provides copied MCP/HTTP setup, rotation, revocation, target tests, and recent redacted activity. Eight permission booleans gate status and discovery, digital display, physical display, prompts, Brain reads, task reads, task writes, and task deletion. Prompt access depends on a granted display target, while task write and delete include task read. MCP tool discovery uses the same permissions; there is no universal core tool set. brain.read is mutation-blocked but may use Taby read tools and data, including tasks, even when direct tasks.read is absent. Local scripts, n8n, and MCP agents call Taby; Taby's Brain does not yet act as an outbound MCP client or invoke Gmail, n8n, or user MCP servers. Tasks are the only current structured productivity-data domain; reminders, notes, focus, schedule, habits, pages, and pins are planned and have no current MCP tools or REST routes. Task reconciliation is polling-based using stable IDs and updatedAt; there is no change-feed cursor or webhook. Display-action acceptance means handoff to the companion runtime, not proof of rendering or delivery. Choice prompt creation is asynchronous and is not proof of presentation or selection. Prompt results must be polled and are retained only in memory for up to ten minutes and 100 records in the current app run; app restart clears them, and there is no push callback or webhook. Task idempotency retains identical success and failure outcomes for five minutes in the current app process without re-execution. After expiry, timeout, or restart, callers must reconcile state before retrying a create. Environment variables and the private endpoint descriptor remain an advanced legacy/source-build mode managed outside Settings."},"externalDocs":{"description":"AI-readable Hey Taby integration context","url":"https://www.heytaby.com/docs/ai.txt"},"servers":[{"url":"http://127.0.0.1:{port}","description":"The running local Hey Taby desktop app. App-managed Settings connections use fixed port 43123; the advanced environment mode may override it.","variables":{"port":{"default":"43123","description":"Fixed app-managed port. Only advanced environment/source-build mode may override this value and publish a private endpoint descriptor."}}}],"tags":[{"name":"Discovery","description":"Reachability and high-level local runtime discovery."},{"name":"Display","description":"Bounded digital and physical companion actions. Acceptance is not a display receipt."},{"name":"Prompts","description":"Asynchronous, bounded two-choice prompts shared across digital and physical Taby."},{"name":"Brain","description":"Completed, local-provider answers with domain mutations blocked."},{"name":"Tasks","description":"Scoped task reads and mutations using stable UUIDs and privacy-safe task projections."},{"name":"Diagnostics","description":"Recent redacted integration decisions from the current app run."}],"security":[{"localBearer":[]}],"paths":{"/v1/health":{"get":{"operationId":"getIntegrationHealth","tags":["Discovery"],"summary":"Check whether the local integration server is reachable","description":"Minimal unauthenticated health check. It does not disclose the app, device, model, or credential state.","security":[],"responses":{"200":{"description":"The local integration server is reachable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/status":{"get":{"operationId":"getIntegrationStatus","tags":["Discovery"],"summary":"Read safe app, target, companion, and local-Brain status","description":"Requires this named connection's status.read permission.","x-taby-required-permission":"status.read","responses":{"200":{"description":"High-level local status without paths, serial numbers, or IP addresses.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/animations":{"get":{"operationId":"listIntegrationAnimations","tags":["Discovery"],"summary":"List approved integration animation IDs","description":"Requires status.read. Returns approved, shipping, renderable animations. Integrations should store a returned canonical ID instead of guessing one.","x-taby-required-permission":"status.read","responses":{"200":{"description":"Approved animation catalog.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnimationsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/logs":{"get":{"operationId":"listIntegrationLogs","tags":["Diagnostics"],"summary":"Read recent redacted integration decisions","description":"Requires status.read. Returns newest-first action decisions from this connection's bounded in-memory log for the current app run. Authentication and transport failures do not appear in this action log. Settings separately shows recent redacted activity across named connections.","x-taby-required-permission":"status.read","parameters":[{"name":"limit","in":"query","required":false,"description":"Number of entries to return.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"Recent redacted integration decisions.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/tasks":{"get":{"operationId":"listIntegrationTasks","tags":["Tasks"],"summary":"List a bounded, privacy-safe task projection","description":"Requires tasks.read. Returns stable task UUIDs, updatedAt, and sanitized task fields only. Linked-note contents, image payloads and paths, launch items, folder IDs, device-template fields, and local paths are omitted. Clients may poll and compare stable IDs and updatedAt, but this bounded list has no updated-since filter, pagination cursor, change feed, subscription, or webhook.","x-taby-required-scope":"tasks.read","parameters":[{"name":"status","in":"query","required":false,"description":"Task lifecycle state to include.","schema":{"type":"string","enum":["open","completed","trashed","all"],"default":"open"}},{"name":"query","in":"query","required":false,"description":"Case-insensitive text filter over the safe task projection.","schema":{"type":"string","maxLength":200}},{"name":"limit","in":"query","required":false,"description":"Maximum number of tasks to return.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"Versioned, bounded task list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createIntegrationTask","tags":["Tasks"],"summary":"Create a task through Taby's normal task service","description":"Requires tasks.write, which also grants tasks.read. An identical idempotency-key retry returns the retained success or failure outcome for five minutes without re-execution. After expiry, timeout, or restart, reconcile before retrying a create.","x-taby-required-scope":"tasks.write","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskCreateRequest"},"examples":{"reviewDocs":{"summary":"Create a dated work task","value":{"title":"Review integration docs","tags":["mcp","docs"],"category":"work","deadline":{"kind":"date","date":"2026-07-31"},"requestId":"task-create-123"}}}}}},"responses":{"201":{"description":"Task created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskMutationResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"408":{"$ref":"#/components/responses/RequestTimeout"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/tasks/{taskId}":{"get":{"operationId":"getIntegrationTask","tags":["Tasks"],"summary":"Read one task by stable UUID","description":"Requires tasks.read. The same privacy-safe task projection is returned for open, completed, or retained trashed tasks.","x-taby-required-scope":"tasks.read","parameters":[{"$ref":"#/components/parameters/TaskId"}],"responses":{"200":{"description":"Versioned task snapshot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskGetResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/TaskNotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateIntegrationTask","tags":["Tasks"],"summary":"Partially update one task","description":"Requires tasks.write. The patch must contain at least one field. Omitted fields remain unchanged; null clears only nullable fields, and a blank description normalizes to null. Duplicate tags are removed case-insensitively. expectedUpdatedAt rejects a stale edit with HTTP 409.","x-taby-required-scope":"tasks.write","parameters":[{"$ref":"#/components/parameters/TaskId"},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskUpdateRequest"}}}},"responses":{"200":{"description":"Current task snapshot and whether a record changed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskMutationResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/TaskNotFound"},"408":{"$ref":"#/components/responses/RequestTimeout"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteIntegrationTask","tags":["Tasks"],"summary":"Move one task to recoverable Trash","description":"Requires the separate destructive tasks.delete grant, which also carries tasks.read because the response includes the current task DTO. This is soft deletion into Taby's 30-day Trash; permanent deletion is not exposed.","x-taby-required-scope":"tasks.delete","parameters":[{"$ref":"#/components/parameters/TaskId"},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskMutationRequest"}}}},"responses":{"200":{"description":"Current trashed task snapshot and whether its state changed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskMutationResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/TaskNotFound"},"408":{"$ref":"#/components/responses/RequestTimeout"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/tasks/{taskId}/complete":{"post":{"operationId":"completeIntegrationTask","tags":["Tasks"],"summary":"Mark one active task complete","description":"Requires tasks.write. Repeating an already-satisfied mutation is safe and can return changed=false.","x-taby-required-scope":"tasks.write","parameters":[{"$ref":"#/components/parameters/TaskId"},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskMutationRequest"}}}},"responses":{"200":{"description":"Current task snapshot after completion.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskMutationResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/TaskNotFound"},"408":{"$ref":"#/components/responses/RequestTimeout"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/tasks/{taskId}/reopen":{"post":{"operationId":"reopenIntegrationTask","tags":["Tasks"],"summary":"Move one completed task back to open","description":"Requires tasks.write. Repeating an already-satisfied mutation is safe and can return changed=false.","x-taby-required-scope":"tasks.write","parameters":[{"$ref":"#/components/parameters/TaskId"},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskMutationRequest"}}}},"responses":{"200":{"description":"Current task snapshot after reopening.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskMutationResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/TaskNotFound"},"408":{"$ref":"#/components/responses/RequestTimeout"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/tasks/{taskId}/restore":{"post":{"operationId":"restoreIntegrationTask","tags":["Tasks"],"summary":"Restore one task from Trash","description":"Requires tasks.write. Repeating an already-satisfied mutation is safe and can return changed=false.","x-taby-required-scope":"tasks.write","parameters":[{"$ref":"#/components/parameters/TaskId"},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskMutationRequest"}}}},"responses":{"200":{"description":"Current task snapshot after restore.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskMutationResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/TaskNotFound"},"408":{"$ref":"#/components/responses/RequestTimeout"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/animations/play":{"post":{"operationId":"playIntegrationAnimation","tags":["Display"],"summary":"Request an approved digital or physical animation","description":"Every requested digital target requires companion.digital.write and every physical target requires device.physical.write. Returns accepted and skipped targets. Animation calls are visual only; use the card endpoint when visible text is required. A 200 response can be a successful no-op when every requested target is skipped. Accepted does not mean delivered or rendered.","x-taby-target-permissions":{"digital":"companion.digital.write","physical":"device.physical.write"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayAnimationRequest"},"examples":{"celebration":{"summary":"Celebrate a completed build","value":{"animationId":"trophy","targets":["digital","physical"],"durationSeconds":4,"requestId":"build-123"}}}}}},"responses":{"200":{"description":"The request was validated and processed. Inspect accepted and skipped targets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisplayResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"408":{"$ref":"#/components/responses/RequestTimeout"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/cards/show":{"post":{"operationId":"showIntegrationCard","tags":["Display"],"summary":"Request a bounded plain-text card","description":"Every requested digital target requires companion.digital.write and every physical target requires device.physical.write. Cards are constrained Hey Taby surfaces, not HTML, Markdown, scripts, links, buttons, or raw device commands. A 200 response can be a successful no-op. Accepted does not mean delivered or rendered.","x-taby-target-permissions":{"digital":"companion.digital.write","physical":"device.physical.write"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShowCardRequest"},"examples":{"buildFinished":{"summary":"Show a build result","value":{"title":"BUILD DONE","subtitle":"desktop passed","tone":"success","animationId":"trophy","targets":["digital","physical"],"durationSeconds":4,"requestId":"build-card-123"}}}}}},"responses":{"200":{"description":"The request was validated and processed. Inspect accepted and skipped targets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisplayResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"408":{"$ref":"#/components/responses/RequestTimeout"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/prompts/choice":{"post":{"operationId":"createIntegrationChoicePrompt","tags":["Prompts"],"summary":"Create an asynchronous two-choice prompt","description":"Requires prompts.write plus companion.digital.write for a digital target and/or device.physical.write for a physical target. Returns a prompt snapshot immediately; it does not wait for presentation or selection. Exactly two choices are required. Digital and physical are two surfaces for the same prompt, and the first valid selection wins. Only one integration prompt may be pending at a time.","x-taby-required-permission":"prompts.write","x-taby-target-permissions":{"digital":"companion.digital.write","physical":"device.physical.write"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChoicePromptRequest"},"examples":{"deployDecision":{"summary":"Ask whether to deploy a completed build","value":{"title":"DEPLOY BUILD?","subtitle":"desktop passed","animationId":"confirmation","targets":["digital","physical"],"timeoutSeconds":30,"requestId":"deploy-prompt-123","choices":[{"id":"deploy","label":"DEPLOY","effect":{"type":"none"}},{"id":"cancel","label":"CANCEL","effect":{"type":"dismiss"}}]}}}}}},"responses":{"200":{"description":"Current asynchronous prompt snapshot. A pending status is not proof of presentation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"408":{"$ref":"#/components/responses/RequestTimeout"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/prompts/{promptId}":{"get":{"operationId":"getIntegrationPromptResult","tags":["Prompts"],"summary":"Poll an asynchronous prompt","description":"Requires prompts.write and returns only a prompt owned by this authenticated named connection. Returns the current status and, after selection, the selected choice, primary/secondary position, digital/physical surface, selection time, and separately tracked effect type and status. Prompt records are retained in memory for up to ten minutes and 100 records in the current app run, then pruned; app restart clears them. There is no push callback, subscription, change feed, or webhook.","x-taby-required-permission":"prompts.write","parameters":[{"$ref":"#/components/parameters/PromptId"}],"responses":{"200":{"description":"Current prompt snapshot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptResponse"},"examples":{"dismissedOnDigital":{"summary":"User selected the secondary DISMISS choice on digital Taby","value":{"ok":true,"data":{"promptId":"c53f2750-0900-4c5a-ad14-f11a785fd893","requestId":"deploy-prompt-123","status":"selected","createdAt":"2026-07-28T18:29:30.000Z","expiresAt":"2026-07-28T18:30:00.000Z","targets":{"accepted":["digital","physical"],"skipped":[]},"result":{"choiceId":"dismiss","label":"DISMISS","position":"secondary","surface":"digital","selectedAt":"2026-07-28T18:29:35.000Z","effect":{"type":"dismiss","status":"none"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/PromptNotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/prompts/{promptId}/cancel":{"post":{"operationId":"cancelIntegrationPrompt","tags":["Prompts"],"summary":"Cancel a pending asynchronous prompt","description":"Requires prompts.write and accepts only a prompt owned by this authenticated named connection. Moves a pending prompt to cancelled and clears its Taby cue. Calling cancel for an already-terminal prompt is safe and returns its existing snapshot.","x-taby-required-permission":"prompts.write","parameters":[{"$ref":"#/components/parameters/PromptId"}],"responses":{"200":{"description":"Prompt snapshot after the cancellation attempt.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/PromptNotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/brain/ask":{"post":{"operationId":"askIntegrationBrain","tags":["Brain"],"summary":"Ask Hey Taby's installed local Brain","description":"Requires brain.read. Always uses Taby's installed local Brain through its managed llama.cpp runtime, even when normal Taby chat is set to Cloud Brain, and forces domain-level read-only execution mode. Approved read tools may access local Taby data, including tasks, even when this connection does not have direct tasks.read. Task, setting, focus, browser, file, navigation, and other mutations are blocked. Normal local AI activity history and the redacted integration audit are still recorded. The response contains a completed answer, not an accepted-for-later job, and there is no separate integration read-later endpoint.","x-taby-required-permission":"brain.read","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrainAskRequest"},"examples":{"nextFocus":{"summary":"Ask for a local read-only answer","value":{"prompt":"What should I focus on next?","sessionId":"local-workflow","requestId":"brain-123"}}}}}},"responses":{"200":{"description":"Completed local-Brain answer and sanitized metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrainResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"408":{"$ref":"#/components/responses/RequestTimeout"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}}},"components":{"securitySchemes":{"localBearer":{"type":"http","scheme":"bearer","bearerFormat":"opaque local token","description":"Create a named connection in Settings > Integrations > Local API & MCP and save its one-time token when shown. Taby stores only a protected hash and short hint. Each token has eight boolean permissions: status.read, companion.digital.write, device.physical.write, prompts.write, brain.read, tasks.read, tasks.write, and tasks.delete. The operation descriptions identify the required permission; target actions also require the permission for every requested surface. tasks.write and tasks.delete carry tasks.read. brain.read can read Taby context including tasks even without direct tasks.read, while Brain mutations remain blocked. Settings can rotate or revoke each token independently. This local credential flow is not OAuth 2.1. Never paste a token into chat, source code, screenshots, workflow exports, or shared logs. Advanced environment/source-build mode may instead publish a private endpoint descriptor."}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional task-mutation retry key. It follows the requestId syntax. If the JSON body also contains requestId, the two values must match. The same client, action, input, and key retain either a success or failure outcome for five minutes in the current app process without re-execution. After expiry, timeout, or restart, reconcile before retrying a create.","schema":{"type":"string","minLength":1,"maxLength":120,"pattern":"^[A-Za-z0-9._:-]+$","description":"Optional idempotency key. Reuse it only when retrying the same logical action. The same client, action, input, and key retain either a success or failure outcome for five minutes in the current app process without re-execution. After expiry, timeout, or restart, reconcile state before retrying a create."}},"PromptId":{"name":"promptId","in":"path","required":true,"description":"UUID returned by POST /v1/prompts/choice. Terminal records are retained in memory for up to ten minutes, with at most 100 records in the current app run. They are not durable workflow storage.","schema":{"type":"string","format":"uuid"}},"TaskId":{"name":"taskId","in":"path","required":true,"description":"Stable task UUID returned by a task list, create, or get operation. Do not identify tasks by title.","schema":{"type":"string","format":"uuid"}}},"schemas":{"ErrorResponse":{"type":"object","additionalProperties":false,"required":["ok","error"],"properties":{"ok":{"type":"boolean","const":false},"error":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"issues":{"type":"array","description":"Structured validation issues, present only for input-schema failures.","items":{"type":"object","additionalProperties":true}}}}}},"HealthResponse":{"type":"object","additionalProperties":false,"required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":false,"required":["status","apiVersion","mcp"],"properties":{"status":{"type":"string","const":"ok"},"apiVersion":{"type":"string","const":"v1"},"mcp":{"type":"boolean","const":true}}}}},"StatusResponse":{"type":"object","additionalProperties":false,"required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/IntegrationStatus"}}},"IntegrationStatus":{"type":"object","additionalProperties":false,"required":["app","companion","targets","brain"],"properties":{"app":{"type":"object","additionalProperties":false,"required":["version"],"properties":{"version":{"type":"string"}}},"companion":{"type":"object","additionalProperties":false,"required":["mode","eventType","animationId"],"properties":{"mode":{"type":"string","enum":["ambient","attention"]},"eventType":{"type":["string","null"]},"animationId":{"type":["string","null"]}}},"targets":{"type":"object","additionalProperties":false,"required":["digital","physical"],"properties":{"digital":{"type":"object","additionalProperties":false,"required":["enabled"],"properties":{"enabled":{"type":"boolean"}}},"physical":{"type":"object","additionalProperties":false,"required":["enabled","connected","transport","firmwareVersion","assetsVersion","batteryPercent","externalPower"],"properties":{"enabled":{"type":"boolean"},"connected":{"type":"boolean"},"transport":{"type":["string","null"],"enum":["usb","bluetooth",null]},"firmwareVersion":{"type":["string","null"]},"assetsVersion":{"type":["string","null"]},"batteryPercent":{"type":["number","null"]},"externalPower":{"type":["boolean","null"]}}}}},"brain":{"type":"object","additionalProperties":false,"required":["installed","installedModelIds","preferredModelId","running","activeModelId","healthy"],"properties":{"installed":{"type":"boolean"},"installedModelIds":{"type":"array","items":{"type":"string"}},"preferredModelId":{"type":["string","null"]},"running":{"type":"boolean"},"activeModelId":{"type":["string","null"]},"healthy":{"type":["boolean","null"]}}}}},"Animation":{"type":"object","additionalProperties":false,"required":["id","displayName","loopPolicy"],"properties":{"id":{"type":"string","description":"Canonical approved animation identifier."},"displayName":{"type":"string"},"loopPolicy":{"type":"string","enum":["play_once","loop"]}}},"AnimationsResponse":{"type":"object","additionalProperties":false,"required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":false,"required":["count","animations"],"properties":{"count":{"type":"integer","minimum":0},"animations":{"type":"array","items":{"$ref":"#/components/schemas/Animation"}}}}}},"AuditEntry":{"type":"object","additionalProperties":false,"required":["at","clientId","action","requestId","result"],"properties":{"at":{"type":"string","maxLength":64},"clientId":{"type":"string","description":"Authenticated named connection ID, or the advanced environment-mode identity."},"action":{"type":"string","enum":["animation.play","card.show","brain.ask","prompt.create","prompt.cancel","task.list","task.get","task.create","task.update","task.complete","task.reopen","task.delete","task.restore"]},"requestId":{"type":"string"},"objectId":{"type":"string","description":"Stable object UUID when the action targets one task."},"result":{"type":"string","enum":["accepted","skipped","rejected","failed"]},"reason":{"type":"string"}}},"LogsResponse":{"type":"object","additionalProperties":false,"required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":false,"required":["entries"],"properties":{"entries":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/AuditEntry"}}}}}},"TaskDateDeadline":{"type":"object","additionalProperties":false,"required":["kind","date"],"properties":{"kind":{"type":"string","const":"date"},"date":{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Valid local calendar date. Taby stores it at the end of the local day and returns the same date."}}},"TaskDateTimeDeadline":{"type":"object","additionalProperties":false,"required":["kind","at"],"properties":{"kind":{"type":"string","const":"date_time"},"at":{"type":"string","maxLength":64,"pattern":"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d{1,3})?)?(?:Z|[+-]\\d{2}:\\d{2})$","description":"Valid ISO 8601 calendar date and time with Z or an explicit accepted UTC offset. Impossible dates, 24:00, and invalid offsets are rejected. Responses are normalized to UTC."}}},"TaskDeadline":{"oneOf":[{"$ref":"#/components/schemas/TaskDateDeadline"},{"$ref":"#/components/schemas/TaskDateTimeDeadline"}]},"TaskCategory":{"type":["string","null"],"enum":["work","personal","coding","learning","meeting",null]},"Task":{"type":"object","additionalProperties":false,"description":"Privacy-safe task projection. It excludes linked-note contents, source-note payloads, image payloads and paths, launch items, folder IDs, device-template fields, and local paths.","required":["id","title","description","tags","category","status","deadline","estimatedPomodoros","completedPomodoros","timeSpentSeconds","color","createdAt","updatedAt","completedAt","deletedAt","trashExpiresAt"],"properties":{"id":{"type":"string","format":"uuid","description":"Stable task identifier used for later mutations."},"title":{"type":"string","minLength":1,"maxLength":200},"description":{"type":["string","null"],"maxLength":8000},"tags":{"type":"array","maxItems":20,"items":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"}},"category":{"$ref":"#/components/schemas/TaskCategory"},"status":{"type":"string","enum":["open","completed","trashed"]},"deadline":{"oneOf":[{"$ref":"#/components/schemas/TaskDeadline"},{"type":"null"}]},"estimatedPomodoros":{"type":["integer","null"],"minimum":1,"maximum":100},"completedPomodoros":{"type":"integer","minimum":0},"timeSpentSeconds":{"type":"integer","minimum":0},"color":{"type":["string","null"],"pattern":"^#[0-9a-fA-F]{6}$"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"completedAt":{"type":["string","null"],"format":"date-time"},"deletedAt":{"type":["string","null"],"format":"date-time"},"trashExpiresAt":{"type":["string","null"],"format":"date-time","description":"Present for retained trashed tasks. Taby's Trash is recoverable for 30 days."}}},"TaskListResult":{"type":"object","additionalProperties":false,"required":["schemaVersion","count","tasks"],"properties":{"schemaVersion":{"type":"integer","const":1},"count":{"type":"integer","minimum":0,"maximum":100},"tasks":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/Task"}}}},"TaskGetResult":{"type":"object","additionalProperties":false,"required":["schemaVersion","task"],"properties":{"schemaVersion":{"type":"integer","const":1},"task":{"$ref":"#/components/schemas/Task"}}},"TaskMutationResult":{"type":"object","additionalProperties":false,"required":["schemaVersion","requestId","changed","task"],"properties":{"schemaVersion":{"type":"integer","const":1},"requestId":{"type":"string"},"changed":{"type":"boolean","description":"False when the task already satisfied the requested state or a patch produced no record change."},"task":{"$ref":"#/components/schemas/Task"}}},"TaskCreateRequest":{"type":"object","additionalProperties":false,"required":["title"],"description":"Blank or whitespace-only description text normalizes to null. Tags are deduplicated case-insensitively.","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"description":{"type":["string","null"],"maxLength":8000,"description":"Blank or whitespace-only text normalizes to null."},"tags":{"type":"array","maxItems":20,"description":"Duplicate tags are removed case-insensitively.","items":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"}},"category":{"$ref":"#/components/schemas/TaskCategory"},"deadline":{"oneOf":[{"$ref":"#/components/schemas/TaskDeadline"},{"type":"null"}]},"estimatedPomodoros":{"type":["integer","null"],"minimum":1,"maximum":100},"color":{"type":["string","null"],"pattern":"^#[0-9a-fA-F]{6}$"},"requestId":{"type":"string","minLength":1,"maxLength":120,"pattern":"^[A-Za-z0-9._:-]+$","description":"Optional idempotency key. Reuse it only when retrying the same logical action. The same client, action, input, and key retain either a success or failure outcome for five minutes in the current app process without re-execution. After expiry, timeout, or restart, reconcile state before retrying a create."}}},"TaskPatch":{"type":"object","additionalProperties":false,"minProperties":1,"description":"Partial update. Omitted fields remain unchanged; null clears a nullable field. A blank description normalizes to null, and duplicate tags are removed case-insensitively.","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"description":{"type":["string","null"],"maxLength":8000,"description":"Blank or whitespace-only text normalizes to null."},"tags":{"type":"array","maxItems":20,"description":"Duplicate tags are removed case-insensitively.","items":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[\\w-]+$"}},"category":{"$ref":"#/components/schemas/TaskCategory"},"deadline":{"oneOf":[{"$ref":"#/components/schemas/TaskDeadline"},{"type":"null"}]},"estimatedPomodoros":{"type":["integer","null"],"minimum":1,"maximum":100},"color":{"type":["string","null"],"pattern":"^#[0-9a-fA-F]{6}$"}}},"TaskExpectedUpdatedAt":{"type":"string","maxLength":64,"pattern":"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d{1,3})?)?(?:Z|[+-]\\d{2}:\\d{2})$","description":"Optional optimistic precondition using a valid calendar date and time with Z or an explicit accepted UTC offset. Impossible values are rejected. The mutation returns HTTP 409 when it differs from the task's current updatedAt."},"TaskUpdateRequest":{"type":"object","additionalProperties":false,"required":["patch"],"properties":{"patch":{"$ref":"#/components/schemas/TaskPatch"},"expectedUpdatedAt":{"$ref":"#/components/schemas/TaskExpectedUpdatedAt"},"requestId":{"type":"string","minLength":1,"maxLength":120,"pattern":"^[A-Za-z0-9._:-]+$","description":"Optional idempotency key. Reuse it only when retrying the same logical action. The same client, action, input, and key retain either a success or failure outcome for five minutes in the current app process without re-execution. After expiry, timeout, or restart, reconcile state before retrying a create."}}},"TaskMutationRequest":{"type":"object","additionalProperties":false,"properties":{"expectedUpdatedAt":{"$ref":"#/components/schemas/TaskExpectedUpdatedAt"},"requestId":{"type":"string","minLength":1,"maxLength":120,"pattern":"^[A-Za-z0-9._:-]+$","description":"Optional idempotency key. Reuse it only when retrying the same logical action. The same client, action, input, and key retain either a success or failure outcome for five minutes in the current app process without re-execution. After expiry, timeout, or restart, reconcile state before retrying a create."}}},"TaskListResponse":{"type":"object","additionalProperties":false,"required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/TaskListResult"}}},"TaskGetResponse":{"type":"object","additionalProperties":false,"required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/TaskGetResult"}}},"TaskMutationResponse":{"type":"object","additionalProperties":false,"required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/TaskMutationResult"}}},"PlayAnimationRequest":{"type":"object","additionalProperties":false,"required":["animationId"],"properties":{"animationId":{"type":"string","minLength":1,"maxLength":120,"description":"Approved canonical animation ID from GET /v1/animations. Known registry aliases are accepted and normalized, but new integrations should store canonical IDs."},"targets":{"type":"array","minItems":1,"maxItems":2,"default":["digital"],"items":{"type":"string","enum":["digital","physical"]},"description":"Presentation targets. Duplicate values are normalized. Defaults to the digital companion."},"durationSeconds":{"type":"integer","minimum":1,"maximum":30,"default":4,"description":"Requested display duration in seconds."},"requestId":{"type":"string","minLength":1,"maxLength":120,"pattern":"^[A-Za-z0-9._:-]+$","description":"Optional idempotency key. Reuse it only when retrying the same logical action. The same client, action, input, and key retain either a success or failure outcome for five minutes in the current app process without re-execution. After expiry, timeout, or restart, reconcile state before retrying a create."}}},"ShowCardRequest":{"type":"object","additionalProperties":false,"required":["title"],"properties":{"title":{"type":"string","minLength":1,"maxLength":80,"description":"Plain text. When physical is requested, the title is limited to 18 characters."},"subtitle":{"type":"string","minLength":1,"maxLength":160,"description":"Optional plain text. When physical is requested, the subtitle is limited to 32 characters."},"tone":{"type":"string","enum":["neutral","progress","success","warning","error"],"default":"neutral"},"animationId":{"type":"string","minLength":1,"maxLength":120,"default":"confirmation","description":"Approved animation ID."},"targets":{"type":"array","minItems":1,"maxItems":2,"default":["digital"],"items":{"type":"string","enum":["digital","physical"]},"description":"Presentation targets. Duplicate values are normalized. Defaults to the digital companion."},"durationSeconds":{"type":"integer","minimum":1,"maximum":30,"default":4,"description":"Requested display duration in seconds."},"requestId":{"type":"string","minLength":1,"maxLength":120,"pattern":"^[A-Za-z0-9._:-]+$","description":"Optional idempotency key. Reuse it only when retrying the same logical action. The same client, action, input, and key retain either a success or failure outcome for five minutes in the current app process without re-execution. After expiry, timeout, or restart, reconcile state before retrying a create."}},"allOf":[{"if":{"required":["targets"],"properties":{"targets":{"contains":{"const":"physical"}}}},"then":{"properties":{"title":{"maxLength":18},"subtitle":{"maxLength":32}}}}],"description":"Card text must pass Hey Taby's plain-display-text validation. HTML, common block/link markup, scripts, controls, remote assets, and control characters are rejected."},"PromptChoiceEffect":{"oneOf":[{"type":"object","additionalProperties":false,"required":["type"],"properties":{"type":{"type":"string","const":"none"}}},{"type":"object","additionalProperties":false,"required":["type"],"properties":{"type":{"type":"string","const":"dismiss"}}},{"type":"object","additionalProperties":false,"required":["type","url"],"properties":{"type":{"type":"string","const":"open_url"},"url":{"type":"string","minLength":1,"maxLength":2048,"format":"uri","pattern":"^[Hh][Tt][Tt][Pp][Ss]?://","description":"HTTP or HTTPS only, with no embedded username or password. Opened through the operating system after selection; it is not fetched by Taby."}}},{"type":"object","additionalProperties":false,"required":["type","section"],"properties":{"type":{"type":"string","const":"open_taby_section"},"section":{"type":"string","enum":["home","tasks","schedule","habits","reminders","stats","for_you","review","settings","brain","pages"],"description":"Allowlisted Taby destination. pages opens the preview and may show Coming Soon when experimental Pages is disabled."}}}],"default":{"type":"none"}},"PromptChoice":{"type":"object","additionalProperties":false,"required":["id","label"],"properties":{"id":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9._:-]+$","description":"Caller-owned stable choice ID. The two IDs in one prompt must be unique."},"label":{"type":"string","minLength":1,"maxLength":32,"description":"Plain text. Limited to 12 characters when physical is requested."},"effect":{"$ref":"#/components/schemas/PromptChoiceEffect"}}},"CreateChoicePromptRequest":{"type":"object","additionalProperties":false,"required":["title","choices"],"properties":{"title":{"type":"string","minLength":1,"maxLength":80,"description":"Plain text. When physical is requested, the title is limited to 18 characters and should use printable ASCII with the current firmware font subset."},"subtitle":{"type":"string","minLength":1,"maxLength":160,"description":"Optional plain text. When physical is requested, the subtitle is limited to 32 characters and should use printable ASCII with the current firmware font subset."},"choices":{"type":"array","minItems":2,"maxItems":2,"description":"Exactly two choices, ordered primary then secondary. Choice IDs must be unique.","items":{"$ref":"#/components/schemas/PromptChoice"}},"animationId":{"type":"string","minLength":1,"maxLength":120,"default":"confirmation","description":"Approved animation ID. Physical prompts require a play-once animation so the controls remain available."},"targets":{"type":"array","minItems":1,"maxItems":2,"default":["digital"],"items":{"type":"string","enum":["digital","physical"]},"description":"Presentation targets. Duplicate values are normalized. Defaults to the digital companion."},"timeoutSeconds":{"type":"integer","minimum":5,"maximum":300,"default":30,"description":"Prompt lifetime. When physical is targeted, this must also cover the approved animation duration, a 750 ms input-unlock grace, and at least one actionable second; boxing therefore requires at least 7 seconds."},"requestId":{"type":"string","minLength":1,"maxLength":120,"pattern":"^[A-Za-z0-9._:-]+$","description":"Optional idempotency key. Reuse it only when retrying the same logical action. The same client, action, input, and key retain either a success or failure outcome for five minutes in the current app process without re-execution. After expiry, timeout, or restart, reconcile state before retrying a create."}},"allOf":[{"if":{"required":["targets"],"properties":{"targets":{"contains":{"const":"physical"}}}},"then":{"properties":{"title":{"maxLength":18},"subtitle":{"maxLength":32},"choices":{"items":{"allOf":[{"$ref":"#/components/schemas/PromptChoice"},{"properties":{"label":{"maxLength":12}}}]}}}}}],"description":"Prompt text and labels must pass Hey Taby's plain-display-text validation. HTML, Markdown links/blocks, scripts, controls, remote assets, and control characters are rejected."},"PromptSelectionEffectResult":{"type":"object","additionalProperties":false,"required":["type","status"],"properties":{"type":{"type":"string","enum":["none","dismiss","open_url","open_taby_section"]},"status":{"type":"string","enum":["none","pending","completed","failed"],"description":"Tracked separately from selection. A selected prompt can still contain a failed effect."}}},"PromptSelectionResult":{"type":"object","additionalProperties":false,"required":["choiceId","label","position","surface","selectedAt","effect"],"properties":{"choiceId":{"type":"string"},"label":{"type":"string"},"position":{"type":"string","enum":["primary","secondary"]},"surface":{"type":"string","enum":["digital","physical"]},"selectedAt":{"type":"string","format":"date-time"},"effect":{"$ref":"#/components/schemas/PromptSelectionEffectResult"}}},"PromptSnapshot":{"type":"object","additionalProperties":false,"required":["promptId","requestId","status","createdAt","expiresAt","targets","result"],"properties":{"promptId":{"type":"string","format":"uuid"},"requestId":{"type":"string"},"status":{"type":"string","enum":["pending","selected","timed_out","cancelled","skipped"]},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"targets":{"$ref":"#/components/schemas/TargetResult"},"result":{"oneOf":[{"$ref":"#/components/schemas/PromptSelectionResult"},{"type":"null"}]}}},"PromptResponse":{"type":"object","additionalProperties":false,"required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/PromptSnapshot"}}},"TargetResult":{"type":"object","additionalProperties":false,"required":["accepted","skipped"],"properties":{"accepted":{"type":"array","maxItems":2,"items":{"type":"string","enum":["digital","physical"]},"description":"Targets handed to the companion runtime. Acceptance is not proof of rendering or delivery."},"skipped":{"type":"array","maxItems":2,"items":{"type":"object","additionalProperties":false,"required":["target","reason"],"properties":{"target":{"type":"string","enum":["digital","physical"]},"reason":{"type":"string","enum":["digital_disabled","physical_disabled","physical_offline"]}}}}}},"DisplayResult":{"type":"object","additionalProperties":false,"required":["requestId","acceptedAt","animationId","targets"],"properties":{"requestId":{"type":"string"},"acceptedAt":{"type":"string","format":"date-time"},"animationId":{"type":"string","description":"Canonical normalized animation ID."},"targets":{"$ref":"#/components/schemas/TargetResult"}}},"DisplayResponse":{"type":"object","additionalProperties":false,"required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/DisplayResult"}}},"BrainAskRequest":{"type":"object","additionalProperties":false,"required":["prompt"],"properties":{"prompt":{"type":"string","minLength":1,"maxLength":8000},"sessionId":{"type":"string","minLength":1,"maxLength":160},"clientTurnId":{"type":"string","minLength":1,"maxLength":200},"requestId":{"type":"string","minLength":1,"maxLength":120,"pattern":"^[A-Za-z0-9._:-]+$","description":"Optional idempotency key. Reuse it only when retrying the same logical action. The same client, action, input, and key retain either a success or failure outcome for five minutes in the current app process without re-execution. After expiry, timeout, or restart, reconcile state before retrying a create."}}},"BrainAction":{"type":"object","additionalProperties":false,"required":["type","description","status"],"properties":{"type":{"type":"string","enum":["tool","info"]},"description":{"type":"string"},"status":{"type":"string","enum":["planned","pending_confirmation","completed","failed","skipped","blocked","cancelled"]},"toolName":{"type":"string"},"policyDecision":{"type":["string","null"],"enum":["auto","confirm","block",null]},"policyReason":{"type":["string","null"]}}},"BrainResult":{"type":"object","additionalProperties":false,"required":["requestId","activityId","createdAt","providerMode","providerLabel","model","text","actions","pendingConfirmationId"],"properties":{"requestId":{"type":"string"},"activityId":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"providerMode":{"type":"string","enum":["heuristic","openai-compatible"]},"providerLabel":{"type":"string"},"model":{"type":["string","null"]},"text":{"type":"string"},"actions":{"type":"array","items":{"$ref":"#/components/schemas/BrainAction"}},"pendingConfirmationId":{"type":"null","description":"Always null for this forced read-only integration surface."}}},"BrainResponse":{"type":"object","additionalProperties":false,"required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/BrainResult"}}}},"responses":{"BadRequest":{"description":"The URL, JSON, query, animation, or action input is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"The local Bearer token is absent or invalid.","headers":{"WWW-Authenticate":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Forbidden":{"description":"The request Host, Origin, or browser fetch site is not accepted, or the authenticated named connection lacks a required permission. Task operations retain x-taby-required-scope; other operation descriptions and x-taby-required-permission or x-taby-target-permissions fields identify their grants.","headers":{"WWW-Authenticate":{"description":"Present for insufficient permission errors and names the required permission in the scope parameter.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"RequestTimeout":{"description":"The JSON body did not arrive within ten seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Conflict":{"description":"The local Brain or prompt surface is busy, a task changed after expectedUpdatedAt, a task lifecycle disallows the mutation, or an idempotency key was reused with different input during its five-minute current-process window.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"PromptNotFound":{"description":"No retained integration prompt exists for this UUID. Prompt records are bounded, in-memory, and short-lived.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"TaskNotFound":{"description":"No retained task exists for this stable UUID. A trashed task may already have passed its 30-day retention window.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"PayloadTooLarge":{"description":"The JSON request body exceeds 32 KiB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"UnsupportedMediaType":{"description":"A request with a JSON body did not use application/json. This includes task PATCH and DELETE bodies.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"RateLimited":{"description":"A general or capability-specific local rate limit rejected the request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"InternalError":{"description":"The local integration capability failed unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}