{ "openapi": "3.1.0", "info": { "title": "Agent Swarm API", "version": "1.127.0", "description": "Multi-agent orchestration API for Claude Code, Codex, and Gemini CLI. Enables task distribution, agent communication, and service discovery.\n\nMCP tools are documented separately in [MCP.md](./MCP.md)." }, "servers": [ { "url": "http://localhost:3013", "description": "Local development" } ], "components": { "securitySchemes": { "bearerAuth": { "type": "http", "scheme": "bearer", "description": "API key via Authorization: Bearer " }, "agentId": { "type": "apiKey", "in": "header", "name": "X-Agent-ID", "description": "Agent UUID for agent-scoped operations" } }, "schemas": {}, "parameters": {} }, "paths": { "/api/active-sessions": { "get": { "summary": "List active sessions", "tags": [ "Active Sessions" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "agentId", "in": "query" } ], "responses": { "200": { "description": "Active session list" } } }, "post": { "summary": "Create a new active session", "tags": [ "Active Sessions" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "agentId": { "type": "string", "minLength": 1 }, "taskId": { "type": "string" }, "triggerType": { "type": "string", "minLength": 1 }, "inboxMessageId": { "type": "string" }, "taskDescription": { "type": "string" }, "runnerSessionId": { "type": "string" } }, "required": [ "agentId", "triggerType" ] } } } }, "responses": { "201": { "description": "Session created" }, "400": { "description": "Validation error" } } } }, "/api/active-sessions/by-task/{taskId}": { "delete": { "summary": "Delete active session by task ID", "tags": [ "Active Sessions" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "taskId", "in": "path" } ], "responses": { "200": { "description": "Session deleted" } } } }, "/api/active-sessions/{id}": { "delete": { "summary": "Delete active session by ID", "tags": [ "Active Sessions" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Session deleted" } } } }, "/api/active-sessions/heartbeat/{taskId}": { "put": { "summary": "Update heartbeat for an active session", "tags": [ "Active Sessions" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "taskId", "in": "path" } ], "responses": { "200": { "description": "Heartbeat updated" } } } }, "/api/active-sessions/provider-session/{taskId}": { "put": { "summary": "Update provider session ID on an active session", "tags": [ "Active Sessions" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "taskId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "providerSessionId": { "type": "string", "minLength": 1 } }, "required": [ "providerSessionId" ] } } } }, "responses": { "200": { "description": "Provider session ID updated" } } } }, "/api/active-sessions/cleanup": { "post": { "summary": "Clean up stale sessions", "tags": [ "Active Sessions" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "agentId": { "type": "string" }, "maxAgeMinutes": { "type": "integer" } } } } } }, "responses": { "200": { "description": "Cleanup result" } } } }, "/api/active-sessions/recover-orphaned-tasks": { "post": { "summary": "Recover orphaned in-progress tasks for an agent", "tags": [ "Active Sessions" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "agentId": { "type": "string", "minLength": 1 }, "minAgeSeconds": { "type": "integer", "exclusiveMinimum": 0 } }, "required": [ "agentId" ] } } } }, "responses": { "200": { "description": "Recovery result" } } } }, "/api/db-query": { "post": { "summary": "Execute a read-only SQL query", "tags": [ "Debug" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "sql": { "type": "string", "minLength": 1, "maxLength": 10000 }, "query": { "type": "string", "minLength": 1, "maxLength": 10000, "description": "Deprecated runtime alias for sql." }, "params": { "type": "array", "items": {}, "default": [] } } } } } }, "responses": { "200": { "description": "Query results", "content": { "application/json": { "schema": { "type": "object", "properties": { "columns": { "type": "array", "items": { "type": "string" } }, "rows": { "type": "array", "items": { "type": "array", "items": {} } }, "elapsed": { "type": "number" }, "total": { "type": "number" } }, "required": [ "columns", "rows", "elapsed", "total" ] } } } }, "400": { "description": "Invalid or disallowed SQL" } } } }, "/api/agents": { "post": { "summary": "Register or re-register an agent", "tags": [ "Agents" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 }, "isLead": { "type": "boolean" }, "description": { "type": "string" }, "role": { "type": "string" }, "capabilities": { "type": "array", "items": { "type": "string" } }, "maxTasks": { "type": "integer" }, "provider": { "type": "string", "enum": [ "claude", "codex", "pi", "devin", "claude-managed", "opencode" ] }, "harness_provider": { "type": "string", "enum": [ "claude", "codex", "pi", "devin", "claude-managed", "opencode" ] } }, "required": [ "name" ] } } } }, "responses": { "200": { "description": "Agent re-registered (already existed). Response includes `enabledCapabilities` — the server's capability flags (registered MCP tool groups), not the agent's declared skill tags." }, "201": { "description": "Agent created. Response includes `enabledCapabilities` (see 200)." }, "400": { "description": "Validation error" } } }, "get": { "summary": "List all agents", "description": "Returns agents WITHOUT the six identity-markdown blobs (`claudeMd`/`soulMd`/`identityMd`/`toolsMd`/`heartbeatMd`/`setupScript`) by default — they bloat the list by ~16 KB/agent and the overview never renders them. Pass `fields=full` to restore them, or fetch a single agent via `GET /api/agents/{id}`.", "tags": [ "Agents" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "tasks" ] }, "required": false, "name": "include", "in": "query" }, { "schema": { "type": "string", "enum": [ "full", "slim" ] }, "required": false, "name": "fields", "in": "query" } ], "responses": { "200": { "description": "Agent list with capacity info" } } } }, "/api/agents/{id}/harness-provider": { "patch": { "summary": "Re-assign an agent's harness_provider (live)", "description": "Updates `agents.harness_provider` and upserts `swarm_config` (scope=agent, key=HARNESS_PROVIDER) so the worker's poll-loop reconciliation picks up the new provider within ~10s. No restart required. The swarm_config row is what actually drives the worker; the column mirrors the latest set value for dashboards.", "tags": [ "Agents" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "harness_provider": { "type": "string", "enum": [ "claude", "codex", "pi", "devin", "claude-managed", "opencode" ] } }, "required": [ "harness_provider" ] } } } }, "responses": { "200": { "description": "Updated agent row" }, "400": { "description": "Validation error (unknown provider)" }, "404": { "description": "Agent not found" } } } }, "/api/agents/{id}/runtime": { "patch": { "summary": "Update an agent's runtime harness and default model", "description": "Updates `agents.harness_provider` and upserts agent-scoped `swarm_config` rows for HARNESS_PROVIDER, MODEL_OVERRIDE, and REASONING_EFFORT_OVERRIDE. The settings apply to future provider sessions. For `model` and `reasoning_effort`: omit the field to leave it unchanged, send `null` to clear the corresponding override, or send a value to set it.", "tags": [ "Agents" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "harness_provider": { "type": "string", "enum": [ "claude", "codex", "pi", "opencode" ] }, "model": { "type": [ "string", "null" ], "minLength": 1 }, "allow_custom_model": { "type": "boolean", "default": false }, "reasoning_effort": { "type": [ "string", "null" ], "enum": [ "off", "low", "medium", "high", "xhigh", "max", null ] } }, "required": [ "harness_provider" ] } } } }, "responses": { "200": { "description": "Updated agent row" }, "400": { "description": "Validation error" }, "404": { "description": "Agent not found" } } } }, "/api/agents/{id}/name": { "put": { "summary": "Update agent name", "tags": [ "Agents" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 } }, "required": [ "name" ] } } } }, "responses": { "200": { "description": "Agent updated" }, "404": { "description": "Agent not found" }, "409": { "description": "Name conflict" } } } }, "/api/agents/{id}/setup-script": { "get": { "summary": "Fetch agent + global setup scripts for Docker entrypoint", "tags": [ "Agents" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Setup scripts" }, "404": { "description": "Agent not found" } } } }, "/api/agents/{id}/profile": { "put": { "summary": "Update agent profile (role, description, capabilities, etc.)", "tags": [ "Agents" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "role": { "type": "string", "maxLength": 100 }, "description": { "type": "string" }, "capabilities": { "type": "array", "items": { "type": "string" } }, "claudeMd": { "type": "string", "maxLength": 65536 }, "soulMd": { "type": "string", "maxLength": 65536 }, "identityMd": { "type": "string", "maxLength": 65536 }, "setupScript": { "type": "string", "maxLength": 65536 }, "toolsMd": { "type": "string", "maxLength": 65536 }, "heartbeatMd": { "type": "string", "maxLength": 65536 }, "avatar": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "lucide" ] }, "icon": { "type": "string", "maxLength": 64, "pattern": "^[a-z0-9-]+$" }, "color": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$" } }, "required": [ "type", "icon" ] }, { "type": "null" } ] }, "changeSource": { "type": "string" }, "changedByAgentId": { "type": "string" }, "changeReason": { "type": "string" } } } } } }, "responses": { "200": { "description": "Profile updated" }, "400": { "description": "Validation error" }, "404": { "description": "Agent not found" } } } }, "/api/agents/{id}/activity": { "put": { "summary": "Update agent last activity timestamp", "tags": [ "Agents" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "204": { "description": "Activity updated" } } } }, "/api/agents/{id}": { "get": { "summary": "Get a single agent", "tags": [ "Agents" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "enum": [ "tasks" ] }, "required": false, "name": "include", "in": "query" } ], "responses": { "200": { "description": "Agent with capacity info" }, "404": { "description": "Agent not found" } } } }, "/api/agents/{id}/credential-status": { "put": { "summary": "Worker self-report of credential readiness (Phase 3 boot loop)", "tags": [ "Agents" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "ready": { "type": "boolean" }, "missing": { "type": [ "array", "null" ], "items": { "type": "string" } }, "cred_status": { "type": [ "object", "null" ], "properties": { "ready": { "type": "boolean" }, "missing": { "type": "array", "items": { "type": "string" }, "default": [] }, "satisfiedBy": { "type": [ "string", "null" ], "enum": [ "env", "file", "side-effect-pending", "sdk-delegated", null ], "default": null }, "hint": { "type": [ "string", "null" ], "default": null }, "liveTest": { "type": [ "object", "null" ], "properties": { "ok": { "type": "boolean" }, "error": { "type": [ "string", "null" ], "default": null }, "latency_ms": { "type": "number" }, "testedAt": { "type": "number" } }, "default": null, "required": [ "ok", "latency_ms", "testedAt" ] }, "latestModel": { "type": [ "object", "null" ], "properties": { "model": { "type": "string", "minLength": 1 }, "source": { "type": "string", "enum": [ "task", "agent_config", "adapter_default", "custom" ] }, "taskId": { "type": [ "string", "null" ], "default": null }, "harnessProvider": { "type": [ "string", "null" ], "enum": [ "claude", "codex", "pi", "devin", "claude-managed", "opencode", null ], "default": null }, "reportedAt": { "type": "number" }, "reasoningEffort": { "type": "string", "enum": [ "off", "low", "medium", "high", "xhigh", "max" ] } }, "default": null, "required": [ "model", "source", "reportedAt" ] }, "reportedAt": { "type": "number" }, "reportKind": { "type": "string", "enum": [ "boot", "post_task" ], "default": "boot" }, "bedrock": { "type": [ "object", "null" ], "properties": { "region": { "type": "string" }, "probedAt": { "type": "number" }, "ready": { "type": "boolean" }, "models": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" } }, "required": [ "id", "name" ] }, "default": [] }, "error": { "type": "string" } }, "default": null, "required": [ "region", "probedAt", "ready" ] } }, "required": [ "ready", "reportedAt" ] }, "latest_model": { "type": "object", "properties": { "model": { "type": "string", "minLength": 1 }, "source": { "type": "string", "enum": [ "task", "agent_config", "adapter_default", "custom" ] }, "taskId": { "type": [ "string", "null" ], "default": null }, "harnessProvider": { "type": [ "string", "null" ], "enum": [ "claude", "codex", "pi", "devin", "claude-managed", "opencode", null ], "default": null }, "reportedAt": { "type": "number" }, "reasoningEffort": { "type": "string", "enum": [ "off", "low", "medium", "high", "xhigh", "max" ] } }, "required": [ "model", "source", "reportedAt" ] } } } } } }, "responses": { "200": { "description": "State updated; returns the agent row." }, "404": { "description": "Agent not found" } } }, "get": { "summary": "Single-agent credential-status snapshot for the dashboard", "tags": [ "Agents" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Credential status payload" }, "404": { "description": "Agent not found" } } } }, "/api/agents/credential-status": { "get": { "summary": "Bulk credential-status across all agents (powers the dashboard)", "tags": [ "Agents" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "idle", "busy", "offline", "waiting_for_credentials" ] }, "required": false, "name": "status", "in": "query" } ], "responses": { "200": { "description": "List of {agentId, status, missing[], lastCheckedAt}" } } } }, "/api/approval-requests": { "post": { "summary": "Create a new approval request", "tags": [ "ApprovalRequests" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "title": { "type": "string", "minLength": 1 }, "questions": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "type": { "type": "string", "enum": [ "approval", "text", "single-select", "multi-select", "boolean" ] }, "label": { "type": "string" }, "required": { "type": "boolean" }, "description": { "type": "string" }, "placeholder": { "type": "string" }, "multiline": { "type": "boolean" }, "options": { "type": "array", "items": { "type": "object", "properties": { "value": { "type": "string" }, "label": { "type": "string" }, "description": { "type": "string" } }, "required": [ "value", "label" ] } }, "minSelections": { "type": "integer", "minimum": 0 }, "maxSelections": { "type": "integer", "minimum": 1 }, "defaultValue": { "type": "boolean" } }, "required": [ "id", "type", "label" ] }, "minItems": 1 }, "approvers": { "type": "object", "properties": { "users": { "type": "array", "items": { "type": "string" } }, "roles": { "type": "array", "items": { "type": "string" } }, "policy": { "anyOf": [ { "type": "string", "enum": [ "any" ] }, { "type": "string", "enum": [ "all" ] }, { "type": "object", "properties": { "min": { "type": "integer", "minimum": 1 } }, "required": [ "min" ] } ] } }, "required": [ "policy" ] }, "workflowRunId": { "type": "string", "format": "uuid" }, "workflowRunStepId": { "type": "string", "format": "uuid" }, "sourceTaskId": { "type": "string", "format": "uuid" }, "timeoutSeconds": { "type": "integer", "minimum": 1 }, "notifications": { "type": "array", "items": { "type": "object", "properties": { "channel": { "type": "string", "enum": [ "slack", "email" ] }, "target": { "type": "string" } }, "required": [ "channel", "target" ] } } }, "required": [ "title", "questions", "approvers" ] } } } }, "responses": { "201": { "description": "Approval request created" }, "400": { "description": "Validation error" } } }, "get": { "summary": "List approval requests with optional filters", "tags": [ "ApprovalRequests" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "status", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "workflowRunId", "in": "query" }, { "schema": { "type": [ "number", "null" ] }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "List of approval requests" } } } }, "/api/approval-requests/{id}": { "get": { "summary": "Get approval request details", "tags": [ "ApprovalRequests" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Approval request details" }, "404": { "description": "Not found" } } } }, "/api/approval-requests/{id}/respond": { "post": { "summary": "Submit a response to an approval request", "tags": [ "ApprovalRequests" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "responses": { "type": "object", "additionalProperties": {} }, "respondedBy": { "type": "string" } }, "required": [ "responses" ] } } } }, "responses": { "200": { "description": "Response recorded" }, "400": { "description": "Validation error" }, "404": { "description": "Not found" }, "409": { "description": "Already resolved" } } } }, "/api/assets/key-audit": { "get": { "summary": "Audit asset namespace invariants", "description": "Operator-only check for structural key validity, personal-user references, and logical provider mapping drift. Repeated logical keys are valid and are never reported as conflicts.", "tags": [ "Assets" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Asset namespace audit result" }, "403": { "description": "Operator access required" } } } }, "/api/assets": { "get": { "summary": "List lightweight cross-entity asset summaries", "description": "Returns only entity type, ID, namespace key, label, update time, and optional provider reference. It never returns task briefs, page bodies, workflow definitions, secrets, or file bytes. Personal keys are namespace labels, not a privacy or read-visibility guarantee.", "tags": [ "Assets" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "required": false, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form.", "name": "keyPrefix", "in": "query" }, { "schema": { "type": "string", "description": "Comma-separated task,workflow,schedule,page,file list" }, "required": false, "description": "Comma-separated task,workflow,schedule,page,file list", "name": "types", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 1000 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "Lightweight asset summary list" }, "400": { "description": "Invalid entity type" } } } }, "/api/assets/mappings": { "post": { "summary": "Register a logical namespace for a provider object", "description": "Idempotently maps a provider tuple to a logical swarm key without moving, renaming, reading, or writing the remote object.", "tags": [ "Assets" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "providerId": { "type": "string", "minLength": 1 }, "orgId": { "type": "string" }, "driveId": { "type": "string" }, "providerKey": { "type": "string", "minLength": 1 }, "key": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." } }, "required": [ "providerId", "providerKey" ] } } } }, "responses": { "200": { "description": "Mapping registered" }, "400": { "description": "Invalid provider tuple or namespace" }, "403": { "description": "Operator access required or personal namespace not authorized" } } } }, "/api/assets/{entityType}/{id}/key": { "patch": { "summary": "Move an asset to another logical namespace", "description": "Updates namespace metadata only. Provider-backed files keep the same provider key, org, and drive; no remote move occurs. Personal keys are labels, not a privacy guarantee.", "tags": [ "Assets" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "task", "workflow", "schedule", "page", "file" ] }, "required": true, "name": "entityType", "in": "path" }, { "schema": { "type": "string", "minLength": 1 }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "key": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." } }, "required": [ "key" ] } } } }, "responses": { "200": { "description": "Asset namespace updated" }, "400": { "description": "Invalid namespace" }, "403": { "description": "Move not authorized" }, "404": { "description": "Asset not found" }, "409": { "description": "Moves blocked until audit warnings are repaired" } } } }, "/api/budgets": { "get": { "summary": "List all configured budget rows", "tags": [ "Budgets" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Budget list", "content": { "application/json": { "schema": { "type": "object", "properties": { "budgets": { "type": "array", "items": { "type": "object", "properties": { "scope": { "type": "string", "enum": [ "global", "agent", "user" ] }, "scopeId": { "type": "string" }, "dailyBudgetUsd": { "type": "number", "minimum": 0 }, "createdAt": { "type": "number" }, "lastUpdatedAt": { "type": "number" } }, "required": [ "scope", "scopeId", "dailyBudgetUsd", "createdAt", "lastUpdatedAt" ] } } }, "required": [ "budgets" ] } } } } } } }, "/api/budgets/refusals": { "get": { "summary": "List recent budget refusal notifications", "tags": [ "Budgets" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "integer", "exclusiveMinimum": 0, "maximum": 500 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "Recent budget refusals (newest first)", "content": { "application/json": { "schema": { "type": "object", "properties": { "refusals": { "type": "array", "items": { "type": "object", "properties": { "taskId": { "type": "string" }, "date": { "type": "string" }, "agentId": { "type": "string" }, "cause": { "type": "string", "enum": [ "agent", "global", "user" ] }, "agentSpendUsd": { "type": [ "number", "null" ] }, "agentBudgetUsd": { "type": [ "number", "null" ] }, "globalSpendUsd": { "type": [ "number", "null" ] }, "globalBudgetUsd": { "type": [ "number", "null" ] }, "userSpendUsd": { "type": [ "number", "null" ] }, "userBudgetUsd": { "type": [ "number", "null" ] }, "followUpTaskId": { "type": [ "string", "null" ] }, "createdAt": { "type": "number" } }, "required": [ "taskId", "date", "agentId", "cause", "createdAt" ] } } }, "required": [ "refusals" ] } } } } } } }, "/api/budgets/{scope}/{scopeId}": { "get": { "summary": "Get a single budget row", "tags": [ "Budgets" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "global", "agent", "user" ] }, "required": true, "name": "scope", "in": "path" }, { "schema": { "type": "string", "maxLength": 255, "description": "Scope identifier — empty string for global, agent UUID otherwise" }, "required": true, "description": "Scope identifier — empty string for global, agent UUID otherwise", "name": "scopeId", "in": "path" } ], "responses": { "200": { "description": "Budget row", "content": { "application/json": { "schema": { "type": "object", "properties": { "scope": { "type": "string", "enum": [ "global", "agent", "user" ] }, "scopeId": { "type": "string" }, "dailyBudgetUsd": { "type": "number", "minimum": 0 }, "createdAt": { "type": "number" }, "lastUpdatedAt": { "type": "number" } }, "required": [ "scope", "scopeId", "dailyBudgetUsd", "createdAt", "lastUpdatedAt" ] } } } }, "404": { "description": "Budget not configured" } } }, "put": { "summary": "Create or update a budget row", "tags": [ "Budgets" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "global", "agent", "user" ] }, "required": true, "name": "scope", "in": "path" }, { "schema": { "type": "string", "maxLength": 255, "description": "Scope identifier — empty string for global, agent UUID otherwise" }, "required": true, "description": "Scope identifier — empty string for global, agent UUID otherwise", "name": "scopeId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "dailyBudgetUsd": { "type": "number", "minimum": 0 } }, "required": [ "dailyBudgetUsd" ] } } } }, "responses": { "200": { "description": "Budget upserted", "content": { "application/json": { "schema": { "type": "object", "properties": { "scope": { "type": "string", "enum": [ "global", "agent", "user" ] }, "scopeId": { "type": "string" }, "dailyBudgetUsd": { "type": "number", "minimum": 0 }, "createdAt": { "type": "number" }, "lastUpdatedAt": { "type": "number" } }, "required": [ "scope", "scopeId", "dailyBudgetUsd", "createdAt", "lastUpdatedAt" ] } } } }, "400": { "description": "Validation error" } } }, "delete": { "summary": "Delete a budget row", "tags": [ "Budgets" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "global", "agent", "user" ] }, "required": true, "name": "scope", "in": "path" }, { "schema": { "type": "string", "maxLength": 255, "description": "Scope identifier — empty string for global, agent UUID otherwise" }, "required": true, "description": "Scope identifier — empty string for global, agent UUID otherwise", "name": "scopeId", "in": "path" } ], "responses": { "204": { "description": "Budget deleted" }, "404": { "description": "Budget not configured" } } } }, "/api/oauth/keep-warm/codex": { "post": { "summary": "Locked keep-warm refresh sweep across all Codex OAuth pool slots", "description": "Enumerates codex_oauth_* slots and refreshes any older than ~7 days through the same locked getValidCodexOAuth path used at task time. Skips slots already benched by codex-auth-expiry-watch.", "tags": [ "OAuth" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Per-slot keep-warm outcomes" } } } }, "/api/config/resolved": { "get": { "summary": "Get resolved config (merged global + agent + repo scopes)", "tags": [ "Config" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "agentId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "repoId", "in": "query" }, { "schema": { "type": "string", "enum": [ "true", "false" ] }, "required": false, "name": "includeSecrets", "in": "query" } ], "responses": { "200": { "description": "Resolved config entries" } } } }, "/api/config/env-presence": { "get": { "summary": "Check which of the given env var keys are currently set in process.env (presence only, no values)", "tags": [ "Config" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1 }, "required": true, "name": "keys", "in": "query" } ], "responses": { "200": { "description": "Map of key -> boolean (true iff set in process.env)" }, "400": { "description": "Validation error" } } } }, "/api/config/reload": { "post": { "summary": "Reload global swarm_config into process.env (override=true) and re-init integrations (Slack, GitHub, Linear, AgentMail)", "tags": [ "Config" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": {} } } } }, "responses": { "200": { "description": "Reload result" }, "500": { "description": "Reload failed" } } } }, "/api/config/{id}": { "get": { "summary": "Get a single config entry by ID", "tags": [ "Config" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "enum": [ "true", "false" ] }, "required": false, "name": "includeSecrets", "in": "query" } ], "responses": { "200": { "description": "Config entry" }, "404": { "description": "Config not found" } } }, "delete": { "summary": "Delete a config entry by ID (including legacy reserved rows for cleanup). Global-scope deletes auto-trigger an integrations reload.", "tags": [ "Config" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Config deleted" }, "404": { "description": "Config not found" } } } }, "/api/config": { "get": { "summary": "List config entries with optional filters", "tags": [ "Config" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "scope", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "scopeId", "in": "query" }, { "schema": { "type": "string", "enum": [ "true", "false" ] }, "required": false, "name": "includeSecrets", "in": "query" } ], "responses": { "200": { "description": "List of config entries" } } }, "put": { "summary": "Create or update a config entry (reserved env-only keys are rejected). Global-scope writes auto-trigger an integrations reload (debounced ~250ms) so Slack/GitHub/Linear/Jira/AgentMail pick up new credentials without an explicit /api/config/reload call.", "tags": [ "Config" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "scope": { "type": "string", "enum": [ "global", "agent", "repo" ] }, "scopeId": { "type": [ "string", "null" ] }, "key": { "type": "string", "minLength": 1 }, "value": {}, "isSecret": { "type": "boolean" }, "envPath": { "type": [ "string", "null" ] }, "description": { "type": [ "string", "null" ] } }, "required": [ "scope", "key" ] } } } }, "responses": { "200": { "description": "Config entry upserted" }, "400": { "description": "Validation error" } } } }, "/api/tasks/{id}/context": { "post": { "summary": "Record a context usage snapshot for a task", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "eventType": { "type": "string", "enum": [ "progress", "compaction", "completion" ] }, "sessionId": { "type": "string" }, "contextUsedTokens": { "type": "integer", "minimum": 0 }, "contextTotalTokens": { "type": "integer", "minimum": 0 }, "contextPercent": { "type": "number", "minimum": 0, "maximum": 100 }, "compactTrigger": { "type": "string", "enum": [ "auto", "manual", "auto-inferred" ] }, "preCompactTokens": { "type": "integer", "minimum": 0 }, "cumulativeInputTokens": { "type": "integer", "minimum": 0 }, "cumulativeOutputTokens": { "type": "integer", "minimum": 0 }, "contextFormula": { "type": "string", "enum": [ "input-cache-output", "input-cache-no-output", "input-output-no-cache", "peak-proxy", "pi-delegated", "harness-reported", "unknown" ] } }, "required": [ "eventType", "sessionId" ] } } } }, "responses": { "200": { "description": "Snapshot recorded" }, "400": { "description": "Validation error" }, "404": { "description": "Task not found" } } }, "get": { "summary": "Get context usage history for a task", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 500, "default": 100 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "Context snapshot history" }, "404": { "description": "Task not found" } } } }, "/ecosystem": { "get": { "summary": "Get PM2 ecosystem config for agent services", "tags": [ "Ecosystem" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "PM2 ecosystem config" }, "400": { "description": "Missing X-Agent-ID" } } } }, "/api/keys/report-usage": { "post": { "summary": "Record which API key was used for a task", "tags": [ "API Keys" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "keyType": { "type": "string" }, "keySuffix": { "type": "string", "minLength": 1, "maxLength": 10 }, "keyIndex": { "type": "integer", "minimum": 0 }, "taskId": { "type": "string", "format": "uuid" }, "scope": { "type": "string" }, "scopeId": { "type": "string" } }, "required": [ "keyType", "keySuffix", "keyIndex" ] } } } }, "responses": { "200": { "description": "Usage recorded" }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" } } } }, "/api/keys/report-rate-limit": { "post": { "summary": "Mark an API key as rate-limited", "tags": [ "API Keys" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "keyType": { "type": "string" }, "keySuffix": { "type": "string", "minLength": 1, "maxLength": 10 }, "keyIndex": { "type": "integer", "minimum": 0 }, "rateLimitedUntil": { "type": "string", "format": "date-time" }, "scope": { "type": "string" }, "scopeId": { "type": "string" } }, "required": [ "keyType", "keySuffix", "keyIndex", "rateLimitedUntil" ] } } } }, "responses": { "200": { "description": "Key marked as rate-limited" }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" } } } }, "/api/keys/report-rate-limit-windows": { "post": { "summary": "Record provider-emitted rate-limit window telemetry for an API key", "tags": [ "API Keys" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "keyType": { "type": "string" }, "keySuffix": { "type": "string", "minLength": 1, "maxLength": 10 }, "keyIndex": { "type": "integer", "minimum": 0 }, "windows": { "type": "object", "additionalProperties": { "type": "object", "properties": { "status": { "type": "string" }, "utilization": { "type": "number" }, "resetsAt": { "type": "number" }, "isUsingOverage": { "type": "boolean" }, "surpassedThreshold": { "type": "number" }, "lastSeenAt": { "type": "string", "format": "date-time" } }, "required": [ "status", "lastSeenAt" ] } }, "scope": { "type": "string" }, "scopeId": { "type": "string" } }, "required": [ "keyType", "keySuffix", "keyIndex", "windows" ] } } } }, "responses": { "200": { "description": "Rate-limit window telemetry recorded" }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" } } } }, "/api/keys/available": { "get": { "summary": "Get available (non-rate-limited) key indices for a credential type", "tags": [ "API Keys" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "keyType", "in": "query" }, { "schema": { "type": "integer", "minimum": 1 }, "required": true, "name": "totalKeys", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "scope", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "scopeId", "in": "query" } ], "responses": { "200": { "description": "List of available key indices" }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" } } } }, "/api/keys/status": { "get": { "summary": "Get all API key status records", "tags": [ "API Keys" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "keyType", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "scope", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "scopeId", "in": "query" } ], "responses": { "200": { "description": "List of key status records" }, "401": { "description": "Unauthorized" } } } }, "/api/keys/costs": { "get": { "summary": "Get aggregated cost data per API key", "tags": [ "API Keys" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "keyType", "in": "query" } ], "responses": { "200": { "description": "Per-key cost aggregation" }, "401": { "description": "Unauthorized" } } } }, "/api/keys/name": { "patch": { "summary": "Set or clear the human-friendly label on a pooled credential", "tags": [ "API Keys" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "keyType": { "type": "string", "minLength": 1 }, "keySuffix": { "type": "string", "minLength": 1, "maxLength": 10 }, "name": { "type": [ "string", "null" ], "maxLength": 60 }, "scope": { "type": "string" }, "scopeId": { "type": "string" } }, "required": [ "keyType", "keySuffix", "name" ] } } } }, "responses": { "200": { "description": "Name updated" }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" }, "404": { "description": "Key not found" } } } }, "/api/keys/clear-rate-limit": { "post": { "summary": "Clear rate-limited status for a key after a successful use proves it is healthy", "tags": [ "API Keys" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "keyType": { "type": "string" }, "keySuffix": { "type": "string", "minLength": 1, "maxLength": 10 }, "scope": { "type": "string" }, "scopeId": { "type": "string" } }, "required": [ "keyType", "keySuffix" ] } } } }, "responses": { "200": { "description": "Rate limit cleared (or key was not rate-limited)" }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" } } } }, "/api/events": { "post": { "summary": "Store a single event", "tags": [ "Events" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "category": { "type": "string", "enum": [ "tool", "skill", "session", "api", "task", "workflow", "system" ] }, "event": { "type": "string", "enum": [ "tool.start", "tool.end", "skill.invoke", "skill.complete", "session.start", "session.end", "session.resume", "session.cost", "api.request", "api.error", "task.poll", "task.assign", "task.timeout", "workflow.step.start", "workflow.step.end", "workflow.run.start", "workflow.run.end", "system.boot", "system.migration", "system.error", "script.global_upsert", "schedule.deleted" ] }, "status": { "type": "string", "enum": [ "ok", "error", "timeout", "skipped" ] }, "source": { "type": "string", "enum": [ "worker", "api", "hook", "scheduler", "cli" ] }, "agentId": { "type": "string" }, "taskId": { "type": "string" }, "sessionId": { "type": "string" }, "parentEventId": { "type": "string" }, "numericValue": { "type": "number" }, "durationMs": { "type": "integer" }, "data": { "type": "object", "additionalProperties": {} } }, "required": [ "category", "event", "source" ] } } } }, "responses": { "201": { "description": "Event stored" }, "400": { "description": "Validation error" } } }, "get": { "summary": "Query events with filters", "tags": [ "Events" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "tool", "skill", "session", "api", "task", "workflow", "system" ] }, "required": false, "name": "category", "in": "query" }, { "schema": { "type": "string", "enum": [ "tool.start", "tool.end", "skill.invoke", "skill.complete", "session.start", "session.end", "session.resume", "session.cost", "api.request", "api.error", "task.poll", "task.assign", "task.timeout", "workflow.step.start", "workflow.step.end", "workflow.run.start", "workflow.run.end", "system.boot", "system.migration", "system.error", "script.global_upsert", "schedule.deleted" ] }, "required": false, "name": "event", "in": "query" }, { "schema": { "type": "string", "enum": [ "ok", "error", "timeout", "skipped" ] }, "required": false, "name": "status", "in": "query" }, { "schema": { "type": "string", "enum": [ "worker", "api", "hook", "scheduler", "cli" ] }, "required": false, "name": "source", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "agentId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "taskId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "sessionId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "since", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "until", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 1000 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "List of events" } } } }, "/api/events/batch": { "post": { "summary": "Store multiple events in a batch", "tags": [ "Events" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "events": { "type": "array", "items": { "type": "object", "properties": { "category": { "type": "string", "enum": [ "tool", "skill", "session", "api", "task", "workflow", "system" ] }, "event": { "type": "string", "enum": [ "tool.start", "tool.end", "skill.invoke", "skill.complete", "session.start", "session.end", "session.resume", "session.cost", "api.request", "api.error", "task.poll", "task.assign", "task.timeout", "workflow.step.start", "workflow.step.end", "workflow.run.start", "workflow.run.end", "system.boot", "system.migration", "system.error", "script.global_upsert", "schedule.deleted" ] }, "status": { "type": "string", "enum": [ "ok", "error", "timeout", "skipped" ] }, "source": { "type": "string", "enum": [ "worker", "api", "hook", "scheduler", "cli" ] }, "agentId": { "type": "string" }, "taskId": { "type": "string" }, "sessionId": { "type": "string" }, "parentEventId": { "type": "string" }, "numericValue": { "type": "number" }, "durationMs": { "type": "integer" }, "data": { "type": "object", "additionalProperties": {} } }, "required": [ "category", "event", "source" ] }, "minItems": 1, "maxItems": 500 } }, "required": [ "events" ] } } } }, "responses": { "201": { "description": "Events stored" }, "400": { "description": "Validation error" } } } }, "/api/events/counts": { "get": { "summary": "Get event counts grouped by event name", "tags": [ "Events" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "tool", "skill", "session", "api", "task", "workflow", "system" ] }, "required": false, "name": "category", "in": "query" }, { "schema": { "type": "string", "enum": [ "worker", "api", "hook", "scheduler", "cli" ] }, "required": false, "name": "source", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "agentId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "taskId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "sessionId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "since", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "until", "in": "query" } ], "responses": { "200": { "description": "Event counts" } } } }, "/api/favorites": { "get": { "summary": "List favorites for the authenticated principal", "tags": [ "Favorites" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "page", "workflow", "schedule" ] }, "required": false, "name": "itemType", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "itemIds", "in": "query" } ], "responses": { "200": { "description": "Favorite rows and favorite item ids" }, "401": { "description": "No authenticated principal context" } } }, "put": { "summary": "Set favorite state for an item", "tags": [ "Favorites" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "itemType": { "type": "string", "enum": [ "page", "workflow", "schedule" ] }, "itemId": { "type": "string", "minLength": 1 }, "favorite": { "type": "boolean" } }, "required": [ "itemType", "itemId", "favorite" ] } } } }, "responses": { "200": { "description": "Favorite state" }, "401": { "description": "No authenticated principal context" } } } }, "/api/fs/capabilities": { "get": { "summary": "Get active file-storage provider capabilities", "tags": [ "FS" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Active provider capabilities" }, "401": { "description": "Unauthorized" } } } }, "/api/fs/agent-credentials": { "post": { "summary": "Ensure agent-scoped agent-fs credentials for the current agent", "description": "Internal runner endpoint. The API server owns agent-fs bootstrap credentials, registers/invites the caller to the shared org when needed, and stores the generated key as an agent-scoped secret. The API key is never returned.", "tags": [ "FS" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": {} } } } }, "responses": { "200": { "description": "Credential state" }, "400": { "description": "Missing agent id" }, "500": { "description": "Provisioning failed" } } } }, "/api/fs/members/invite": { "post": { "summary": "Invite an external member into the agent-fs shared org", "description": "The API server performs the invite with its own bootstrap credentials (which are API-only and never served over HTTP), provisioning the shared org/drive first when needed. Intended for the cloud control plane's Connect-to-Drive flow. No keys are returned; the invitee obtains their own key via agent-fs registration.", "tags": [ "FS" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "role": { "type": "string", "enum": [ "viewer", "editor", "admin" ], "default": "editor" } }, "required": [ "email" ] } } } }, "responses": { "200": { "description": "Invite state ({ orgId, invited })" }, "400": { "description": "Invalid body" }, "500": { "description": "Provisioning or invite failed" } } } }, "/api/fs/tasks/{taskId}/files": { "get": { "summary": "List task file attachments", "tags": [ "FS" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "taskId", "in": "path" } ], "responses": { "200": { "description": "Task file attachments" }, "404": { "description": "Task not found" } } }, "post": { "summary": "Upload a binary task file attachment", "description": "Accepts a raw binary request body. Pass the display/path name as the `name` query parameter.", "tags": [ "FS" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "taskId", "in": "path" }, { "schema": { "type": "string", "minLength": 1 }, "required": true, "name": "name", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "intent", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "description", "in": "query" }, { "schema": { "type": "string", "enum": [ "true", "false" ] }, "required": false, "name": "isPrimary", "in": "query" } ], "responses": { "201": { "description": "Uploaded task attachment" }, "400": { "description": "Validation error" }, "403": { "description": "Caller cannot mutate this task" }, "404": { "description": "Task not found" }, "413": { "description": "Upload exceeds 50 MiB" } } } }, "/api/fs/tasks/{taskId}/files/{attachmentId}": { "get": { "summary": "Get task file attachment metadata", "tags": [ "FS" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "taskId", "in": "path" }, { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "attachmentId", "in": "path" } ], "responses": { "200": { "description": "Task attachment metadata" }, "404": { "description": "Task or attachment not found" } } }, "delete": { "summary": "Delete a task file attachment", "tags": [ "FS" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "taskId", "in": "path" }, { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "attachmentId", "in": "path" } ], "responses": { "204": { "description": "Attachment deleted" }, "403": { "description": "Caller cannot mutate this task" }, "404": { "description": "Task or attachment not found" } } } }, "/api/fs/tasks/{taskId}/files/{attachmentId}/raw": { "get": { "summary": "Download raw task file bytes", "description": "Streams raw bytes. File content is not secret-scrubbed.", "tags": [ "FS" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "taskId", "in": "path" }, { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "attachmentId", "in": "path" } ], "responses": { "200": { "description": "Raw file bytes" }, "404": { "description": "Task, attachment, or provider object not found" } } } }, "/api/fs/tasks/{taskId}/files/{attachmentId}/signed-url": { "get": { "summary": "Create a provider signed GET URL for a task file", "tags": [ "FS" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "taskId", "in": "path" }, { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "attachmentId", "in": "path" }, { "schema": { "type": "integer", "exclusiveMinimum": 0, "maximum": 3600 }, "required": false, "name": "expiresIn", "in": "query" } ], "responses": { "200": { "description": "Signed URL" }, "404": { "description": "Task, attachment, or provider object not found" }, "501": { "description": "Active provider does not support signed URLs" } } } }, "/api/heartbeat/sweep": { "post": { "summary": "Trigger an immediate heartbeat sweep", "tags": [ "Heartbeat" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Sweep completed successfully" }, "401": { "description": "Unauthorized" } } } }, "/api/heartbeat/checklist": { "post": { "summary": "Trigger an immediate heartbeat checklist check", "tags": [ "Heartbeat" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Checklist check completed successfully" }, "401": { "description": "Unauthorized" } } } }, "/api/inbox-state": { "get": { "summary": "List inbox-item state rows for a user", "tags": [ "Inbox State" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "userId", "in": "query" }, { "schema": { "type": "string", "enum": [ "open", "snoozed", "dismissed", "done" ] }, "required": false, "name": "status", "in": "query" }, { "schema": { "type": "string", "enum": [ "approval", "credential_missing", "broken_task", "to_read", "to_start_template" ] }, "required": false, "name": "itemType", "in": "query" } ], "responses": { "200": { "description": "Inbox state rows" }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" } } }, "patch": { "summary": "Upsert per-user dismiss/snooze/done state for an inbox item", "tags": [ "Inbox State" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "userId": { "type": "string" }, "itemType": { "type": "string", "enum": [ "approval", "credential_missing", "broken_task", "to_read", "to_start_template" ] }, "itemId": { "type": "string", "minLength": 1 }, "status": { "type": "string", "enum": [ "open", "snoozed", "dismissed", "done" ] }, "snoozeUntil": { "type": "string", "format": "date-time" } }, "required": [ "userId", "itemType", "itemId", "status" ] } } } }, "responses": { "200": { "description": "Upserted inbox state row" }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" } } } }, "/api/integrations/claude-managed/test": { "post": { "summary": "Test the claude-managed integration: resolves ANTHROPIC_API_KEY + MANAGED_AGENT_ID from swarm_config and calls beta.agents.retrieve.", "tags": [ "Integrations" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": {} } } } }, "responses": { "200": { "description": "Connection result — `{ ok: true, agentName, model }` on success or `{ ok: false, error }` on any failure (missing config, Anthropic API error). Always 200 OK." } } } }, "/api/integrations/mcp-user/config": { "get": { "summary": "Get server-derived config for end-user MCP clients.", "tags": [ "Integrations" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Server-derived MCP user config. `mcpBaseUrl` is the API server base URL and `mcpUserUrl` appends `/mcp-user`." } } } }, "/api/kv/{key}": { "get": { "summary": "Get a KV entry by key (namespace resolved from request headers)", "tags": [ "KV" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 512, "pattern": "^[a-zA-Z0-9._:/%-]{1,512}$" }, "required": true, "name": "key", "in": "path" } ], "responses": { "200": { "description": "KV entry" }, "400": { "description": "Validation error or unresolvable namespace" }, "404": { "description": "KV entry not found or expired" } } }, "put": { "summary": "Upsert a KV entry by key (namespace resolved from request headers)", "tags": [ "KV" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 512, "pattern": "^[a-zA-Z0-9._:/%-]{1,512}$" }, "required": true, "name": "key", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "value": {}, "valueType": { "type": "string", "enum": [ "json", "string", "integer" ] }, "expiresInSec": { "type": "integer", "exclusiveMinimum": 0 } } } } } }, "responses": { "200": { "description": "KV entry stored" }, "400": { "description": "Validation error" }, "403": { "description": "Caller may not write this namespace" }, "409": { "description": "INCR collision: existing value_type is not 'integer'" }, "413": { "description": "Body exceeds 2 MiB" } } }, "delete": { "summary": "Delete a KV entry by key (namespace resolved from request headers)", "tags": [ "KV" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 512, "pattern": "^[a-zA-Z0-9._:/%-]{1,512}$" }, "required": true, "name": "key", "in": "path" } ], "responses": { "204": { "description": "KV entry deleted" }, "400": { "description": "Validation error or unresolvable namespace" }, "403": { "description": "Caller may not write this namespace" }, "404": { "description": "KV entry not found" } } } }, "/api/kv/{key}/incr": { "post": { "summary": "Atomically increment an integer KV entry (header-resolved namespace)", "tags": [ "KV" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 512, "pattern": "^[a-zA-Z0-9._:/%-]{1,512}$" }, "required": true, "name": "key", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": [ "object", "null" ], "properties": { "by": { "type": "integer" } } } } } }, "responses": { "200": { "description": "KV entry stored" }, "400": { "description": "Validation error" }, "403": { "description": "Caller may not write this namespace" }, "409": { "description": "INCR collision: existing value_type is not 'integer'" }, "413": { "description": "Body exceeds 2 MiB" } } } }, "/api/kv": { "get": { "summary": "List KV entries in the header-resolved namespace", "tags": [ "KV" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "prefix", "in": "query" }, { "schema": { "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": [ "integer", "null" ], "minimum": 0 }, "required": false, "name": "offset", "in": "query" } ], "responses": { "200": { "description": "KV entries in the resolved namespace" }, "400": { "description": "Validation error or unresolvable namespace" } } } }, "/api/kv/_/{namespace}/{key}": { "get": { "summary": "Get a KV entry by explicit namespace + key", "tags": [ "KV" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 512, "pattern": "^[a-zA-Z0-9._:/%-]{1,512}$" }, "required": true, "name": "namespace", "in": "path" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 512, "pattern": "^[a-zA-Z0-9._:/%-]{1,512}$" }, "required": true, "name": "key", "in": "path" } ], "responses": { "200": { "description": "KV entry" }, "400": { "description": "Validation error or unresolvable namespace" }, "404": { "description": "KV entry not found or expired" } } }, "put": { "summary": "Upsert a KV entry by explicit namespace + key", "tags": [ "KV" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 512, "pattern": "^[a-zA-Z0-9._:/%-]{1,512}$" }, "required": true, "name": "namespace", "in": "path" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 512, "pattern": "^[a-zA-Z0-9._:/%-]{1,512}$" }, "required": true, "name": "key", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "value": {}, "valueType": { "type": "string", "enum": [ "json", "string", "integer" ] }, "expiresInSec": { "type": "integer", "exclusiveMinimum": 0 } } } } } }, "responses": { "200": { "description": "KV entry stored" }, "400": { "description": "Validation error" }, "403": { "description": "Caller may not write this namespace" }, "409": { "description": "INCR collision: existing value_type is not 'integer'" }, "413": { "description": "Body exceeds 2 MiB" } } }, "delete": { "summary": "Delete a KV entry by explicit namespace + key", "tags": [ "KV" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 512, "pattern": "^[a-zA-Z0-9._:/%-]{1,512}$" }, "required": true, "name": "namespace", "in": "path" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 512, "pattern": "^[a-zA-Z0-9._:/%-]{1,512}$" }, "required": true, "name": "key", "in": "path" } ], "responses": { "204": { "description": "KV entry deleted" }, "403": { "description": "Caller may not write this namespace" }, "404": { "description": "KV entry not found" } } } }, "/api/kv/_/{namespace}/{key}/incr": { "post": { "summary": "Atomically increment an integer KV entry (explicit namespace)", "tags": [ "KV" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 512, "pattern": "^[a-zA-Z0-9._:/%-]{1,512}$" }, "required": true, "name": "namespace", "in": "path" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 512, "pattern": "^[a-zA-Z0-9._:/%-]{1,512}$" }, "required": true, "name": "key", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": [ "object", "null" ], "properties": { "by": { "type": "integer" } } } } } }, "responses": { "200": { "description": "KV entry stored" }, "400": { "description": "Validation error" }, "403": { "description": "Caller may not write this namespace" }, "409": { "description": "INCR collision: existing value_type is not 'integer'" }, "413": { "description": "Body exceeds 2 MiB" } } } }, "/api/kv/_/{namespace}": { "get": { "summary": "List KV entries in an explicit namespace", "tags": [ "KV" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 512, "pattern": "^[a-zA-Z0-9._:/%-]{1,512}$" }, "required": true, "name": "namespace", "in": "path" }, { "schema": { "type": "string" }, "required": false, "name": "prefix", "in": "query" }, { "schema": { "type": "integer", "exclusiveMinimum": 0, "maximum": 1000 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": [ "integer", "null" ], "minimum": 0 }, "required": false, "name": "offset", "in": "query" } ], "responses": { "200": { "description": "KV entries in the resolved namespace" }, "400": { "description": "Validation error or unresolvable namespace" } } } }, "/api/memory/index": { "post": { "summary": "Ingest content into memory system (async embedding)", "tags": [ "Memory" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "agentId": { "type": "string" }, "content": { "type": "string", "minLength": 1 }, "name": { "type": "string", "minLength": 1 }, "scope": { "type": "string", "enum": [ "agent", "swarm" ] }, "source": { "type": "string", "enum": [ "manual", "file_index", "session_summary", "task_completion" ] }, "sourceTaskId": { "type": "string", "format": "uuid" }, "sourcePath": { "type": "string" }, "tags": { "type": "array", "items": { "type": "string" } }, "persistMemory": { "type": "boolean" }, "contextKey": { "type": "string" } }, "required": [ "content", "name", "scope", "source" ] } } } }, "responses": { "202": { "description": "Content queued for embedding" }, "400": { "description": "Validation error" } } } }, "/api/memory/search": { "post": { "summary": "Search memories by natural language query", "tags": [ "Memory" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "query": { "type": "string", "minLength": 1 }, "intent": { "type": "string", "minLength": 1, "description": "Why you are searching. Required for agent recall-edge tracking; omit for UI browse/search calls." }, "limit": { "type": "integer", "minimum": 1, "maximum": 20, "default": 5 }, "scope": { "type": "string", "enum": [ "agent", "swarm", "all" ], "default": "all" }, "source": { "type": "string", "enum": [ "manual", "file_index", "session_summary", "task_completion" ] } }, "required": [ "query" ] } } } }, "responses": { "200": { "description": "Search results" }, "400": { "description": "Missing query or agent ID" } } } }, "/api/memory/edit": { "post": { "summary": "Edit a single memory in place while preserving its ID and usefulness posterior. Modes: 'replace' overwrites entire content; 'exact' performs surgical find-and-replace of oldString→newString (fails if missing or ambiguous)", "tags": [ "Memory" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "memoryId": { "type": "string", "format": "uuid" }, "key": { "type": "string", "minLength": 1 }, "scope": { "type": "string", "enum": [ "agent", "swarm" ] }, "mode": { "type": "string", "enum": [ "replace", "exact" ], "default": "replace" }, "content": { "type": "string", "minLength": 1 }, "oldString": { "type": "string", "minLength": 1 }, "newString": { "type": "string" }, "intent": { "type": "string", "minLength": 1 }, "expectedVersion": { "type": "integer", "minimum": 1 } }, "required": [ "intent" ] } } } }, "responses": { "200": { "description": "Memory edited" }, "400": { "description": "Validation error" }, "404": { "description": "Memory not found" }, "409": { "description": "Version conflict" } } } }, "/api/memory/re-embed": { "post": { "summary": "Re-embed all memories using the current embedding provider", "tags": [ "Memory" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "agentId": { "type": "string", "format": "uuid", "description": "Re-embed only this agent's memories. Omit for all." }, "batchSize": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20, "description": "Memories per batch" } } } } } }, "responses": { "202": { "description": "Re-embedding started" } } } }, "/api/memory/list": { "post": { "summary": "List or semantically search memories across all agents (debug/admin)", "tags": [ "Memory" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "query": { "type": "string", "description": "Natural-language query. If present, runs semantic search; otherwise lists by recency." }, "agentId": { "type": "string", "description": "Filter to a single agent. Omit for all." }, "scope": { "type": "string", "enum": [ "agent", "swarm", "all" ], "default": "all" }, "source": { "type": "string", "enum": [ "manual", "file_index", "session_summary", "task_completion" ] }, "sourcePath": { "type": "string", "description": "Substring match against sourcePath (case-insensitive). Useful for file_index memories." }, "limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }, "offset": { "type": "integer", "minimum": 0, "default": 0 } } } } } }, "responses": { "200": { "description": "Memory list / search results" }, "400": { "description": "Validation error" } } } }, "/api/memory/health": { "get": { "summary": "Report memory vector index health and retrieval mode", "tags": [ "Memory" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Memory vector index health" } } } }, "/api/memory/usefulness": { "get": { "summary": "Windowed memory usefulness analytics: retrieval volume, per-arm breakdown, citation rate per source, posterior movement", "tags": [ "Memory" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "integer", "minimum": 1, "maximum": 365, "default": 30, "description": "Analysis window in days (default 30)" }, "required": false, "description": "Analysis window in days (default 30)", "name": "days", "in": "query" }, { "schema": { "type": [ "number", "null" ], "minimum": 0, "maximum": 1, "default": 0.6, "description": "Posterior-mean threshold for the aboveThreshold count (default 0.6)" }, "required": false, "description": "Posterior-mean threshold for the aboveThreshold count (default 0.6)", "name": "threshold", "in": "query" } ], "responses": { "200": { "description": "Usefulness stats for the window" }, "400": { "description": "Validation error" } } } }, "/api/memory/{id}": { "delete": { "summary": "Delete a single memory by ID (debug/admin)", "tags": [ "Memory" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Memory deleted" }, "404": { "description": "Memory not found" } } }, "get": { "summary": "Get a single memory by ID", "tags": [ "Memory" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "minLength": 1, "description": "Why you are retrieving this memory. Required for agent recall-edge tracking; omit for UI browse calls." }, "required": false, "description": "Why you are retrieving this memory. Required for agent recall-edge tracking; omit for UI browse calls.", "name": "intent", "in": "query" } ], "responses": { "200": { "description": "Memory details, plus `links` (outgoing memory_link rows; memory-kind targets carry `resolved` + ACL-filtered `target` metadata) and `backlinks` (inbound links from other memories, ACL-filtered)" }, "404": { "description": "Memory not found" } } } }, "/api/memory/rate": { "post": { "summary": "Submit RatingEvents to update memory usefulness posteriors", "tags": [ "Memory" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "events": { "type": "array", "items": { "type": "object", "properties": { "memoryId": { "type": "string", "minLength": 1 }, "signal": { "type": "number", "minimum": -1, "maximum": 1 }, "weight": { "type": "number", "minimum": 0, "maximum": 1 }, "source": { "type": "string", "enum": [ "llm", "explicit-self" ] }, "reasoning": { "type": "string", "maxLength": 500 }, "taskId": { "type": "string", "format": "uuid" }, "referencesSource": { "type": "string", "minLength": 1, "maxLength": 512, "description": "Optional external source ID this memory references. Free-form string, convention \":\" (e.g. \"github:owner/repo#N\", \"linear:KEY-N\", \"customer:\", \"slack::\", \"agentmail:\"). Pick any prefix that fits — no closed enum. When present, an edge from this memory to the external source is created/updated." } }, "required": [ "memoryId", "signal", "weight", "source" ] }, "minItems": 1, "maxItems": 50 } }, "required": [ "events" ] } } } }, "responses": { "200": { "description": "Ratings applied; per-event rejections returned in body" }, "400": { "description": "Validation error or explicit-self R6 spam-guard rejection" }, "409": { "description": "Duplicate explicit-self rating for (taskId, memoryId)" } } } }, "/api/memory/retrievals": { "get": { "summary": "List memories retrieved for a task or session (rater input)", "tags": [ "Memory" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": false, "name": "taskId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "sessionId", "in": "query" } ], "responses": { "200": { "description": "Retrieval rows joined with agent_memory" }, "400": { "description": "Missing taskId/sessionId or X-Agent-ID" } } } }, "/api/memory/edges": { "get": { "summary": "List references-source edges for a memory", "tags": [ "Memory" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1 }, "required": true, "name": "memoryId", "in": "query" } ], "responses": { "200": { "description": "Edges with computed usefulness scores" }, "400": { "description": "Missing memoryId or X-Agent-ID" } } } }, "/api/metrics/definitions": { "post": { "summary": "Create a metric definition", "tags": [ "Metrics" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "slug": { "type": "string", "minLength": 1 }, "title": { "type": "string", "minLength": 1 }, "description": { "type": [ "string", "null" ] }, "definition": { "type": "object", "properties": { "version": { "type": "number", "enum": [ 1 ] }, "widgets": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1 }, "title": { "type": "string", "minLength": 1 }, "description": { "type": "string" }, "query": { "type": "object", "properties": { "sql": { "type": "string", "minLength": 1, "maxLength": 10000 }, "params": { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" } ] } }, "maxRows": { "type": "integer", "minimum": 1, "maximum": 500 } }, "required": [ "sql" ] }, "viz": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "stat", "table", "bar", "line", "multi-bar", "multi-line" ] }, "x": { "type": "string" }, "y": { "type": "string" }, "series": { "type": "array", "items": { "type": "string" } }, "label": { "type": "string" }, "value": { "type": "string" }, "columns": { "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "label": { "type": "string" }, "format": { "type": "string", "enum": [ "number", "integer", "currency", "percent", "duration" ] } }, "required": [ "key" ] } }, "format": { "type": "string", "enum": [ "number", "integer", "currency", "percent", "duration" ] } }, "required": [ "type" ] }, "colSpan": { "type": "integer", "minimum": 1, "maximum": 4 }, "rowSpan": { "type": "integer", "minimum": 1, "maximum": 4 } }, "required": [ "id", "title", "query", "viz" ] }, "minItems": 1, "maxItems": 24 }, "variables": { "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string", "minLength": 1, "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$" }, "label": { "type": "string", "minLength": 1 }, "type": { "type": "string", "enum": [ "text", "number", "select" ], "default": "text" }, "defaultValue": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" } ] }, "options": { "type": "array", "items": { "type": "object", "properties": { "label": { "type": "string", "minLength": 1 }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" } ] } }, "required": [ "label", "value" ] } }, "optionsQuery": { "type": "object", "properties": { "sql": { "type": "string", "minLength": 1, "maxLength": 10000 }, "valueKey": { "type": "string", "minLength": 1 }, "labelKey": { "type": "string", "minLength": 1 } }, "required": [ "sql", "valueKey" ] } }, "required": [ "key" ] }, "maxItems": 12 }, "layout": { "type": "object", "properties": { "columns": { "type": "integer", "minimum": 1, "maximum": 4 } } }, "refreshSeconds": { "type": "integer", "minimum": 5, "maximum": 3600 } }, "required": [ "version", "widgets" ] } }, "required": [ "title", "definition" ] } } } }, "responses": { "201": { "description": "Metric created" }, "400": { "description": "Invalid metric definition" }, "409": { "description": "Slug already exists for this agent" } } }, "get": { "summary": "List metric definitions", "tags": [ "Metrics" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1 }, "required": false, "name": "agentId", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 500 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": [ "integer", "null" ], "minimum": 0 }, "required": false, "name": "offset", "in": "query" }, { "schema": { "type": "string", "enum": [ "full", "slim" ] }, "required": false, "name": "fields", "in": "query" } ], "responses": { "200": { "description": "Metric definitions" } } } }, "/api/metrics/definitions/{id}": { "get": { "summary": "Get a metric definition", "tags": [ "Metrics" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Metric definition" }, "404": { "description": "Metric not found" } } }, "put": { "summary": "Update a metric definition", "tags": [ "Metrics" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "slug": { "type": "string", "minLength": 1 }, "title": { "type": "string", "minLength": 1 }, "description": { "type": [ "string", "null" ] }, "definition": { "type": "object", "properties": { "version": { "type": "number", "enum": [ 1 ] }, "widgets": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1 }, "title": { "type": "string", "minLength": 1 }, "description": { "type": "string" }, "query": { "type": "object", "properties": { "sql": { "type": "string", "minLength": 1, "maxLength": 10000 }, "params": { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" } ] } }, "maxRows": { "type": "integer", "minimum": 1, "maximum": 500 } }, "required": [ "sql" ] }, "viz": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "stat", "table", "bar", "line", "multi-bar", "multi-line" ] }, "x": { "type": "string" }, "y": { "type": "string" }, "series": { "type": "array", "items": { "type": "string" } }, "label": { "type": "string" }, "value": { "type": "string" }, "columns": { "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "label": { "type": "string" }, "format": { "type": "string", "enum": [ "number", "integer", "currency", "percent", "duration" ] } }, "required": [ "key" ] } }, "format": { "type": "string", "enum": [ "number", "integer", "currency", "percent", "duration" ] } }, "required": [ "type" ] }, "colSpan": { "type": "integer", "minimum": 1, "maximum": 4 }, "rowSpan": { "type": "integer", "minimum": 1, "maximum": 4 } }, "required": [ "id", "title", "query", "viz" ] }, "minItems": 1, "maxItems": 24 }, "variables": { "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string", "minLength": 1, "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$" }, "label": { "type": "string", "minLength": 1 }, "type": { "type": "string", "enum": [ "text", "number", "select" ], "default": "text" }, "defaultValue": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" } ] }, "options": { "type": "array", "items": { "type": "object", "properties": { "label": { "type": "string", "minLength": 1 }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" } ] } }, "required": [ "label", "value" ] } }, "optionsQuery": { "type": "object", "properties": { "sql": { "type": "string", "minLength": 1, "maxLength": 10000 }, "valueKey": { "type": "string", "minLength": 1 }, "labelKey": { "type": "string", "minLength": 1 } }, "required": [ "sql", "valueKey" ] } }, "required": [ "key" ] }, "maxItems": 12 }, "layout": { "type": "object", "properties": { "columns": { "type": "integer", "minimum": 1, "maximum": 4 } } }, "refreshSeconds": { "type": "integer", "minimum": 5, "maximum": 3600 } }, "required": [ "version", "widgets" ] } } } } } }, "responses": { "200": { "description": "Metric updated" }, "404": { "description": "Metric not found" } } }, "delete": { "summary": "Delete a metric definition", "tags": [ "Metrics" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "204": { "description": "Metric deleted" }, "404": { "description": "Metric not found" } } } }, "/api/metrics/definitions/{id}/run": { "post": { "summary": "Run a metric definition", "tags": [ "Metrics" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "variables": { "type": "object", "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "null" } ] } } } } } } }, "responses": { "200": { "description": "Metric result" }, "400": { "description": "Invalid or disallowed query" }, "404": { "description": "Metric not found" } } } }, "/api/metrics/definitions/{id}/versions": { "get": { "summary": "List metric definition versions", "tags": [ "Metrics" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Metric version list" }, "404": { "description": "Metric not found" } } } }, "/api/metrics/definitions/{id}/versions/{version}": { "get": { "summary": "Get a metric definition version", "tags": [ "Metrics" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "integer", "minimum": 1 }, "required": true, "name": "version", "in": "path" } ], "responses": { "200": { "description": "Metric version" }, "404": { "description": "Metric or version not found" } } } }, "/api/metrics/schema": { "get": { "summary": "Get the metric definition JSON Schema", "tags": [ "Metrics" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Metric definition JSON Schema" } } } }, "/api/models-catalog": { "get": { "summary": "Get the live model catalog for the picker-reachable providers", "description": "Slim projection of the models.dev payload (openrouter / anthropic / openai / amazon-bedrock only), refreshed server-side at boot and every 12h by the pricing-refresh loop. `source` is 'snapshot' with `updatedAt: null` until the first successful fetch (or when models.dev is unreachable), in which case the vendored snapshot is served instead.", "tags": [ "Pricing" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Model catalog", "content": { "application/json": { "schema": { "type": "object", "properties": { "source": { "type": "string", "enum": [ "live", "snapshot" ] }, "updatedAt": { "type": [ "number", "null" ] }, "providers": { "type": "object", "additionalProperties": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "models": { "type": "object", "additionalProperties": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "cost": { "type": "object", "properties": { "input": { "type": "number" }, "output": { "type": "number" } } }, "limit": { "type": "object", "properties": { "context": { "type": "number" } } }, "reasoning": { "type": "boolean" }, "reasoning_options": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string" }, "values": { "type": "array", "items": { "type": "string" } } }, "required": [ "type" ] } } }, "required": [ "id" ] } } }, "required": [ "id", "models" ] } } }, "required": [ "source", "updatedAt", "providers" ] } } } } } } }, "/api/oauth/refresh-locks/{key}": { "post": { "summary": "Acquire a cross-process OAuth refresh lock", "tags": [ "OAuth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "pattern": "^[a-zA-Z0-9._:-]{1,200}$" }, "required": true, "name": "key", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "ttlMs": { "type": "integer", "exclusiveMinimum": 0, "maximum": 300000 } }, "required": [ "ttlMs" ] } } } }, "responses": { "200": { "description": "Lock acquired; returns the owner token" }, "400": { "description": "Validation error" }, "409": { "description": "Lock is currently held by another caller" } } }, "delete": { "summary": "Release a cross-process OAuth refresh lock if still held by the given owner", "tags": [ "OAuth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "pattern": "^[a-zA-Z0-9._:-]{1,200}$" }, "required": true, "name": "key", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "owner": { "type": "string", "minLength": 1 } }, "required": [ "owner" ] } } } }, "responses": { "204": { "description": "Released (a mismatched/expired owner is a no-op, also 204)" }, "400": { "description": "Validation error" } } } }, "/api/mcp-oauth/{mcpServerId}/metadata": { "get": { "summary": "Probe OAuth metadata (PRMD + AS) for an MCP server", "tags": [ "MCP OAuth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "mcpServerId", "in": "path" } ], "responses": { "200": { "description": "OAuth metadata or { requiresOAuth: false }" }, "400": { "description": "MCP has no URL / invalid transport" }, "404": { "description": "MCP server not found" } } } }, "/api/mcp-oauth/{mcpServerId}/status": { "get": { "summary": "Get the current OAuth connection status for an MCP server", "tags": [ "MCP OAuth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "mcpServerId", "in": "path" }, { "schema": { "type": "string" }, "required": false, "name": "userId", "in": "query" } ], "responses": { "200": { "description": "Token status (never includes the token value itself)" }, "404": { "description": "MCP server not found" } } } }, "/api/mcp-oauth/{mcpServerId}/authorize": { "get": { "summary": "Start an OAuth flow. Redirects to the provider.", "tags": [ "MCP OAuth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "mcpServerId", "in": "path" }, { "schema": { "type": "string" }, "required": false, "name": "redirect", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "userId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "scopes", "in": "query" } ], "responses": { "302": { "description": "Redirect to authorization server" }, "400": { "description": "MCP has no URL / does not require OAuth" }, "404": { "description": "MCP server not found" } } } }, "/api/mcp-oauth/{mcpServerId}/authorize-url": { "get": { "summary": "Build an OAuth authorize URL. Returns JSON so the browser can navigate without losing the Bearer auth header.", "tags": [ "MCP OAuth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "mcpServerId", "in": "path" }, { "schema": { "type": "string" }, "required": false, "name": "redirect", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "userId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "scopes", "in": "query" } ], "responses": { "200": { "description": "{ providerUrl: string }" }, "400": { "description": "MCP has no URL / does not require OAuth" }, "404": { "description": "MCP server not found" } } } }, "/api/mcp-oauth/callback": { "get": { "summary": "OAuth redirect target. Exchanges code -> tokens and redirects back to dashboard.", "tags": [ "MCP OAuth" ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "code", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "state", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "error", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "error_description", "in": "query" } ], "responses": { "302": { "description": "Redirect back to dashboard with oauth=success or oauth=error" }, "400": { "description": "Bad state / missing code" } } } }, "/api/mcp-oauth/{mcpServerId}/refresh": { "post": { "summary": "Force-refresh the access token for an MCP server", "tags": [ "MCP OAuth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "mcpServerId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "userId": { "type": "string" } } } } } }, "responses": { "200": { "description": "Refreshed token" }, "404": { "description": "No token for this MCP server" }, "500": { "description": "Refresh failed" } } } }, "/api/mcp-oauth/{mcpServerId}": { "delete": { "summary": "Revoke and delete the OAuth token for an MCP server", "tags": [ "MCP OAuth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "mcpServerId", "in": "path" }, { "schema": { "type": "string" }, "required": false, "name": "userId", "in": "query" } ], "responses": { "200": { "description": "Token revoked/deleted" }, "404": { "description": "No token for this MCP server" } } } }, "/api/mcp-oauth/{mcpServerId}/manual-client": { "post": { "summary": "Register a pre-existing OAuth client (DCR fallback)", "tags": [ "MCP OAuth" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "mcpServerId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "clientId": { "type": "string", "minLength": 1 }, "clientSecret": { "type": "string" }, "authorizationServerIssuer": { "type": "string", "format": "uri" }, "authorizeUrl": { "type": "string", "format": "uri" }, "tokenUrl": { "type": "string", "format": "uri" }, "revocationUrl": { "type": "string", "format": "uri" }, "scopes": { "type": "array", "items": { "type": "string" } } }, "required": [ "clientId" ] } } } }, "responses": { "200": { "description": "Pending client stored. Call /authorize to start the flow." }, "400": { "description": "Bad input" }, "404": { "description": "MCP server not found" } } } }, "/api/oauth/callback": { "get": { "operationId": "oauth_static_callback", "summary": "Single static OAuth redirect target (state-keyed, all flows)", "tags": [ "OAuth" ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "code", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "state", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "error", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "error_description", "in": "query" } ], "responses": { "200": { "description": "OAuth authorization completed" }, "302": { "description": "Redirect back to the final destination" }, "400": { "description": "Missing or invalid OAuth callback parameters" }, "404": { "description": "OAuth app not configured" }, "502": { "description": "Token exchange failed" } } } }, "/api/oauth/redirect-uri": { "get": { "operationId": "oauth_redirect_uri", "summary": "The static OAuth callback URL to register with providers (pre-creation display)", "tags": [ "OAuth" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "{ redirectUri: string }" } } } }, "/api/oauth/{provider}/callback": { "get": { "operationId": "oauth_generic_callback", "summary": "Legacy per-provider OAuth redirect target (delegates to the static callback)", "tags": [ "OAuth" ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^[A-Za-z0-9_-]+$" }, "required": true, "name": "provider", "in": "path" }, { "schema": { "type": "string" }, "required": false, "name": "code", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "state", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "error", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "error_description", "in": "query" } ], "responses": { "200": { "description": "OAuth authorization completed" }, "400": { "description": "Missing or invalid OAuth callback parameters" }, "404": { "description": "OAuth app not configured" }, "502": { "description": "Token exchange failed" } } } }, "/@swarm/api/{path}": { "get": { "summary": "Cookie-gated proxy to the swarm API (used by db-backed page iframes)", "tags": [ "Pages" ], "responses": { "200": { "description": "Proxied response from the underlying /api/* endpoint" }, "401": { "description": "No or invalid page-session cookie" }, "404": { "description": "Page referenced by the cookie no longer exists" } } }, "post": { "summary": "Cookie-gated proxy to the swarm API (POST)", "tags": [ "Pages" ], "responses": { "200": { "description": "Proxied response" }, "401": { "description": "No or invalid page-session cookie" } } }, "put": { "summary": "Cookie-gated proxy to the swarm API (PUT)", "tags": [ "Pages" ], "responses": { "200": { "description": "Proxied response" }, "401": { "description": "No or invalid page-session cookie" } } }, "delete": { "summary": "Cookie-gated proxy to the swarm API (DELETE)", "tags": [ "Pages" ], "responses": { "200": { "description": "Proxied response" }, "401": { "description": "No or invalid page-session cookie" } } }, "patch": { "summary": "Cookie-gated proxy to the swarm API (PATCH)", "tags": [ "Pages" ], "responses": { "200": { "description": "Proxied response" }, "401": { "description": "No or invalid page-session cookie" } } } }, "/api/pages": { "post": { "summary": "Create a new page", "tags": [ "Pages" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "key": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "slug": { "type": "string", "minLength": 1 }, "title": { "type": "string", "minLength": 1 }, "description": { "type": "string" }, "contentType": { "type": "string", "enum": [ "text/html", "application/json" ] }, "authMode": { "type": "string", "enum": [ "public", "authed", "password" ], "default": "authed" }, "password": { "type": "string", "minLength": 1 }, "body": { "type": "string" }, "needsCredentials": { "type": "array", "items": { "type": "string" } } }, "required": [ "title", "contentType", "body" ] } } } }, "responses": { "201": { "description": "Page created" }, "400": { "description": "Invalid body" }, "409": { "description": "Slug already exists for this agent" } } }, "get": { "summary": "List pages", "description": "Returns pages WITHOUT the heavy `body` (the full HTML/JSON document) and `passwordHash` by default — list views never render the body. Pass `fields=full` to restore `body`. Fetch a full page via `GET /api/pages/{id}`.", "tags": [ "Pages" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1 }, "required": false, "name": "agentId", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "required": false, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form.", "name": "key", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "required": false, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form.", "name": "keyPrefix", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 500 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": [ "integer", "null" ], "minimum": 0 }, "required": false, "name": "offset", "in": "query" }, { "schema": { "type": "string", "enum": [ "full", "slim" ] }, "required": false, "name": "fields", "in": "query" } ], "responses": { "200": { "description": "Page list with totals + share-URL pointers" } } } }, "/api/pages/{id}": { "get": { "summary": "Get a page by ID", "tags": [ "Pages" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Page row" }, "404": { "description": "Page not found" } } }, "put": { "summary": "Update an existing page", "tags": [ "Pages" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "key": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "title": { "type": "string", "minLength": 1 }, "description": { "type": [ "string", "null" ] }, "contentType": { "type": "string", "enum": [ "text/html", "application/json" ] }, "authMode": { "type": "string", "enum": [ "public", "authed", "password" ] }, "password": { "type": [ "string", "null" ], "minLength": 1 }, "body": { "type": "string" }, "needsCredentials": { "type": [ "array", "null" ], "items": { "type": "string" } } } } } } }, "responses": { "200": { "description": "Page updated" }, "404": { "description": "Page not found" }, "413": { "description": "Payload too large" } } }, "delete": { "summary": "Delete a page (and all version history)", "tags": [ "Pages" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "204": { "description": "Page deleted" }, "404": { "description": "Page not found" } } } }, "/api/pages/resolve": { "get": { "summary": "Resolve a page by slug", "tags": [ "Pages" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1 }, "required": true, "name": "slug", "in": "query" }, { "schema": { "type": "string", "minLength": 1 }, "required": false, "name": "agentId", "in": "query" } ], "responses": { "200": { "description": "Resolved page row" }, "404": { "description": "Page not found" } } } }, "/api/pages/{id}/launch": { "post": { "summary": "Launch a page session (issues HttpOnly cookie)", "tags": [ "Pages" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "204": { "description": "Cookie issued" }, "400": { "description": "Launch not supported for this page (e.g. password mode)" }, "404": { "description": "Page not found" } } } }, "/api/pages/actions": { "get": { "summary": "List JSON-page action allowlist (with param JSON Schemas)", "tags": [ "Pages" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Action allowlist" } } } }, "/api/pages/{id}/versions": { "get": { "summary": "List version snapshots for a page", "tags": [ "Pages" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Version list (newest first)" }, "404": { "description": "Page not found" } } } }, "/api/pages/{id}/versions/{version}": { "get": { "summary": "Get a single page-version snapshot", "tags": [ "Pages" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "integer", "minimum": 1 }, "required": true, "name": "version", "in": "path" } ], "responses": { "200": { "description": "Version snapshot" }, "404": { "description": "Page or version not found" } } } }, "/p/{id}": { "get": { "summary": "Render a page (HTML inline; JSON redirects to SPA)", "tags": [ "Pages" ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Rendered HTML page" }, "302": { "description": "Redirect to SPA for JSON content" }, "401": { "description": "Page requires an authenticated session" }, "403": { "description": "Cookie does not match this page id" }, "404": { "description": "Page not found" } } } }, "/p/{id}.json": { "get": { "summary": "Page metadata + body as JSON (used by SPA renderer)", "tags": [ "Pages" ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Page JSON" }, "401": { "description": "Page requires an authenticated session" }, "403": { "description": "Cookie does not match this page id" }, "404": { "description": "Page not found" } } } }, "/api/prompt-templates/resolved": { "get": { "summary": "Resolve a prompt template for a given event type and scope chain", "tags": [ "PromptTemplates" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "eventType", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "agentId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "repoId", "in": "query" } ], "responses": { "200": { "description": "Resolved template info" }, "400": { "description": "Missing eventType" } } } }, "/api/prompt-templates/events": { "get": { "summary": "List all registered event types with their available variables", "tags": [ "PromptTemplates" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "List of event template definitions" } } } }, "/api/prompt-templates/preview": { "post": { "summary": "Dry-run render a template with provided variables", "tags": [ "PromptTemplates" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "eventType": { "type": "string" }, "body": { "type": "string" }, "variables": { "type": "object", "additionalProperties": {} } }, "required": [ "eventType" ] } } } }, "responses": { "200": { "description": "Rendered template preview" }, "400": { "description": "Validation error" } } } }, "/api/prompt-templates/render": { "post": { "summary": "Full scope-aware template resolution with interpolation (used by workers via HTTP)", "tags": [ "PromptTemplates" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "eventType": { "type": "string" }, "variables": { "type": "object", "additionalProperties": {} }, "agentId": { "type": "string" }, "repoId": { "type": "string" } }, "required": [ "eventType" ] } } } }, "responses": { "200": { "description": "Fully resolved and interpolated template" }, "400": { "description": "Validation error" } } } }, "/api/prompt-templates/{id}/checkout": { "post": { "summary": "Checkout a specific version of a prompt template from history", "tags": [ "PromptTemplates" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "version": { "type": "number" } }, "required": [ "version" ] } } } }, "responses": { "200": { "description": "Checked-out template" }, "400": { "description": "Validation error" }, "404": { "description": "Template or version not found" } } } }, "/api/prompt-templates/{id}/reset": { "post": { "summary": "Reset a prompt template to its code-defined default", "tags": [ "PromptTemplates" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Reset template" }, "404": { "description": "Template not found or no code default available" } } } }, "/api/prompt-templates/{id}": { "get": { "summary": "Get a single prompt template with its version history", "tags": [ "PromptTemplates" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Template with history" }, "404": { "description": "Template not found" } } }, "delete": { "summary": "Delete a prompt template override", "tags": [ "PromptTemplates" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Template deleted" }, "400": { "description": "Cannot delete default template" }, "404": { "description": "Template not found" } } } }, "/api/prompt-templates": { "get": { "summary": "List prompt templates with optional filters", "tags": [ "PromptTemplates" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "eventType", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "scope", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "scopeId", "in": "query" }, { "schema": { "type": "string", "enum": [ "true", "false" ] }, "required": false, "name": "isDefault", "in": "query" } ], "responses": { "200": { "description": "List of prompt templates" } } }, "put": { "summary": "Create or update a prompt template override", "tags": [ "PromptTemplates" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "eventType": { "type": "string", "minLength": 1 }, "scope": { "type": "string", "enum": [ "global", "agent", "repo" ] }, "scopeId": { "type": "string" }, "state": { "type": "string", "enum": [ "enabled", "default_prompt_fallback", "skip_event" ] }, "body": { "type": "string" }, "changedBy": { "type": "string" }, "changeReason": { "type": "string" } }, "required": [ "eventType", "body" ] } } } }, "responses": { "200": { "description": "Upserted template" }, "400": { "description": "Validation error" } } } }, "/api/poll": { "get": { "summary": "Poll for triggers (tasks, mentions)", "tags": [ "Poll" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Trigger data or null" }, "400": { "description": "Missing X-Agent-ID" }, "404": { "description": "Agent not found" } } } }, "/api/channel-activity/commit-cursors": { "post": { "summary": "Commit channel activity cursors after successful processing", "tags": [ "Poll" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "cursorUpdates": { "type": "array", "items": { "type": "object", "properties": { "channelId": { "type": "string" }, "ts": { "type": "string" } }, "required": [ "channelId", "ts" ] } } }, "required": [ "cursorUpdates" ] } } } }, "responses": { "200": { "description": "Cursors committed" }, "400": { "description": "Invalid request" } } } }, "/api/pricing": { "get": { "summary": "List every pricing row across all providers", "tags": [ "Pricing" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Pricing rows", "content": { "application/json": { "schema": { "type": "object", "properties": { "rows": { "type": "array", "items": { "type": "object", "properties": { "provider": { "type": "string", "enum": [ "claude", "claude-managed", "codex", "pi", "opencode", "devin", "gemini" ] }, "model": { "type": "string" }, "tokenClass": { "type": "string", "enum": [ "input", "cached_input", "output", "cache_write", "runtime_hour", "acu" ] }, "effectiveFrom": { "type": "number", "minimum": 0 }, "pricePerMillionUsd": { "type": "number", "minimum": 0 }, "createdAt": { "type": "number" }, "lastUpdatedAt": { "type": "number" } }, "required": [ "provider", "model", "tokenClass", "effectiveFrom", "pricePerMillionUsd", "createdAt", "lastUpdatedAt" ] } } }, "required": [ "rows" ] } } } } } } }, "/api/pricing/{provider}/{model}/{tokenClass}": { "get": { "summary": "List pricing history for a (provider, model, tokenClass) triple", "tags": [ "Pricing" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "claude", "claude-managed", "codex", "pi", "opencode", "devin", "gemini" ] }, "required": true, "name": "provider", "in": "path" }, { "schema": { "type": "string", "minLength": 1 }, "required": true, "name": "model", "in": "path" }, { "schema": { "type": "string", "enum": [ "input", "cached_input", "output", "cache_write", "runtime_hour", "acu" ] }, "required": true, "name": "tokenClass", "in": "path" } ], "responses": { "200": { "description": "Pricing rows (latest first)" } } }, "post": { "summary": "Append a new pricing row", "tags": [ "Pricing" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "claude", "claude-managed", "codex", "pi", "opencode", "devin", "gemini" ] }, "required": true, "name": "provider", "in": "path" }, { "schema": { "type": "string", "minLength": 1 }, "required": true, "name": "model", "in": "path" }, { "schema": { "type": "string", "enum": [ "input", "cached_input", "output", "cache_write", "runtime_hour", "acu" ] }, "required": true, "name": "tokenClass", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "pricePerMillionUsd": { "type": "number", "minimum": 0 }, "effectiveFrom": { "type": "number", "minimum": 0 } }, "required": [ "pricePerMillionUsd" ] } } } }, "responses": { "201": { "description": "Pricing row inserted", "content": { "application/json": { "schema": { "type": "object", "properties": { "provider": { "type": "string", "enum": [ "claude", "claude-managed", "codex", "pi", "opencode", "devin", "gemini" ] }, "model": { "type": "string" }, "tokenClass": { "type": "string", "enum": [ "input", "cached_input", "output", "cache_write", "runtime_hour", "acu" ] }, "effectiveFrom": { "type": "number", "minimum": 0 }, "pricePerMillionUsd": { "type": "number", "minimum": 0 }, "createdAt": { "type": "number" }, "lastUpdatedAt": { "type": "number" } }, "required": [ "provider", "model", "tokenClass", "effectiveFrom", "pricePerMillionUsd", "createdAt", "lastUpdatedAt" ] } } } }, "400": { "description": "Validation error" }, "409": { "description": "Duplicate (provider, model, tokenClass, effectiveFrom)" } } } }, "/api/pricing/{provider}/{model}/{tokenClass}/active": { "get": { "summary": "Get the currently active pricing row", "tags": [ "Pricing" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "claude", "claude-managed", "codex", "pi", "opencode", "devin", "gemini" ] }, "required": true, "name": "provider", "in": "path" }, { "schema": { "type": "string", "minLength": 1 }, "required": true, "name": "model", "in": "path" }, { "schema": { "type": "string", "enum": [ "input", "cached_input", "output", "cache_write", "runtime_hour", "acu" ] }, "required": true, "name": "tokenClass", "in": "path" } ], "responses": { "200": { "description": "Active pricing row", "content": { "application/json": { "schema": { "type": "object", "properties": { "provider": { "type": "string", "enum": [ "claude", "claude-managed", "codex", "pi", "opencode", "devin", "gemini" ] }, "model": { "type": "string" }, "tokenClass": { "type": "string", "enum": [ "input", "cached_input", "output", "cache_write", "runtime_hour", "acu" ] }, "effectiveFrom": { "type": "number", "minimum": 0 }, "pricePerMillionUsd": { "type": "number", "minimum": 0 }, "createdAt": { "type": "number" }, "lastUpdatedAt": { "type": "number" } }, "required": [ "provider", "model", "tokenClass", "effectiveFrom", "pricePerMillionUsd", "createdAt", "lastUpdatedAt" ] } } } }, "404": { "description": "No pricing row in effect" } } } }, "/api/pricing/{provider}/{model}/{tokenClass}/{effectiveFrom}": { "delete": { "summary": "Delete a pricing row (typo correction)", "tags": [ "Pricing" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "claude", "claude-managed", "codex", "pi", "opencode", "devin", "gemini" ] }, "required": true, "name": "provider", "in": "path" }, { "schema": { "type": "string", "minLength": 1 }, "required": true, "name": "model", "in": "path" }, { "schema": { "type": "string", "enum": [ "input", "cached_input", "output", "cache_write", "runtime_hour", "acu" ] }, "required": true, "name": "tokenClass", "in": "path" }, { "schema": { "type": "string", "pattern": "^\\d+$" }, "required": true, "name": "effectiveFrom", "in": "path" } ], "responses": { "204": { "description": "Pricing row deleted" }, "404": { "description": "Pricing row not found" } } } }, "/api/repos/{id}": { "get": { "summary": "Get a repo by ID", "tags": [ "Repos" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Repo details", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "url": { "type": "string", "minLength": 1 }, "name": { "type": "string", "minLength": 1, "maxLength": 100 }, "clonePath": { "type": "string", "minLength": 1 }, "defaultBranch": { "type": "string", "default": "main" }, "autoClone": { "type": "boolean", "default": true }, "hooks": { "type": "object", "properties": { "enabled": { "type": "boolean", "default": false } }, "default": { "enabled": false } }, "guidelines": { "type": [ "object", "null" ], "properties": { "prChecks": { "type": "array", "items": { "type": "string" } }, "mergeChecks": { "type": "array", "items": { "type": "string" } }, "allowMerge": { "type": "boolean", "default": false }, "review": { "type": "array", "items": { "type": "string" } } }, "required": [ "prChecks", "mergeChecks", "review" ] }, "createdAt": { "type": "string" }, "lastUpdatedAt": { "type": "string" } }, "required": [ "id", "url", "name", "clonePath", "createdAt", "lastUpdatedAt" ] } } } }, "404": { "description": "Repo not found", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } }, "required": [ "error" ] } } } } } }, "put": { "summary": "Update a repo", "tags": [ "Repos" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "url": { "type": "string" }, "name": { "type": "string" }, "clonePath": { "type": "string" }, "defaultBranch": { "type": "string" }, "autoClone": { "type": "boolean" }, "hooks": { "type": [ "object", "null" ], "properties": { "enabled": { "type": "boolean", "default": false } } }, "guidelines": { "type": [ "object", "null" ], "properties": { "prChecks": { "type": "array", "items": { "type": "string" } }, "mergeChecks": { "type": "array", "items": { "type": "string" } }, "allowMerge": { "type": "boolean", "default": false }, "review": { "type": "array", "items": { "type": "string" } } }, "required": [ "prChecks", "mergeChecks", "review" ] } } } } } }, "responses": { "200": { "description": "Repo updated", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "url": { "type": "string", "minLength": 1 }, "name": { "type": "string", "minLength": 1, "maxLength": 100 }, "clonePath": { "type": "string", "minLength": 1 }, "defaultBranch": { "type": "string", "default": "main" }, "autoClone": { "type": "boolean", "default": true }, "hooks": { "type": "object", "properties": { "enabled": { "type": "boolean", "default": false } }, "default": { "enabled": false } }, "guidelines": { "type": [ "object", "null" ], "properties": { "prChecks": { "type": "array", "items": { "type": "string" } }, "mergeChecks": { "type": "array", "items": { "type": "string" } }, "allowMerge": { "type": "boolean", "default": false }, "review": { "type": "array", "items": { "type": "string" } } }, "required": [ "prChecks", "mergeChecks", "review" ] }, "createdAt": { "type": "string" }, "lastUpdatedAt": { "type": "string" } }, "required": [ "id", "url", "name", "clonePath", "createdAt", "lastUpdatedAt" ] } } } }, "404": { "description": "Repo not found", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } }, "required": [ "error" ] } } } }, "409": { "description": "Duplicate repo", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } }, "required": [ "error" ] } } } } } }, "delete": { "summary": "Delete a repo", "tags": [ "Repos" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Repo deleted", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" } }, "required": [ "success" ] } } } }, "404": { "description": "Repo not found", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } }, "required": [ "error" ] } } } } } } }, "/api/repos": { "get": { "summary": "List repos with optional filters", "tags": [ "Repos" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "true", "false" ] }, "required": false, "name": "autoClone", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "name", "in": "query" } ], "responses": { "200": { "description": "List of repos", "content": { "application/json": { "schema": { "type": "object", "properties": { "repos": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "url": { "type": "string", "minLength": 1 }, "name": { "type": "string", "minLength": 1, "maxLength": 100 }, "clonePath": { "type": "string", "minLength": 1 }, "defaultBranch": { "type": "string", "default": "main" }, "autoClone": { "type": "boolean", "default": true }, "hooks": { "type": "object", "properties": { "enabled": { "type": "boolean", "default": false } }, "default": { "enabled": false } }, "guidelines": { "type": [ "object", "null" ], "properties": { "prChecks": { "type": "array", "items": { "type": "string" } }, "mergeChecks": { "type": "array", "items": { "type": "string" } }, "allowMerge": { "type": "boolean", "default": false }, "review": { "type": "array", "items": { "type": "string" } } }, "required": [ "prChecks", "mergeChecks", "review" ] }, "createdAt": { "type": "string" }, "lastUpdatedAt": { "type": "string" } }, "required": [ "id", "url", "name", "clonePath", "createdAt", "lastUpdatedAt" ] } } }, "required": [ "repos" ] } } } } } }, "post": { "summary": "Create a new repo", "tags": [ "Repos" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "url": { "type": "string", "minLength": 1 }, "name": { "type": "string", "minLength": 1 }, "clonePath": { "type": "string" }, "defaultBranch": { "type": "string" }, "autoClone": { "type": "boolean" }, "hooks": { "type": "object", "properties": { "enabled": { "type": "boolean", "default": false } } }, "guidelines": { "type": [ "object", "null" ], "properties": { "prChecks": { "type": "array", "items": { "type": "string" } }, "mergeChecks": { "type": "array", "items": { "type": "string" } }, "allowMerge": { "type": "boolean", "default": false }, "review": { "type": "array", "items": { "type": "string" } } }, "required": [ "prChecks", "mergeChecks", "review" ] } }, "required": [ "url", "name" ] } } } }, "responses": { "201": { "description": "Repo created", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "url": { "type": "string", "minLength": 1 }, "name": { "type": "string", "minLength": 1, "maxLength": 100 }, "clonePath": { "type": "string", "minLength": 1 }, "defaultBranch": { "type": "string", "default": "main" }, "autoClone": { "type": "boolean", "default": true }, "hooks": { "type": "object", "properties": { "enabled": { "type": "boolean", "default": false } }, "default": { "enabled": false } }, "guidelines": { "type": [ "object", "null" ], "properties": { "prChecks": { "type": "array", "items": { "type": "string" } }, "mergeChecks": { "type": "array", "items": { "type": "string" } }, "allowMerge": { "type": "boolean", "default": false }, "review": { "type": "array", "items": { "type": "string" } } }, "required": [ "prChecks", "mergeChecks", "review" ] }, "createdAt": { "type": "string" }, "lastUpdatedAt": { "type": "string" } }, "required": [ "id", "url", "name", "clonePath", "createdAt", "lastUpdatedAt" ] } } } }, "400": { "description": "Validation error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } }, "required": [ "error" ] } } } }, "409": { "description": "Duplicate repo", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } }, "required": [ "error" ] } } } } } } }, "/api/schedules": { "post": { "summary": "Create a new schedule", "tags": [ "Schedules" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "key": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "name": { "type": "string", "minLength": 1 }, "description": { "type": "string" }, "cronExpression": { "type": "string" }, "intervalMs": { "type": "integer" }, "taskTemplate": { "type": "string", "minLength": 1 }, "taskType": { "type": "string" }, "tags": { "type": "array", "items": { "type": "string" } }, "priority": { "type": "integer" }, "targetAgentId": { "type": "string" }, "enabled": { "type": "boolean" }, "timezone": { "type": "string" }, "model": { "type": "string" }, "modelTier": { "type": "string", "enum": [ "smol", "regular", "smart", "ultra" ] }, "scheduleType": { "type": "string", "enum": [ "recurring", "one_time" ] }, "targetType": { "type": "string", "enum": [ "agent-task", "workflow", "script" ] }, "workflowId": { "type": "string", "format": "uuid" }, "scriptName": { "type": "string" }, "scriptArgs": { "type": "object", "additionalProperties": {} }, "delayMs": { "type": "integer" }, "runAt": { "type": "string" } }, "required": [ "name" ] } } } }, "responses": { "201": { "description": "Schedule created" }, "400": { "description": "Validation error" }, "409": { "description": "Duplicate name" } } }, "get": { "summary": "List schedules", "description": "Returns schedules with the full `taskTemplate` replaced by a short `taskTemplatePreview` by default — list views never render the full template. Pass `fields=full` to restore `taskTemplate`. Fetch the full template via `GET /api/schedules/{id}`.", "tags": [ "Schedules" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "true", "false" ] }, "required": false, "name": "enabled", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "name", "in": "query" }, { "schema": { "type": "string", "enum": [ "recurring", "one_time" ] }, "required": false, "name": "scheduleType", "in": "query" }, { "schema": { "type": "string", "enum": [ "agent-task", "workflow", "script" ] }, "required": false, "name": "targetType", "in": "query" }, { "schema": { "type": "string", "format": "uuid" }, "required": false, "name": "workflowId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "scriptName", "in": "query" }, { "schema": { "type": "string", "enum": [ "true", "false" ] }, "required": false, "name": "hideCompleted", "in": "query" }, { "schema": { "type": [ "integer", "null" ], "minimum": 0 }, "required": false, "name": "consecutiveErrorsMin", "in": "query" }, { "schema": { "type": "string", "enum": [ "failed", "succeeded" ] }, "required": false, "name": "lastRunStatus", "in": "query" }, { "schema": { "type": "string", "enum": [ "full", "slim" ] }, "required": false, "name": "fields", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "required": false, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form.", "name": "key", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "required": false, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form.", "name": "keyPrefix", "in": "query" } ], "responses": { "200": { "description": "List of schedules" } } } }, "/api/schedules/{id}/run": { "post": { "summary": "Run a schedule immediately", "tags": [ "Schedules" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Schedule run triggered" }, "400": { "description": "Schedule is disabled" }, "404": { "description": "Schedule not found" } } } }, "/api/schedules/{id}": { "get": { "summary": "Get a schedule by ID", "tags": [ "Schedules" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Schedule details" }, "404": { "description": "Schedule not found" } } }, "put": { "summary": "Update a schedule", "tags": [ "Schedules" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "key": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "name": { "type": "string" }, "description": { "type": "string" }, "cronExpression": { "type": [ "string", "null" ] }, "intervalMs": { "type": [ "integer", "null" ], "exclusiveMinimum": 0 }, "taskTemplate": { "type": "string" }, "taskType": { "type": "string" }, "tags": { "type": "array", "items": { "type": "string" } }, "priority": { "type": "integer" }, "targetAgentId": { "type": [ "string", "null" ] }, "enabled": { "type": "boolean" }, "timezone": { "type": "string" }, "model": { "type": [ "string", "null" ] }, "modelTier": { "type": [ "string", "null" ], "enum": [ "smol", "regular", "smart", "ultra", null ] }, "nextRunAt": { "type": [ "string", "null" ] }, "targetType": { "type": "string", "enum": [ "agent-task", "workflow", "script" ] }, "workflowId": { "type": [ "string", "null" ], "format": "uuid" }, "scriptName": { "type": [ "string", "null" ] }, "scriptArgs": { "type": [ "object", "null" ], "additionalProperties": {} } } } } } }, "responses": { "200": { "description": "Schedule updated" }, "400": { "description": "Validation error" }, "404": { "description": "Schedule not found" }, "409": { "description": "Duplicate name" } } }, "patch": { "summary": "Patch a schedule", "description": "Partially updates a schedule by shallow-merging provided fields over the existing row.", "tags": [ "Schedules" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "key": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "name": { "type": "string" }, "description": { "type": "string" }, "cronExpression": { "type": [ "string", "null" ] }, "intervalMs": { "type": [ "integer", "null" ], "exclusiveMinimum": 0 }, "taskTemplate": { "type": "string" }, "taskType": { "type": "string" }, "tags": { "type": "array", "items": { "type": "string" } }, "priority": { "type": "integer" }, "targetAgentId": { "type": [ "string", "null" ] }, "enabled": { "type": "boolean" }, "timezone": { "type": "string" }, "model": { "type": [ "string", "null" ] }, "modelTier": { "type": [ "string", "null" ], "enum": [ "smol", "regular", "smart", "ultra", null ] }, "nextRunAt": { "type": [ "string", "null" ] }, "targetType": { "type": "string", "enum": [ "agent-task", "workflow", "script" ] }, "workflowId": { "type": [ "string", "null" ], "format": "uuid" }, "scriptName": { "type": [ "string", "null" ] }, "scriptArgs": { "type": [ "object", "null" ], "additionalProperties": {} } } } } } }, "responses": { "200": { "description": "Schedule patched" }, "400": { "description": "Validation error" }, "404": { "description": "Schedule not found" }, "409": { "description": "Duplicate name" } } }, "delete": { "summary": "Delete a schedule", "tags": [ "Schedules" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Schedule deleted" }, "404": { "description": "Schedule not found" } } } }, "/api/script-connections": { "get": { "operationId": "script_connections_list", "summary": "List script connections", "description": "Dashboard read of OpenAPI, GraphQL, and MCP script connections with credential summaries.", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "openapi", "graphql", "mcp" ] }, "required": false, "name": "kind", "in": "query" }, { "schema": { "type": "string", "enum": [ "global", "agent", "repo" ] }, "required": false, "name": "scope", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "scopeId", "in": "query" } ], "responses": { "200": { "description": "Script connections" }, "400": { "description": "Validation error" } } }, "post": { "operationId": "script_connections_upsert", "summary": "Create or update a script connection", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "slug": { "type": "string", "minLength": 1, "maxLength": 80 }, "displayName": { "type": "string", "maxLength": 160 }, "scope": { "type": "string", "enum": [ "global", "agent", "repo" ] }, "scopeId": { "type": [ "string", "null" ], "minLength": 1, "maxLength": 255 }, "allowedHosts": { "type": "array", "items": { "type": "string", "minLength": 1 } }, "credentialBindingId": { "type": [ "string", "null" ], "format": "uuid" }, "auth": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "none" ] } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "bearer" ] }, "secret": { "type": "string", "minLength": 1 }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "template": { "type": "string", "minLength": 1 }, "hosts": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "header" ] }, "headerName": { "type": "string", "minLength": 1, "maxLength": 255 }, "secret": { "type": "string", "minLength": 1 }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "template": { "type": "string", "minLength": 1 }, "hosts": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "required": [ "type", "headerName" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "query" ] }, "paramName": { "type": "string", "minLength": 1, "maxLength": 255 }, "secret": { "type": "string", "minLength": 1 }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "template": { "type": "string", "minLength": 1 }, "hosts": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "required": [ "type", "paramName" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "oauth" ] }, "authorizationId": { "type": "string", "minLength": 1, "maxLength": 255 }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "template": { "type": "string", "minLength": 1 }, "hosts": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "required": [ "type", "authorizationId" ] } ] }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "headerTemplate": { "type": "string", "minLength": 1 }, "queryTemplate": { "type": "string", "minLength": 1 }, "authKind": { "type": "string", "enum": [ "config", "oauth" ] }, "oauthAuthorizationId": { "type": "string", "minLength": 1, "maxLength": 255 }, "enabled": { "type": "boolean" }, "kind": { "type": "string", "enum": [ "openapi" ] }, "baseUrl": { "type": "string", "format": "uri" }, "openapiSpecUrl": { "type": "string", "format": "uri" }, "openapiSpecJson": { "type": "string" }, "specSource": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "vendored" ] }, "slug": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" } }, "required": [ "kind", "slug" ] } }, "required": [ "slug", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "slug": { "type": "string", "minLength": 1, "maxLength": 80 }, "displayName": { "type": "string", "maxLength": 160 }, "scope": { "type": "string", "enum": [ "global", "agent", "repo" ] }, "scopeId": { "type": [ "string", "null" ], "minLength": 1, "maxLength": 255 }, "allowedHosts": { "type": "array", "items": { "type": "string", "minLength": 1 }, "minItems": 1 }, "credentialBindingId": { "type": [ "string", "null" ], "format": "uuid" }, "auth": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "none" ] } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "bearer" ] }, "secret": { "type": "string", "minLength": 1 }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "template": { "type": "string", "minLength": 1 }, "hosts": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "header" ] }, "headerName": { "type": "string", "minLength": 1, "maxLength": 255 }, "secret": { "type": "string", "minLength": 1 }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "template": { "type": "string", "minLength": 1 }, "hosts": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "required": [ "type", "headerName" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "query" ] }, "paramName": { "type": "string", "minLength": 1, "maxLength": 255 }, "secret": { "type": "string", "minLength": 1 }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "template": { "type": "string", "minLength": 1 }, "hosts": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "required": [ "type", "paramName" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "oauth" ] }, "authorizationId": { "type": "string", "minLength": 1, "maxLength": 255 }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "template": { "type": "string", "minLength": 1 }, "hosts": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "required": [ "type", "authorizationId" ] } ] }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "headerTemplate": { "type": "string", "minLength": 1 }, "queryTemplate": { "type": "string", "minLength": 1 }, "authKind": { "type": "string", "enum": [ "config", "oauth" ] }, "oauthAuthorizationId": { "type": "string", "minLength": 1, "maxLength": 255 }, "enabled": { "type": "boolean" }, "kind": { "type": "string", "enum": [ "graphql" ] }, "baseUrl": { "type": "string", "format": "uri" } }, "required": [ "slug", "allowedHosts", "kind", "baseUrl" ] }, { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "slug": { "type": "string", "minLength": 1, "maxLength": 80 }, "displayName": { "type": "string", "maxLength": 160 }, "scope": { "type": "string", "enum": [ "global", "agent", "repo" ] }, "scopeId": { "type": [ "string", "null" ], "minLength": 1, "maxLength": 255 }, "allowedHosts": { "type": "array", "items": { "type": "string", "minLength": 1 } }, "credentialBindingId": { "type": [ "string", "null" ], "format": "uuid" }, "auth": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "none" ] } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "bearer" ] }, "secret": { "type": "string", "minLength": 1 }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "template": { "type": "string", "minLength": 1 }, "hosts": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "header" ] }, "headerName": { "type": "string", "minLength": 1, "maxLength": 255 }, "secret": { "type": "string", "minLength": 1 }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "template": { "type": "string", "minLength": 1 }, "hosts": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "required": [ "type", "headerName" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "query" ] }, "paramName": { "type": "string", "minLength": 1, "maxLength": 255 }, "secret": { "type": "string", "minLength": 1 }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "template": { "type": "string", "minLength": 1 }, "hosts": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "required": [ "type", "paramName" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "oauth" ] }, "authorizationId": { "type": "string", "minLength": 1, "maxLength": 255 }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "template": { "type": "string", "minLength": 1 }, "hosts": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "required": [ "type", "authorizationId" ] } ] }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "headerTemplate": { "type": "string", "minLength": 1 }, "queryTemplate": { "type": "string", "minLength": 1 }, "authKind": { "type": "string", "enum": [ "config", "oauth" ] }, "oauthAuthorizationId": { "type": "string", "minLength": 1, "maxLength": 255 }, "enabled": { "type": "boolean" }, "kind": { "type": "string", "enum": [ "mcp" ] }, "mcpServerId": { "type": "string", "format": "uuid" } }, "required": [ "slug", "kind", "mcpServerId" ] } ] } } } }, "responses": { "200": { "description": "Saved script connection" }, "400": { "description": "Validation or generation error" }, "403": { "description": "Only the lead agent can manage script connections" } } } }, "/api/script-connections/{id}": { "get": { "operationId": "script_connections_get", "summary": "Get script connection detail", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Script connection detail" }, "404": { "description": "Script connection not found" } } } }, "/api/script-connections/{id}/refresh": { "post": { "operationId": "script_connections_refresh", "summary": "Refresh a script connection", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Refreshed script connection" }, "400": { "description": "Connection cannot be refreshed" }, "403": { "description": "Only the lead agent can manage script connections" }, "404": { "description": "Script connection not found" } } } }, "/api/script-connections/{id}/disable": { "post": { "operationId": "script_connections_set_enabled", "summary": "Enable or disable a script connection", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "enabled": { "type": "boolean" } }, "required": [ "enabled" ] } } } }, "responses": { "200": { "description": "Updated script connection" }, "403": { "description": "Only the lead agent can manage script connections" }, "404": { "description": "Script connection not found" } } } }, "/api/credential-bindings": { "get": { "operationId": "credential_bindings_list", "summary": "List standalone script credential bindings", "description": "Lists standalone (raw fetch()) credential bindings. Auto-managed bindings that back embedded connection auth are hidden by default; pass includeManaged=true to include them.", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "true", "false" ] }, "required": false, "name": "includeManaged", "in": "query" } ], "responses": { "200": { "description": "Credential bindings" } } }, "post": { "operationId": "credential_bindings_upsert", "summary": "Create or update a script credential binding", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "configKey": { "type": "string", "minLength": 1, "maxLength": 255 }, "allowedHosts": { "type": "array", "items": { "type": "string", "minLength": 1 }, "minItems": 1 }, "headerTemplate": { "type": "string", "minLength": 1 }, "queryTemplate": { "type": "string", "minLength": 1 }, "scope": { "type": "string", "enum": [ "global", "agent", "repo" ], "default": "global" }, "scopeId": { "type": [ "string", "null" ], "minLength": 1, "maxLength": 255 }, "active": { "type": "boolean", "default": true }, "authKind": { "type": "string", "enum": [ "config", "oauth" ], "default": "config" }, "oauthAuthorizationId": { "type": "string", "minLength": 1, "maxLength": 255 } }, "required": [ "configKey", "allowedHosts" ] } } } }, "responses": { "200": { "description": "Saved credential binding" }, "400": { "description": "Validation error" }, "403": { "description": "Only the lead agent can manage script connections" } } } }, "/api/oauth-apps": { "get": { "operationId": "oauth_apps_list", "summary": "List OAuth apps for script credential bindings", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "OAuth apps without client secrets" } } }, "post": { "operationId": "oauth_apps_upsert", "summary": "Create or update an OAuth app for script credential bindings", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 255 }, "presetId": { "type": "string", "minLength": 1 }, "provider": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^[A-Za-z0-9_-]+$" }, "clientId": { "type": "string", "minLength": 1 }, "clientSecret": { "type": "string", "minLength": 1 }, "authorizeUrl": { "type": "string", "format": "uri" }, "tokenUrl": { "type": "string", "format": "uri" }, "userinfoUrl": { "type": "string", "format": "uri" }, "revocationUrl": { "type": "string", "format": "uri" }, "scopes": { "type": "array", "items": { "type": "string", "minLength": 1 } }, "extraParams": { "type": "object", "additionalProperties": { "type": "string" } }, "tokenAuthStyle": { "type": "string", "enum": [ "body", "basic" ] }, "tokenBodyFormat": { "type": "string", "enum": [ "form", "json" ] } }, "required": [ "clientId" ] } } } }, "responses": { "200": { "description": "Saved OAuth app without client secret" }, "400": { "description": "Validation error" }, "403": { "description": "Only the lead agent can manage script connections" } } } }, "/api/oauth-presets": { "get": { "operationId": "oauth_presets_list", "summary": "List curated OAuth presets for app-creation pickers", "description": "Static curated OAuth presets (endpoints, scopes, quirks, and setup hints). Contains no secrets; client credentials are always customer-supplied.", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Curated OAuth presets" } } } }, "/api/oauth-apps/discover": { "post": { "operationId": "oauth_apps_discover", "summary": "Discover OAuth endpoints from provider metadata", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "url": { "type": "string", "format": "uri" } }, "required": [ "url" ] } } } }, "responses": { "200": { "description": "Discovered OAuth metadata" }, "400": { "description": "Discovery failed" }, "403": { "description": "Only the lead agent can manage script connections" } } } }, "/api/oauth-apps/{provider}": { "delete": { "operationId": "oauth_apps_delete", "summary": "Delete an OAuth app and its tokens", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^[A-Za-z0-9_-]+$" }, "required": true, "name": "provider", "in": "path" } ], "responses": { "200": { "description": "OAuth app deleted" }, "403": { "description": "Only the lead agent can manage script connections" }, "404": { "description": "OAuth app not found" } } } }, "/api/oauth-apps/{id}/authorize-url": { "post": { "operationId": "oauth_apps_authorize_url", "summary": "Build an OAuth authorization URL for a labeled authorization", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 255 }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "label": { "type": "string", "minLength": 1, "maxLength": 255, "default": "default" }, "finalRedirect": { "type": "string", "format": "uri" } } } } } }, "responses": { "200": { "description": "OAuth authorization URL + state" }, "403": { "description": "Only the lead agent can manage OAuth authorizations" }, "404": { "description": "OAuth app not found" } } } }, "/api/oauth-apps/{id}/authorizations": { "get": { "operationId": "oauth_app_authorizations_list", "summary": "List the labeled authorizations for an OAuth app (never token material)", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 255 }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Authorizations without token material" }, "404": { "description": "OAuth app not found" } } } }, "/api/oauth-authorizations/{id}": { "delete": { "operationId": "oauth_authorization_delete", "summary": "Revoke (best-effort) and delete a single OAuth authorization", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 255 }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Authorization revoked + deleted" }, "403": { "description": "Only the lead agent can manage OAuth authorizations" }, "404": { "description": "Authorization not found" } } } }, "/api/oauth-authorizations/{id}/refresh": { "post": { "operationId": "oauth_authorization_refresh", "summary": "Force-refresh a single OAuth authorization (never returns token values)", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 255 }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Refresh result with token status and new expiry" }, "400": { "description": "No refresh token stored" }, "403": { "description": "Only the lead agent can manage OAuth authorizations" }, "404": { "description": "Authorization not found" }, "502": { "description": "Provider token endpoint rejected the refresh" } } } }, "/api/integrations-catalog": { "get": { "operationId": "integrations_catalog_list", "summary": "Proxy integrations.sh catalog entries", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Integrations catalog entries" }, "502": { "description": "Catalog upstream unavailable" } } } }, "/api/integrations-catalog/{domain}/surface": { "get": { "operationId": "integrations_catalog_surface", "summary": "Proxy integrations.sh per-domain surface details (trimmed for the Add Connection flow)", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^[a-z0-9.-]+$/i" }, "required": true, "name": "domain", "in": "path" } ], "responses": { "200": { "description": "Trimmed integration surface details for a domain" }, "404": { "description": "No surface data for this domain" }, "502": { "description": "Surface upstream unavailable" } } } }, "/api/oauth-apps/{provider}/tokens": { "delete": { "operationId": "oauth_app_disconnect", "summary": "Disconnect an OAuth app: delete stored tokens (best-effort remote revocation when a revocation endpoint is known)", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^[A-Za-z0-9_-]+$" }, "required": true, "name": "provider", "in": "path" } ], "responses": { "200": { "description": "Disconnect result" }, "403": { "description": "Only the lead agent can manage script connections" }, "404": { "description": "OAuth app not found" } } } }, "/api/oauth-apps/{provider}/refresh": { "post": { "operationId": "oauth_app_refresh_tokens", "summary": "Force-refresh the stored OAuth tokens for a provider (never returns token values)", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^[A-Za-z0-9_-]+$" }, "required": true, "name": "provider", "in": "path" } ], "responses": { "200": { "description": "Refresh result with token status and new expiry" }, "400": { "description": "No stored tokens or provider does not support refresh" }, "403": { "description": "Only the lead agent can manage script connections" }, "404": { "description": "OAuth app not found" }, "502": { "description": "Provider token endpoint rejected the refresh" } } } }, "/api/script-runs": { "post": { "operationId": "script_runs_create", "summary": "Launch a durable script workflow run", "description": "Foundation endpoint for Script Workflows v1. In PR 1 it persists the run and returns its dashboard URL; spawning is added by the supervisor PR.", "tags": [ "Script Runs" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "source": { "type": "string", "minLength": 1 }, "args": {}, "background": { "type": "boolean", "default": true }, "idempotencyKey": { "type": "string", "minLength": 1, "maxLength": 200 }, "scriptName": { "type": "string", "minLength": 1, "maxLength": 200 }, "requestedByUserId": { "type": "string" } }, "required": [ "source" ] } } } }, "responses": { "201": { "description": "Script run created" }, "400": { "description": "Validation or label-lint failure" }, "409": { "description": "Existing idempotent run returned" }, "429": { "description": "Script run concurrency cap reached" } } }, "get": { "operationId": "script_runs_list", "summary": "List script workflow runs", "tags": [ "Script Runs" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "running", "paused", "completed", "failed", "cancelled", "aborted_limit" ] }, "required": false, "name": "status", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "agentId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "scriptName", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 500 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": [ "integer", "null" ], "minimum": 0 }, "required": false, "name": "offset", "in": "query" } ], "responses": { "200": { "description": "Paginated script run list" } } } }, "/api/script-runs/{id}": { "get": { "operationId": "script_runs_get", "summary": "Get a script workflow run with journal", "tags": [ "Script Runs" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Script run detail" }, "404": { "description": "Script run not found" } } }, "delete": { "operationId": "script_runs_cancel", "summary": "Cancel a script workflow run", "tags": [ "Script Runs" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "responses": { "204": { "description": "Script run cancelled, or already terminal" }, "404": { "description": "Script run not found" } } } }, "/api/internal/script-runs/{runId}/steps/{stepKey}": { "get": { "operationId": "script_runs_internal_step_get", "summary": "Get a script run journal step", "tags": [ "Script Runs" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "runId", "in": "path" }, { "schema": { "type": "string", "minLength": 1 }, "required": true, "name": "stepKey", "in": "path" } ], "responses": { "200": { "description": "Journal step found" }, "404": { "description": "Journal step not found" } } } }, "/api/internal/script-runs/{runId}/steps": { "post": { "operationId": "script_runs_internal_step_create", "summary": "Write a script run journal step", "tags": [ "Script Runs" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "runId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "stepKey": { "type": "string", "minLength": 1 }, "stepType": { "type": "string", "minLength": 1 }, "config": {}, "status": { "type": "string", "enum": [ "completed", "failed" ] }, "result": {}, "error": { "type": "string" }, "durationMs": { "type": "integer", "minimum": 0 } }, "required": [ "stepKey", "stepType", "status" ] } } } }, "responses": { "201": { "description": "Journal step written" }, "404": { "description": "Script run not found" } } } }, "/api/internal/script-runs/{runId}/heartbeat": { "post": { "operationId": "script_runs_internal_heartbeat", "summary": "Record a script run heartbeat", "tags": [ "Script Runs" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "runId", "in": "path" } ], "responses": { "204": { "description": "Heartbeat recorded" }, "404": { "description": "Script run not found" } } } }, "/api/internal/script-runs/{runId}/status": { "post": { "operationId": "script_runs_internal_status", "summary": "Update script run status from subprocess", "tags": [ "Script Runs" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "runId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "oneOf": [ { "type": "object", "properties": { "status": { "type": "string", "enum": [ "completed" ] }, "output": {} }, "required": [ "status" ] }, { "type": "object", "properties": { "status": { "type": "string", "enum": [ "failed" ] }, "error": { "type": "string" } }, "required": [ "status" ] }, { "type": "object", "properties": { "status": { "type": "string", "enum": [ "paused" ] } }, "required": [ "status" ] } ] } } } }, "responses": { "204": { "description": "Status updated" }, "404": { "description": "Script run not found" } } } }, "/api/internal/raw-llm": { "post": { "operationId": "script_runs_internal_raw_llm", "summary": "Execute a raw LLM call for a script workflow", "tags": [ "Script Runs" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "prompt": { "type": "string" }, "model": { "type": "string" }, "schema": { "type": "object", "additionalProperties": {} }, "fallbackPort": { "type": "string" } }, "required": [ "prompt" ] } } } }, "responses": { "200": { "description": "LLM call completed" }, "500": { "description": "LLM call failed" } } } }, "/api/internal/script-runs/{runId}/agent-task": { "post": { "operationId": "script_runs_internal_agent_task", "summary": "Create or wait for a script workflow agent task step", "tags": [ "Script Runs" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "runId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "stepKey": { "type": "string", "minLength": 1 }, "template": { "type": "string" }, "task": { "type": "string" }, "agentId": { "type": "string" }, "tags": { "type": "array", "items": { "type": "string" } }, "priority": { "type": "integer", "minimum": 0, "maximum": 100 }, "offerMode": { "type": "boolean" }, "dir": { "type": "string", "minLength": 1 }, "vcsRepo": { "type": "string", "minLength": 1 }, "model": { "type": "string", "minLength": 1 }, "parentTaskId": { "type": "string", "format": "uuid" }, "requestedByUserId": { "type": "string" }, "outputSchema": { "type": "object", "additionalProperties": {} } }, "required": [ "stepKey" ] } } } }, "responses": { "200": { "description": "Agent task completed" }, "202": { "description": "Agent task created or still running" }, "404": { "description": "Script run not found" } } } }, "/api/script-connections/{id}/mcp-call": { "post": { "summary": "Invoke a tool on an MCP script connection", "tags": [ "Script Connections" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "tool": { "type": "string", "minLength": 1 }, "arguments": { "type": "object", "additionalProperties": {} } }, "required": [ "tool" ] } } } }, "responses": { "200": { "description": "MCP call result" }, "400": { "description": "Invalid MCP connection or request" }, "403": { "description": "Not allowed to invoke this MCP connection" }, "404": { "description": "Script connection or agent not found" } } } }, "/api/session-logs": { "post": { "summary": "Store session logs", "tags": [ "Session Data" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "sessionId": { "type": "string", "minLength": 1 }, "iteration": { "type": "integer", "minimum": 1 }, "lines": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, "taskId": { "type": "string" }, "cli": { "type": "string" } }, "required": [ "sessionId", "iteration", "lines" ] } } } }, "responses": { "201": { "description": "Logs stored" }, "400": { "description": "Validation error" } } } }, "/api/tasks/{taskId}/session-logs": { "get": { "summary": "Get session logs for a task", "tags": [ "Session Data" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "taskId", "in": "path" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 1000 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "Session logs" }, "404": { "description": "Task not found" } } } }, "/api/session-costs": { "post": { "summary": "Store session cost record", "tags": [ "Session Data" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "sessionId": { "type": "string", "minLength": 1 }, "agentId": { "type": "string", "minLength": 1 }, "totalCostUsd": { "type": "number" }, "taskId": { "type": "string" }, "inputTokens": { "type": "integer" }, "outputTokens": { "type": "integer" }, "cacheReadTokens": { "type": "integer" }, "cacheWriteTokens": { "type": [ "integer", "null" ] }, "reasoningOutputTokens": { "type": "integer", "minimum": 0 }, "thinkingTokens": { "type": "integer", "minimum": 0 }, "durationMs": { "type": "integer" }, "numTurns": { "type": [ "integer", "null" ] }, "model": { "type": "string" }, "isError": { "type": "boolean" }, "provider": { "type": "string", "enum": [ "claude", "claude-managed", "codex", "pi", "opencode", "devin", "gemini" ] }, "createdAt": { "type": "integer", "minimum": 0 } }, "required": [ "sessionId", "agentId", "totalCostUsd" ] } } } }, "responses": { "201": { "description": "Cost record stored" }, "400": { "description": "Validation error" } } }, "get": { "summary": "Query session costs with filters", "tags": [ "Session Data" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "agentId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "taskId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "startDate", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "endDate", "in": "query" }, { "schema": { "type": "integer", "minimum": 1 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "Session costs" } } } }, "/api/session-costs/summary": { "get": { "summary": "Aggregated session cost summary", "tags": [ "Session Data" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "day", "agent", "both" ] }, "required": false, "name": "groupBy", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "startDate", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "endDate", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "agentId", "in": "query" } ], "responses": { "200": { "description": "Cost summary" }, "400": { "description": "Invalid groupBy" } } } }, "/api/session-costs/dashboard": { "get": { "summary": "Cost today and month-to-date for dashboard", "tags": [ "Session Data" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Dashboard cost data" } } } }, "/api/sessions": { "get": { "summary": "List recent task sessions (root tasks + chain summary)", "description": "Each item's `root` is a slim task summary by default — the full `task` text is replaced with a bounded `taskPreview` and completion/integration blobs are dropped. Pass `fields=full` to restore the full root `AgentTask`. The full root + descendant chain are on `GET /api/sessions/{rootTaskId}`.", "tags": [ "Sessions" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": [ "integer", "null" ] }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": [ "integer", "null" ] }, "required": false, "name": "offset", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "source", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "q", "in": "query" }, { "schema": { "type": "string", "minLength": 1 }, "required": false, "name": "requestedByUserId", "in": "query" }, { "schema": { "type": "string", "enum": [ "full", "slim" ] }, "required": false, "name": "fields", "in": "query" } ], "responses": { "200": { "description": "Recent sessions ordered by chain-wide last activity" }, "401": { "description": "Unauthorized" } } } }, "/api/sessions/{rootTaskId}": { "get": { "summary": "Get a session — root task + the entire descendant chain", "tags": [ "Sessions" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "rootTaskId", "in": "path" } ], "responses": { "200": { "description": "Root task + chain (ordered by createdAt)" }, "401": { "description": "Unauthorized" }, "404": { "description": "Root task not found" } } } }, "/api/skills": { "get": { "summary": "List skills with optional filters", "description": "Returns skills WITHOUT the heavy `content` (full SKILL.md) by default — list views never render it. Pass `fields=full` to include `content` (e.g. for SDK consumers that read it from the list).", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "type", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "scope", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "agentId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "enabled", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "search", "in": "query" }, { "schema": { "type": "string", "enum": [ "full", "slim" ] }, "required": false, "name": "fields", "in": "query" } ], "responses": { "200": { "description": "Skill list" } } }, "post": { "summary": "Create a new skill", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "content": { "type": "string", "minLength": 1 }, "type": { "type": "string" }, "scope": { "type": "string" }, "ownerAgentId": { "type": "string" }, "systemDefault": { "type": "boolean" } }, "required": [ "content" ] } } } }, "responses": { "201": { "description": "Skill created" }, "400": { "description": "Validation error" } } } }, "/api/skills/{id}": { "get": { "summary": "Get skill by ID", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Skill details" }, "404": { "description": "Skill not found" } } }, "put": { "summary": "Update a skill", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "additionalProperties": {} } } } }, "responses": { "200": { "description": "Skill updated" }, "403": { "description": "System-managed skills cannot be edited" }, "404": { "description": "Skill not found" } } }, "delete": { "summary": "Delete a skill", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Skill deleted" }, "403": { "description": "System-managed skills cannot be deleted" }, "404": { "description": "Skill not found" } } } }, "/api/skills/{id}/files": { "get": { "summary": "List bundled files for a skill", "description": "Returns a manifest of bundled skill files without file content.", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Skill file manifest" }, "404": { "description": "Skill not found" } } }, "post": { "summary": "Bulk upsert bundled files for a skill", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "files": { "type": "array", "items": { "type": "object", "properties": { "content": { "type": "string" }, "mimeType": { "type": "string" }, "isBinary": { "type": "boolean" }, "size": { "type": "integer", "minimum": 0 }, "path": { "type": "string", "minLength": 1 } }, "required": [ "content", "path" ] }, "maxItems": 100 } }, "required": [ "files" ] } } } }, "responses": { "200": { "description": "Skill files upserted" }, "400": { "description": "Validation error" }, "404": { "description": "Skill not found" } } } }, "/api/skills/{id}/files/{path}": { "get": { "summary": "Get a bundled skill file", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "path", "in": "path" } ], "responses": { "200": { "description": "Skill file" }, "404": { "description": "Skill or file not found" } } }, "put": { "summary": "Upsert a bundled skill file", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "path", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "content": { "type": "string" }, "mimeType": { "type": "string" }, "isBinary": { "type": "boolean" }, "size": { "type": "integer", "minimum": 0 } }, "required": [ "content" ] } } } }, "responses": { "200": { "description": "Skill file upserted" }, "400": { "description": "Validation error" }, "404": { "description": "Skill not found" } } }, "delete": { "summary": "Delete a bundled skill file", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "path", "in": "path" } ], "responses": { "200": { "description": "Skill file deleted" }, "404": { "description": "Skill or file not found" } } } }, "/api/skills/{id}/install": { "post": { "summary": "Install skill for an agent", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "agentId": { "type": "string" } }, "required": [ "agentId" ] } } } }, "responses": { "200": { "description": "Skill installed" }, "404": { "description": "Skill not found" } } } }, "/api/skills/{id}/install/{agentId}": { "delete": { "summary": "Uninstall skill for an agent", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "agentId", "in": "path" } ], "responses": { "200": { "description": "Skill uninstalled" } } } }, "/api/skills/install-remote": { "post": { "summary": "Install a remote skill from GitHub", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "sourceRepo": { "type": "string" }, "sourcePath": { "type": "string" }, "scope": { "type": "string" }, "isComplex": { "type": "boolean" } }, "required": [ "sourceRepo" ] } } } }, "responses": { "201": { "description": "Remote skill installed" }, "400": { "description": "Fetch failed" } } } }, "/api/skills/sync-remote": { "post": { "summary": "Trigger remote skill sync", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "skillId": { "type": "string" }, "force": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "Sync results" } } } }, "/api/skills/sync-filesystem": { "post": { "summary": "Sync installed skills to agent filesystem", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Filesystem sync results" } } } }, "/api/agents/{id}/skills": { "get": { "summary": "Get all skills installed for an agent", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Agent skills list" } } } }, "/api/agents/{id}/skills/signature": { "get": { "summary": "Compute a stable signature over an agent's installed skills", "description": "Returns a sha256 hash over per-row mutation fields of the agent's active+enabled skill set. Workers poll this to detect skill changes cheaply without fetching the full list.", "tags": [ "Skills" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Skills signature" } } } }, "/api/scripts/upsert": { "post": { "operationId": "scripts_upsert", "summary": "Create or update a reusable script", "description": "Explicit script upserts run a TypeScript typecheck before writing.", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 200 }, "source": { "type": "string", "minLength": 1 }, "description": { "type": "string", "default": "" }, "intent": { "type": "string", "default": "" }, "scope": { "type": "string", "enum": [ "global", "agent" ], "default": "agent" }, "fsMode": { "type": "string", "enum": [ "none", "workspace-rw" ], "default": "none" } }, "required": [ "name", "source" ] } } } }, "responses": { "200": { "description": "Script upserted" }, "400": { "description": "Validation or typecheck failure" }, "403": { "description": "Global write requires lead agent" } } } }, "/api/scripts/run": { "post": { "operationId": "scripts_run", "summary": "Run a reusable or inline script", "description": "Inline source skips typecheck and is auto-saved as a scratch script only on success.", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 200 }, "source": { "type": "string", "minLength": 1 }, "args": {}, "intent": { "type": "string", "default": "" }, "scope": { "type": "string", "enum": [ "global", "agent" ] }, "fsMode": { "type": "string", "enum": [ "none", "workspace-rw" ], "default": "none" }, "idempotencyKey": { "type": "string", "maxLength": 200 } } } } } }, "responses": { "200": { "description": "Script run completed" }, "400": { "description": "Validation error" }, "404": { "description": "Script not found" }, "501": { "description": "workspace-rw scripts are not supported in v1" } } } }, "/api/scripts/search": { "post": { "operationId": "scripts_search", "summary": "Search reusable scripts", "description": "Phase 3 search is substring-only over script name and metadata.", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "query": { "type": "string", "default": "" }, "scope": { "type": "string", "enum": [ "global", "agent" ] }, "limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 10 } } } } } }, "responses": { "200": { "description": "Matching scripts" }, "400": { "description": "Validation error" } } } }, "/api/scripts/{name}": { "delete": { "operationId": "scripts_delete", "summary": "Delete a reusable script", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 200 }, "required": true, "name": "name", "in": "path" }, { "schema": { "type": "string", "enum": [ "global", "agent" ], "default": "agent" }, "required": false, "name": "scope", "in": "query" } ], "responses": { "200": { "description": "Delete result" }, "400": { "description": "Validation error" }, "403": { "description": "Global delete requires lead agent" } } } }, "/api/scripts/{name}/types": { "get": { "operationId": "scripts_types", "summary": "Get script signature and authoring types", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "minLength": 1, "maxLength": 200 }, "required": true, "name": "name", "in": "path" }, { "schema": { "type": "string", "enum": [ "global", "agent" ] }, "required": false, "name": "scope", "in": "query" } ], "responses": { "200": { "description": "Script signature and type blobs" }, "404": { "description": "Script not found" } } } }, "/api/scripts": { "get": { "operationId": "scripts_list", "summary": "List saved scripts", "description": "Dashboard read: lean projection without source. Scratch scripts are excluded unless includeScratch=true.", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "global", "agent" ] }, "required": false, "name": "scope", "in": "query" }, { "schema": { "type": "string", "enum": [ "true", "false" ] }, "required": false, "name": "includeScratch", "in": "query" } ], "responses": { "200": { "description": "Saved scripts" }, "400": { "description": "Validation error" } } } }, "/api/scripts/type-defs": { "get": { "operationId": "scripts_type_defs", "summary": "Get script SDK and stdlib type definitions", "description": "Static .d.ts blobs for editor integration (e.g. Monaco extraLibs). Cacheable.", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "SDK and stdlib type definition blobs" } } } }, "/api/scripts/{id}": { "get": { "operationId": "scripts_get", "summary": "Get a saved script by id", "description": "Dashboard read: full record including source and parsed signature.", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Script detail" }, "404": { "description": "Script not found" } } } }, "/api/scripts/{id}/versions": { "get": { "operationId": "scripts_versions", "summary": "List versions of a saved script", "description": "Dashboard read: version history, newest first.", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Script versions" }, "404": { "description": "Script not found" } } } }, "/api/scripts/{id}/apis": { "post": { "operationId": "scripts_api_create", "summary": "Expose a script as an external HTTP API endpoint", "description": "Returns the endpoint plus the plaintext bearer token (when authMode is 'bearer').", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "authMode": { "type": "string", "enum": [ "none", "bearer" ], "default": "bearer" }, "label": { "type": "string", "maxLength": 200 }, "agentId": { "type": "string" } } } } } }, "responses": { "201": { "description": "Endpoint created" }, "400": { "description": "Validation error or script has no owning agent" }, "404": { "description": "Script not found" } } }, "get": { "operationId": "scripts_api_list", "summary": "List external API endpoints for a script", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Endpoints (without secrets)" }, "404": { "description": "Script not found" } } } }, "/api/scripts/{id}/apis/{endpointId}/secret": { "get": { "operationId": "scripts_api_reveal_secret", "summary": "Reveal an endpoint's bearer token", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "endpointId", "in": "path" } ], "responses": { "200": { "description": "Decrypted token (null when authMode is 'none')" }, "404": { "description": "Endpoint not found" } } } }, "/api/scripts/{id}/apis/{endpointId}": { "patch": { "operationId": "scripts_api_update", "summary": "Enable/disable or relabel an external API endpoint", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "endpointId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "enabled": { "type": "boolean" }, "label": { "type": [ "string", "null" ], "maxLength": 200 } } } } } }, "responses": { "200": { "description": "Updated endpoint" }, "404": { "description": "Endpoint not found" } } }, "delete": { "operationId": "scripts_api_delete", "summary": "Delete an external API endpoint", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "endpointId", "in": "path" } ], "responses": { "200": { "description": "Deleted" }, "404": { "description": "Endpoint not found" } } } }, "/api/scripts/{id}/apis/{endpointId}/rotate": { "post": { "operationId": "scripts_api_rotate", "summary": "Rotate an endpoint's bearer token", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "endpointId", "in": "path" } ], "responses": { "200": { "description": "Endpoint with new plaintext token" }, "400": { "description": "Endpoint uses 'none' auth — nothing to rotate" }, "404": { "description": "Endpoint not found" } } } }, "/api/mcp-bridge": { "post": { "summary": "Generic MCP tool proxy for the scripts SDK bridge", "tags": [ "Scripts" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "tool": { "type": "string", "minLength": 1, "maxLength": 200 }, "args": { "type": "object", "additionalProperties": {}, "default": {} } }, "required": [ "tool" ] } } } }, "responses": { "200": { "description": "Tool result" }, "400": { "description": "Invalid tool name or args" }, "403": { "description": "Tool not in SDK allowlist" }, "404": { "description": "Tool not found" } } } }, "/api/mcp-servers": { "get": { "summary": "List MCP servers with optional filters", "tags": [ "MCP Servers" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "scope", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "transport", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "ownerAgentId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "enabled", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "search", "in": "query" } ], "responses": { "200": { "description": "MCP server list" } } }, "post": { "summary": "Create a new MCP server", "tags": [ "MCP Servers" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 }, "transport": { "type": "string", "enum": [ "stdio", "http", "sse" ] }, "description": { "type": "string" }, "scope": { "type": "string" }, "ownerAgentId": { "type": "string" }, "command": { "type": "string" }, "args": { "type": "string" }, "url": { "type": "string" }, "headers": { "type": "string" }, "envConfigKeys": { "type": "string" }, "headerConfigKeys": { "type": "string" } }, "required": [ "name", "transport" ] } } } }, "responses": { "201": { "description": "MCP server created" }, "400": { "description": "Validation error" } } } }, "/api/mcp-servers/{id}": { "get": { "summary": "Get MCP server by ID", "tags": [ "MCP Servers" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "MCP server details" }, "404": { "description": "MCP server not found" } } }, "put": { "summary": "Update an MCP server", "tags": [ "MCP Servers" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "additionalProperties": {} } } } }, "responses": { "200": { "description": "MCP server updated" }, "404": { "description": "MCP server not found" } } }, "delete": { "summary": "Delete an MCP server", "tags": [ "MCP Servers" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "MCP server deleted" }, "404": { "description": "MCP server not found" } } } }, "/api/mcp-servers/{id}/install": { "post": { "summary": "Install MCP server for an agent", "tags": [ "MCP Servers" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "agentId": { "type": "string" } }, "required": [ "agentId" ] } } } }, "responses": { "200": { "description": "MCP server installed" }, "404": { "description": "MCP server not found" } } } }, "/api/mcp-servers/{id}/install/{agentId}": { "delete": { "summary": "Uninstall MCP server for an agent", "tags": [ "MCP Servers" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "agentId", "in": "path" } ], "responses": { "200": { "description": "MCP server uninstalled" } } } }, "/api/agents/{id}/mcp-servers": { "get": { "summary": "Get all MCP servers installed for an agent", "tags": [ "MCP Servers" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string" }, "required": false, "name": "resolveSecrets", "in": "query" } ], "responses": { "200": { "description": "Agent MCP servers list" } } } }, "/api/logs": { "get": { "summary": "List agent logs", "tags": [ "Stats" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "integer", "minimum": 1 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "agentId", "in": "query" } ], "responses": { "200": { "description": "Agent logs" } } } }, "/api/stats": { "get": { "summary": "Dashboard summary stats", "tags": [ "Stats" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Agent and task statistics" } } } }, "/api/metrics": { "get": { "summary": "Lightweight swarm-wide counts", "description": "Single JSON object of cheap `COUNT(*)` metrics — tasks (by status), agents (by status), workflows (total + enabled), pages, active sessions, skills. Use this instead of fetching full list payloads just to count. Powers UI footers/sidebars and MCP context.", "tags": [ "Stats" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Swarm metrics counts" } } } }, "/api/services": { "get": { "summary": "List all registered services", "tags": [ "Stats" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "status", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "agentId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "name", "in": "query" } ], "responses": { "200": { "description": "Service list" } } } }, "/api/scheduled-tasks": { "get": { "summary": "List scheduled tasks", "tags": [ "Stats" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "true", "false" ] }, "required": false, "name": "enabled", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "name", "in": "query" }, { "schema": { "type": "string", "enum": [ "recurring", "one_time" ] }, "required": false, "name": "scheduleType", "in": "query" }, { "schema": { "type": "string", "enum": [ "true", "false" ] }, "required": false, "name": "hideCompleted", "in": "query" }, { "schema": { "type": "string", "enum": [ "agent-task", "workflow", "script" ] }, "required": false, "name": "targetType", "in": "query" }, { "schema": { "type": "string", "format": "uuid" }, "required": false, "name": "workflowId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "scriptName", "in": "query" } ], "responses": { "200": { "description": "Scheduled tasks list" } } } }, "/api/concurrent-context": { "get": { "summary": "Get concurrent session context for lead awareness", "tags": [ "Stats" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Concurrent context data" } } } }, "/status": { "get": { "summary": "Identity + setup readiness + live activity for the swarm dashboard", "description": "Single source of truth consumed by the UI home page. Identity comes from SWARM_* envs; the 7 setup milestones each emit `unverified | configured | verified`; activity counts agents alive in the last 5 min and tasks created in the last 24h; agent_fs reports whether AGENT_FS_API_URL is set.", "tags": [ "Status" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Status payload", "content": { "application/json": { "schema": { "type": "object", "properties": { "identity": { "type": "object", "properties": { "name": { "type": "string" }, "logo_url": { "type": [ "string", "null" ] }, "brand_color": { "type": [ "string", "null" ] }, "is_cloud": { "type": "boolean" }, "marketing_url": { "type": [ "string", "null" ] }, "hide_cloud_promo": { "type": "boolean" }, "org_id": { "type": [ "string", "null" ] } }, "required": [ "name", "logo_url", "brand_color", "is_cloud", "marketing_url", "hide_cloud_promo", "org_id" ] }, "setup": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "enum": [ "harness", "slack", "github", "linear", "jira", "workers", "first_task" ] }, "label": { "type": "string" }, "state": { "type": "string", "enum": [ "unverified", "configured", "verified" ] }, "hint": { "type": "string" }, "action_url": { "type": "string" }, "provider": { "type": "string", "enum": [ "claude", "codex", "pi", "devin", "claude-managed", "opencode" ] }, "providers": { "type": "array", "items": { "type": "object", "properties": { "provider": { "type": "string", "enum": [ "claude", "codex", "pi", "devin", "claude-managed", "opencode" ] }, "state": { "type": "string", "enum": [ "unverified", "configured", "verified" ] }, "workers": { "type": "integer", "minimum": 0 } }, "required": [ "provider", "state", "workers" ] } } }, "required": [ "id", "label", "state" ] } }, "activity": { "type": "object", "properties": { "agents_online": { "type": "integer", "minimum": 0 }, "leads_online": { "type": "integer", "minimum": 0 }, "recent_tasks_count": { "type": "integer", "minimum": 0 } }, "required": [ "agents_online", "leads_online", "recent_tasks_count" ] }, "agent_fs": { "type": "object", "properties": { "configured": { "type": "boolean" }, "base_url": { "type": [ "string", "null" ] }, "provider_id": { "type": "string" }, "capabilities": { "type": "object", "additionalProperties": {} } }, "required": [ "configured", "base_url", "provider_id", "capabilities" ] }, "health": { "type": "string", "enum": [ "ok", "degraded", "broken" ] } }, "required": [ "identity", "setup", "activity", "agent_fs", "health" ] } } } }, "401": { "description": "Unauthorized" } } } }, "/status/test-connection": { "post": { "summary": "Live-test the harness provider's credentials", "description": "Issues a real upstream call (Anthropic /v1/models, OpenAI /v1/models, etc.) for the given provider. Updates an in-memory cache so the next GET /status reports `harness.state = 'verified'` for SWARM_VERIFY_TTL_MS (default 1h).", "tags": [ "Status" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "provider": { "type": "string", "enum": [ "claude", "codex", "pi", "devin", "claude-managed", "opencode" ] } }, "required": [ "provider" ] } } } }, "responses": { "200": { "description": "Live-test result", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "error": { "type": "string" }, "latency_ms": { "type": "integer", "minimum": 0 } }, "required": [ "ok", "latency_ms" ] } } } }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" } } } }, "/api/tasks": { "get": { "summary": "List tasks with filters", "description": "Returns tasks with the full `task` text replaced by a bounded `taskPreview` and completion/integration blobs dropped by default — list views only need the preview. Pass `fields=full` to restore the full `AgentTask`. Fetch a single task in full via `GET /api/tasks/{id}`.", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "status", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "agentId", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "scheduleId", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "required": false, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form.", "name": "key", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "required": false, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form.", "name": "keyPrefix", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "search", "in": "query" }, { "schema": { "type": "string", "enum": [ "true", "false" ] }, "required": false, "name": "includeHeartbeat", "in": "query" }, { "schema": { "type": "string", "format": "date-time" }, "required": false, "name": "createdAfter", "in": "query" }, { "schema": { "type": "string", "format": "date-time" }, "required": false, "name": "createdBefore", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "source", "in": "query" }, { "schema": { "type": "string", "minLength": 1 }, "required": false, "name": "requestedByUserId", "in": "query" }, { "schema": { "type": "string", "enum": [ "lastUpdatedAt", "createdAt" ] }, "required": false, "name": "orderBy", "in": "query" }, { "schema": { "type": [ "integer", "null" ] }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": [ "integer", "null" ] }, "required": false, "name": "offset", "in": "query" }, { "schema": { "type": "string", "enum": [ "full", "slim" ] }, "required": false, "name": "fields", "in": "query" } ], "responses": { "200": { "description": "Paginated task list" }, "400": { "description": "Validation error (e.g. unknown status token)" } } }, "post": { "summary": "Create a new task", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "task": { "type": "string", "minLength": 1 }, "agentId": { "type": "string" }, "taskType": { "type": "string" }, "tags": { "type": "array", "items": { "type": "string" } }, "priority": { "type": "integer" }, "dependsOn": { "type": "array", "items": { "type": "string" } }, "offeredTo": { "type": "string" }, "dir": { "type": "string" }, "parentTaskId": { "type": "string" }, "key": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "source": { "type": "string", "enum": [ "mcp", "slack", "api", "ui", "github", "gitlab", "agentmail", "system", "schedule", "workflow", "linear", "jira" ] }, "outputSchema": { "type": "object", "additionalProperties": {} }, "contextKey": { "type": "string" }, "requestedByUserId": { "type": "string" }, "model": { "type": "string" }, "modelTier": { "type": "string", "enum": [ "smol", "regular", "smart", "ultra" ] }, "effort": { "type": "string", "enum": [ "off", "low", "medium", "high", "xhigh", "max" ] } }, "required": [ "task" ] } } } }, "responses": { "201": { "description": "Task created" }, "400": { "description": "Validation error" } } } }, "/api/tasks/{id}/session": { "put": { "summary": "Update provider session ID and harness metadata for a task", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "anyOf": [ { "type": "object", "properties": { "claudeSessionId": { "type": "string", "minLength": 1 }, "provider": { "type": "string", "enum": [ "devin" ] }, "model": { "type": "string" }, "providerMeta": { "type": "object", "properties": { "sessionUrl": { "type": "string" }, "maxAcuLimit": { "type": "number" }, "acuCostUsd": { "type": "number" } }, "required": [ "sessionUrl" ] } }, "required": [ "claudeSessionId", "provider", "providerMeta" ] }, { "type": "object", "properties": { "claudeSessionId": { "type": "string", "minLength": 1 }, "provider": { "type": "string", "enum": [ "claude", "codex", "pi", "claude-managed", "opencode" ] }, "model": { "type": "string" }, "providerMeta": { "type": "object", "properties": {} }, "harnessVariant": { "type": "string" }, "harnessVariantMeta": { "type": "object", "additionalProperties": {} } }, "required": [ "claudeSessionId" ] } ] } } } }, "responses": { "200": { "description": "Session ID updated" }, "404": { "description": "Task not found" } } } }, "/api/tasks/{id}/cancel": { "post": { "summary": "Cancel a pending or in-progress task", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Task cancelled" }, "400": { "description": "Cannot cancel terminal task" }, "404": { "description": "Task not found" } } } }, "/api/tasks/{id}/steer": { "post": { "summary": "Deliver a steering message to a running task", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "minLength": 1 }, "mode": { "type": "string", "enum": [ "steer", "queue" ], "default": "queue" }, "onUnsupported": { "type": "string", "enum": [ "degrade", "fail" ], "default": "degrade" }, "source": { "type": "string", "enum": [ "ui", "mcp", "script", "slack", "api" ] }, "requestedByUserId": { "type": "string" } }, "required": [ "message" ] } } } }, "responses": { "200": { "description": "Steering accepted (see `outcome` for what actually happened)" }, "400": { "description": "Validation error" }, "403": { "description": "Caller cannot steer this task" }, "404": { "description": "Task not found" }, "422": { "description": "Requested mode unsupported by the target harness and onUnsupported=fail" } } } }, "/api/tasks/{id}/steering-messages": { "get": { "summary": "List steering messages for a task", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Steering messages" }, "404": { "description": "Task not found" } } } }, "/api/steering-messages": { "get": { "summary": "List pending steering messages for the current worker", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "taskId", "in": "query" } ], "responses": { "200": { "description": "Pending steering messages" }, "400": { "description": "Missing X-Agent-ID header" }, "404": { "description": "Agent not found" } } } }, "/api/steering-messages/{id}/delivered": { "post": { "summary": "Mark a steering message delivered", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "mode": { "type": "string", "enum": [ "steer", "queue" ] } }, "required": [ "mode" ] } } } }, "responses": { "200": { "description": "Steering message delivery recorded" }, "400": { "description": "Missing X-Agent-ID header or validation error" }, "403": { "description": "Steering message task is assigned to another agent" }, "404": { "description": "Agent or steering message not found" } } } }, "/api/steering-messages/{id}/handled": { "post": { "summary": "Mark a steering message handled", "description": "Optionally accepts a JSON body `{ note?: string }` — a short acceptance note describing how the steering was incorporated, persisted as `handledNote`.", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Steering message acknowledgement recorded" }, "400": { "description": "Missing X-Agent-ID header or validation error" }, "403": { "description": "Steering message task is assigned to another agent" }, "404": { "description": "Agent or steering message not found" } } } }, "/api/steering-messages/{id}/undeliverable": { "post": { "summary": "Promote an undeliverable steering message", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "reason": { "type": "string", "minLength": 1 } }, "required": [ "reason" ] } } } }, "responses": { "200": { "description": "Steering message promoted to a follow-up task" }, "400": { "description": "Missing X-Agent-ID header or validation error" }, "403": { "description": "Steering message task is assigned to another agent" }, "404": { "description": "Agent or steering message not found" } } } }, "/api/tasks/{id}": { "get": { "summary": "Get task details with logs and attachments", "description": "Returns the full `AgentTask` row decorated with `logs` (capped by `logsLimit`) and `attachments` (pointer-based artifacts stored on the task, ordered by `created_at`).", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 1000 }, "required": false, "name": "logsLimit", "in": "query" } ], "responses": { "200": { "description": "Task with logs and attachments" }, "404": { "description": "Task not found" } } } }, "/api/tasks/{id}/progress": { "post": { "summary": "Update task progress text", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "progress": { "type": "string", "minLength": 1 } }, "required": [ "progress" ] } } } }, "responses": { "200": { "description": "Progress updated" }, "404": { "description": "Task not found" } } } }, "/api/tasks/{id}/finish": { "post": { "summary": "Mark task as completed or failed (runner endpoint)", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "completed", "failed" ] }, "output": { "type": "string" }, "failureReason": { "type": "string" }, "force": { "type": "boolean" } }, "required": [ "status" ] } } } }, "responses": { "200": { "description": "Task finished" }, "400": { "description": "Invalid status" }, "403": { "description": "Not assigned to this agent" }, "404": { "description": "Task not found" }, "409": { "description": "Differing terminal result text was discarded" } } } }, "/api/paused-tasks": { "get": { "summary": "Get paused tasks for this agent", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Paused task list" } } } }, "/api/tasks/{id}/pause": { "post": { "summary": "Pause an in-progress task", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Task paused" }, "400": { "description": "Task not in_progress" }, "403": { "description": "Task belongs to another agent" }, "404": { "description": "Task not found" } } } }, "/api/tasks/{id}/resume": { "post": { "summary": "Resume a paused task", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Task resumed" }, "400": { "description": "Task not paused" }, "403": { "description": "Task belongs to another agent" }, "404": { "description": "Task not found" } } } }, "/api/tasks/{id}/supersede": { "post": { "summary": "Supersede an in-progress task (terminate + spawn resume follow-up)", "description": "Marks the original task `superseded` (terminal) and creates a fresh `taskType=\"resume\"` follow-up so a worker can pick up the work in a new provider session. Workflow-step tasks (those with `workflowRunStepId`) are carved out: the original is marked `failed` with reason `superseded_workflow_task` and no follow-up is created — the workflow engine's retry/failure policy applies.", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "reason": { "type": "string", "enum": [ "graceful_shutdown", "context_limits", "manual_supersede", "crash_recovery" ] } }, "required": [ "reason" ] } } } }, "responses": { "200": { "description": "Task superseded (or workflow-failed)" }, "400": { "description": "Task not in_progress" }, "403": { "description": "Task belongs to another agent" }, "404": { "description": "Task not found" } } } }, "/api/tasks/{id}/vcs": { "patch": { "summary": "Update VCS (PR/MR) info for a task", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "vcsProvider": { "type": "string", "enum": [ "github", "gitlab" ] }, "vcsRepo": { "type": "string" }, "vcsNumber": { "type": "integer", "exclusiveMinimum": 0 }, "vcsUrl": { "type": "string", "format": "uri" } }, "required": [ "vcsProvider", "vcsRepo", "vcsNumber", "vcsUrl" ] } } } }, "responses": { "200": { "description": "VCS info updated" }, "404": { "description": "Task not found" } } } }, "/api/tasks/{id}/title": { "patch": { "summary": "Set or clear a task's display title (session rename)", "description": "Sets a human-facing display title override on a task. The sessions UI only reads this from root tasks (session list items), but titles on child tasks are harmless. Pass `title: null` (or an empty string) to clear the override and fall back to the task prompt.", "tags": [ "Tasks" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "title": { "type": [ "string", "null" ], "maxLength": 120 } }, "required": [ "title" ] } } } }, "responses": { "200": { "description": "Title updated" }, "404": { "description": "Task not found" } } } }, "/api/task-templates": { "get": { "summary": "List task templates ('To start' bucket)", "tags": [ "Task Templates" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "category", "in": "query" }, { "schema": { "type": "string", "enum": [ "task", "workflow", "schedule" ] }, "required": false, "name": "kind", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "query", "in": "query" } ], "responses": { "200": { "description": "Task template list" }, "401": { "description": "Unauthorized" } } } }, "/api/trackers/jira/authorize": { "get": { "summary": "Redirect to Atlassian OAuth consent screen", "tags": [ "Trackers" ], "responses": { "302": { "description": "Redirect to Atlassian OAuth" }, "500": { "description": "Failed to generate authorization URL" }, "503": { "description": "Jira integration not configured" } } } }, "/api/trackers/jira/callback": { "get": { "summary": "Handle Jira OAuth callback (resolves cloudId via accessible-resources)", "tags": [ "Trackers" ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "code", "in": "query" }, { "schema": { "type": "string" }, "required": true, "name": "state", "in": "query" } ], "responses": { "200": { "description": "OAuth complete" }, "400": { "description": "Invalid state or code" }, "500": { "description": "Token exchange or accessible-resources fetch failed" } } } }, "/api/trackers/jira/status": { "get": { "summary": "Jira connection status, cloudId/siteUrl, token expiry, expected webhook URL, scope/token-config flags", "tags": [ "Trackers" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Connection status" }, "503": { "description": "Jira integration not configured" } } } }, "/api/trackers/jira/refresh": { "post": { "summary": "Force a Jira OAuth token refresh and return the updated status payload. Useful when an agent observes an expired token via tracker-status / db-query and wants to recover without restarting the server or re-running 3LO.", "tags": [ "Trackers" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Token refreshed; returns same shape as /status" }, "409": { "description": "Jira not connected (no refresh token stored)" }, "500": { "description": "Refresh failed (e.g. revoked grant, network error)" }, "503": { "description": "Jira integration not configured" } } } }, "/api/trackers/jira/webhook/{token}": { "post": { "summary": "Receive Jira webhook events (URL-token authenticated). Phase 2 stub — Phase 3 fills in dispatch.", "tags": [ "Trackers" ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "token", "in": "path" } ], "responses": { "200": { "description": "Event accepted" }, "401": { "description": "Invalid URL token" }, "503": { "description": "Jira webhook handler not configured" } } } }, "/api/trackers/jira/webhook-register": { "post": { "summary": "Register a Jira dynamic webhook (admin only)", "tags": [ "Trackers" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "jqlFilter": { "type": "string", "minLength": 1 } }, "required": [ "jqlFilter" ] } } } }, "responses": { "200": { "description": "Webhook registered" }, "400": { "description": "Invalid jqlFilter" }, "503": { "description": "Jira not connected or JIRA_WEBHOOK_TOKEN missing" } } } }, "/api/trackers/jira/webhook/{id}": { "delete": { "summary": "Delete a Jira dynamic webhook (admin only)", "tags": [ "Trackers" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "integer", "exclusiveMinimum": 0 }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Webhook deleted" }, "400": { "description": "Invalid webhook id" }, "503": { "description": "Jira not connected" } } } }, "/api/trackers/jira/disconnect": { "delete": { "summary": "Fully disconnect Jira: delete all webhooks, drop tokens, clear metadata", "tags": [ "Trackers" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Disconnected" }, "503": { "description": "Jira not configured" } } } }, "/api/trackers/linear/authorize": { "get": { "summary": "Redirect to Linear OAuth consent screen", "tags": [ "Trackers" ], "responses": { "302": { "description": "Redirect to Linear OAuth" }, "500": { "description": "Failed to generate authorization URL" }, "503": { "description": "Linear integration not configured" } } } }, "/api/trackers/linear/callback": { "get": { "summary": "Handle Linear OAuth callback", "tags": [ "Trackers" ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "code", "in": "query" }, { "schema": { "type": "string" }, "required": true, "name": "state", "in": "query" } ], "responses": { "200": { "description": "OAuth complete" }, "400": { "description": "Invalid state or code" }, "500": { "description": "Token exchange failed" } } } }, "/api/trackers/linear/status": { "get": { "summary": "Linear connection status, token expiry, workspace info, expected webhook URL", "tags": [ "Trackers" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Connection status" }, "503": { "description": "Linear integration not configured" } } } }, "/api/trackers/linear/refresh": { "post": { "summary": "Force a Linear OAuth token refresh and return the updated status payload. Useful when an agent observes an expired token and wants to recover without restarting the server or re-running OAuth.", "tags": [ "Trackers" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Token refreshed; returns same shape as /status" }, "409": { "description": "Linear not connected (no refresh token stored)" }, "500": { "description": "Refresh failed" }, "503": { "description": "Linear integration not configured" } } } }, "/api/trackers/linear/webhook": { "post": { "summary": "Handle Linear webhook events (signature-verified)", "tags": [ "Trackers" ], "responses": { "200": { "description": "Event accepted" }, "401": { "description": "Invalid signature" }, "503": { "description": "Linear integration not configured" } } } }, "/api/trackers/linear/disconnect": { "delete": { "summary": "Fully disconnect Linear: revoke OAuth grant + drop tokens", "tags": [ "Trackers" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "Disconnected" }, "503": { "description": "Linear not configured" } } } }, "/api/users": { "get": { "summary": "List all users with identities, token summaries and recent events", "tags": [ "Users" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": [ "integer", "null" ], "minimum": 0, "maximum": 50 }, "required": false, "name": "recentEvents", "in": "query" } ], "responses": { "200": { "description": "List of users" }, "401": { "description": "Unauthorized" } } }, "post": { "summary": "Create a new user (optionally with initial identity links)", "tags": [ "Users" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 }, "email": { "type": "string" }, "role": { "type": "string" }, "notes": { "type": "string" }, "emailAliases": { "type": "array", "items": { "type": "string" } }, "preferredChannel": { "type": "string" }, "timezone": { "type": "string" }, "metadata": { "type": "object", "additionalProperties": {} }, "dailyBudgetUsd": { "type": [ "number", "null" ] }, "status": { "type": "string", "enum": [ "invited", "active", "suspended" ] }, "identities": { "type": "array", "items": { "type": "object", "properties": { "kind": { "type": "string", "minLength": 1 }, "externalId": { "type": "string", "minLength": 1 } }, "required": [ "kind", "externalId" ] } } }, "required": [ "name" ] } } } }, "responses": { "200": { "description": "User created" }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" } } } }, "/api/users/unmapped": { "get": { "summary": "List unmapped external identities (kv-backed triage queue)", "tags": [ "Users" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": false, "name": "kind", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 1000 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "List of unmapped identities sorted by count DESC, lastSeenAt DESC" }, "401": { "description": "Unauthorized" } } } }, "/api/users/unmapped/{kind}/{externalId}/resolve": { "post": { "summary": "Resolve an unmapped identity — link to an existing user or create a new one", "tags": [ "Users" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "kind", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "externalId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "anyOf": [ { "type": "object", "properties": { "userId": { "type": "string", "minLength": 1 } }, "required": [ "userId" ] }, { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 }, "email": { "type": "string", "format": "email" }, "notes": { "type": "string" } }, "required": [ "name" ] } ] } } } }, "responses": { "200": { "description": "Identity linked + kv entries cleared" }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" }, "404": { "description": "Target user not found" } } } }, "/api/users/{id}": { "get": { "summary": "Get a user by ID with identities, token summaries and recent events", "tags": [ "Users" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": [ "integer", "null" ], "minimum": 0, "maximum": 200 }, "required": false, "name": "recentEvents", "in": "query" } ], "responses": { "200": { "description": "User row" }, "401": { "description": "Unauthorized" }, "404": { "description": "User not found" } } }, "patch": { "summary": "Update an existing user (profile / budget / status / email-aliases / identities)", "tags": [ "Users" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 }, "email": { "type": "string" }, "role": { "type": "string" }, "notes": { "type": "string" }, "emailAliases": { "type": "array", "items": { "type": "string" } }, "preferredChannel": { "type": "string" }, "timezone": { "type": "string" }, "metadata": { "type": [ "object", "null" ], "additionalProperties": {} }, "dailyBudgetUsd": { "type": [ "number", "null" ] }, "status": { "type": "string", "enum": [ "invited", "active", "suspended" ] }, "identities": { "type": "array", "items": { "type": "object", "properties": { "kind": { "type": "string", "minLength": 1 }, "externalId": { "type": "string", "minLength": 1 } }, "required": [ "kind", "externalId" ] } } } } } } }, "responses": { "200": { "description": "User updated" }, "400": { "description": "Validation error or empty body" }, "401": { "description": "Unauthorized" }, "404": { "description": "User not found" } } } }, "/api/users/{id}/mcp-tokens": { "post": { "summary": "Mint a one-time plaintext MCP token for a user", "description": "Returns the plaintext token exactly once. Subsequent reads only expose token summaries.", "tags": [ "Users" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "label": { "type": [ "string", "null" ] } } } } } }, "responses": { "200": { "description": "Minted token plaintext, token summary and composed user" }, "401": { "description": "Unauthorized" }, "404": { "description": "User not found" } } } }, "/api/users/{id}/mcp-tokens/{tokenId}": { "delete": { "summary": "Revoke a user's MCP token", "tags": [ "Users" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "tokenId", "in": "path" } ], "responses": { "200": { "description": "Composed user after token revocation" }, "401": { "description": "Unauthorized" }, "404": { "description": "User or token not found" } } } }, "/api/users/{id}/merge": { "post": { "summary": "Merge another user into this one — moves identities + email aliases, deletes source", "tags": [ "Users" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "sourceUserId": { "type": "string", "minLength": 1 } }, "required": [ "sourceUserId" ] } } } }, "responses": { "200": { "description": "Merged user" }, "400": { "description": "Validation error (e.g. target == source)" }, "401": { "description": "Unauthorized" }, "404": { "description": "Target or source user not found" } } } }, "/api/users/{id}/events": { "get": { "summary": "Paginated identity-event timeline for a user (DESC by createdAt)", "tags": [ "Users" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 200 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "before", "in": "query" } ], "responses": { "200": { "description": "Array of identity events" }, "401": { "description": "Unauthorized" }, "404": { "description": "User not found" } } } }, "/api/users/{id}/identities": { "post": { "summary": "Link a new (kind, externalId) identity to this user", "tags": [ "Users" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "kind": { "type": "string", "minLength": 1 }, "externalId": { "type": "string", "minLength": 1 } }, "required": [ "kind", "externalId" ] } } } }, "responses": { "200": { "description": "Updated identity list" }, "400": { "description": "Validation error or PK collision" }, "401": { "description": "Unauthorized" }, "404": { "description": "User not found" } } } }, "/api/users/{id}/identities/{kind}/{externalId}": { "delete": { "summary": "Remove a (kind, externalId) identity link from this user", "tags": [ "Users" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "kind", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "externalId", "in": "path" } ], "responses": { "200": { "description": "Updated identity list" }, "401": { "description": "Unauthorized" }, "404": { "description": "User not found" } } } }, "/api/github/webhook": { "post": { "summary": "Handle GitHub webhook events", "tags": [ "Webhooks" ], "responses": { "200": { "description": "Event processed" }, "401": { "description": "Invalid signature" }, "503": { "description": "GitHub integration not configured" } } } }, "/api/gitlab/webhook": { "post": { "summary": "Handle GitLab webhook events", "tags": [ "Webhooks" ], "responses": { "200": { "description": "Event processed" }, "401": { "description": "Invalid token" }, "503": { "description": "GitLab integration not configured" } } } }, "/api/agentmail/webhook": { "post": { "summary": "Handle AgentMail webhook events", "tags": [ "Webhooks" ], "responses": { "200": { "description": "Event received" }, "401": { "description": "Invalid signature" }, "503": { "description": "AgentMail integration not configured" } } } }, "/api/integrations/kapso/webhook": { "post": { "summary": "Handle native Kapso/WhatsApp webhook events", "tags": [ "Webhooks" ], "responses": { "200": { "description": "Event received" }, "401": { "description": "Invalid signature" }, "503": { "description": "Kapso integration not configured" } } } }, "/api/workflow-runs/{runId}/events": { "post": { "summary": "Fire a run-scoped event signal", "description": "Emits an event onto the workflow event bus with `_runId` injected. Used by wait nodes in `event` mode with `scope: 'run'`. The body's `name` is the bus event name; `payload` is forwarded as-is plus `_runId`.", "tags": [ "WorkflowEvents" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "required": true, "name": "runId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 }, "payload": { "type": "object", "additionalProperties": {} } }, "required": [ "name" ] } } } }, "responses": { "200": { "description": "Event emitted" }, "400": { "description": "Validation error" }, "404": { "description": "Workflow run not found" } } } }, "/api/workflow-events": { "post": { "summary": "Fire a global workflow event signal", "description": "Emits an event onto the workflow event bus. Wait-states with `scope: 'global'` may match. Run-scoped waits will NOT match this broadcast unless the payload carries a matching `workflowRunId`.", "tags": [ "WorkflowEvents" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 }, "payload": { "type": "object", "additionalProperties": {} } }, "required": [ "name" ] } } } }, "responses": { "200": { "description": "Event emitted" }, "400": { "description": "Validation error" } } } }, "/api/workflows": { "get": { "summary": "List all workflows", "description": "Returns workflows WITHOUT the heavy `definition` (the full DAG) by default — the list view only needs a `nodeCount`, which is included. Pass `fields=full` to restore `definition` + trigger config. Fetch the full workflow via `GET /api/workflows/{id}`.", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "true", "false" ] }, "required": false, "name": "enabled", "in": "query" }, { "schema": { "type": [ "integer", "null" ], "minimum": 0 }, "required": false, "name": "consecutiveErrorsMin", "in": "query" }, { "schema": { "type": "string", "enum": [ "running", "waiting", "completed", "failed", "skipped", "cancelled" ] }, "required": false, "name": "lastRunStatus", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "required": false, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form.", "name": "key", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "required": false, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form.", "name": "keyPrefix", "in": "query" }, { "schema": { "type": "string", "enum": [ "full", "slim" ] }, "required": false, "name": "fields", "in": "query" } ], "responses": { "200": { "description": "Workflow list" } } }, "post": { "summary": "Create a new workflow", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1 }, "key": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "description": { "type": "string" }, "definition": { "type": "object", "properties": { "nodes": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique node identifier, used in 'next' and 'inputs' mappings" }, "type": { "type": "string", "description": "Executor type: 'agent-task', 'script', 'swarm-script', 'raw-llm', 'validate', 'property-match'" }, "label": { "type": "string", "description": "Human-readable label for UI display" }, "config": { "type": "object", "additionalProperties": {}, "description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode? }. Values support {{interpolation}} from the node's inputs context. NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})." }, "next": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "type": "string" } }, { "type": "object", "additionalProperties": { "type": "string" } } ], "description": "Next node(s): string for simple chaining, string[] for fan-out to parallel nodes, or record for port-based routing ({pass: 'a', fail: 'b'})" }, "validation": { "type": "object", "properties": { "executor": { "type": "string", "default": "validate" }, "config": { "type": "object", "additionalProperties": {} }, "mustPass": { "type": "boolean", "default": false }, "retry": { "type": "object", "properties": { "maxRetries": { "type": "integer", "minimum": 0, "default": 3 }, "strategy": { "type": "string", "enum": [ "exponential", "static", "linear" ], "default": "exponential" }, "baseDelayMs": { "type": "integer", "minimum": 0, "default": 1000 }, "maxDelayMs": { "type": "integer", "minimum": 0, "default": 60000 } } } }, "required": [ "config" ] }, "retry": { "type": "object", "properties": { "maxRetries": { "type": "integer", "minimum": 0, "default": 3 }, "strategy": { "type": "string", "enum": [ "exponential", "static", "linear" ], "default": "exponential" }, "baseDelayMs": { "type": "integer", "minimum": 0, "default": 1000 }, "maxDelayMs": { "type": "integer", "minimum": 0, "default": 60000 } } }, "inputs": { "type": "object", "additionalProperties": { "type": "string" }, "description": "REQUIRED for cross-node data access. Maps local names to context paths. Without this, upstream step outputs are NOT available for interpolation — only 'trigger' and 'input' are. Example: { \"cityData\": \"generate-city\" } → use {{cityData.taskOutput.field}} in config templates. For trigger data: { \"pr\": \"trigger.pullRequest\" }." }, "inputSchema": { "type": "object", "additionalProperties": {}, "description": "JSON Schema to validate resolved inputs before execution" }, "outputSchema": { "type": "object", "additionalProperties": {}, "description": "JSON Schema to validate the executor's output (e.g. {taskId, taskOutput} for agent-task). Different from config.outputSchema which validates the agent's raw output." } }, "required": [ "id", "type", "config" ] }, "minItems": 1 }, "onNodeFailure": { "type": "string", "enum": [ "fail", "continue" ], "default": "fail", "description": "Behavior when a node's task fails or is cancelled. 'fail' (default): mark the entire run as failed. 'continue': treat the failed node as completed with error output and proceed — downstream convergence nodes receive '[FAILED: reason]' and can handle partial results." } }, "required": [ "nodes" ] }, "triggers": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "webhook" ] }, "hmacSecret": { "type": "string" }, "hmacHeader": { "type": "string", "default": "X-Hub-Signature-256", "description": "Legacy HMAC header for webhook verification. Prefer verification.header for new workflows." }, "verification": { "oneOf": [ { "type": "object", "properties": { "format": { "type": "string", "enum": [ "hmac-sha256" ] }, "header": { "type": "string", "default": "X-Hub-Signature-256", "description": "Header containing HMAC-SHA256 over the raw request body. Accepts sha256= or bare hex." } }, "required": [ "format" ] }, { "type": "object", "properties": { "format": { "type": "string", "enum": [ "timestamped-hmac-sha256" ] }, "header": { "type": "string", "minLength": 1, "description": "Header containing comma-separated timestamp/signature pairs such as t=,v1=." }, "timestampKey": { "type": "string", "default": "t", "description": "Timestamp field key in the signature header" }, "signatureKey": { "type": "string", "default": "v1", "description": "Signature field key in the signature header; multiple entries are allowed" }, "toleranceSeconds": { "type": "integer", "exclusiveMinimum": 0, "default": 300, "description": "Maximum allowed clock skew, in seconds, for replay protection" } }, "required": [ "format", "header" ] }, { "type": "object", "properties": { "format": { "type": "string", "enum": [ "token-equality" ] }, "header": { "type": "string", "minLength": 1, "description": "Header containing the shared token to compare" } }, "required": [ "format", "header" ] } ], "description": "Optional webhook verification format. Omit to keep legacy HMAC-SHA256 behavior with fallback header scanning." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "schedule" ] }, "scheduleId": { "type": "string", "format": "uuid" } }, "required": [ "type", "scheduleId" ] } ] } }, "cooldown": { "type": "object", "properties": { "hours": { "type": "number", "minimum": 0 }, "minutes": { "type": "number", "minimum": 0 }, "seconds": { "type": "number", "minimum": 0 } } }, "input": { "type": "object", "additionalProperties": { "anyOf": [ { "type": "string", "pattern": "^\\$\\{.+\\}$" }, { "type": "string", "pattern": "^secret\\..+$" }, { "type": "string" } ] } }, "triggerSchema": { "type": "object", "additionalProperties": {} }, "dir": { "type": "string", "minLength": 1 }, "vcsRepo": { "type": "string", "minLength": 1 } }, "required": [ "name", "definition" ] } } } }, "responses": { "201": { "description": "Workflow created" }, "400": { "description": "Invalid definition" } } } }, "/api/workflows/{id}": { "get": { "summary": "Get a workflow by ID", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Workflow details with auto-generated edges" }, "404": { "description": "Workflow not found" } } }, "put": { "summary": "Update a workflow", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "key": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." }, "description": { "type": "string" }, "definition": { "type": "object", "properties": { "nodes": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique node identifier, used in 'next' and 'inputs' mappings" }, "type": { "type": "string", "description": "Executor type: 'agent-task', 'script', 'swarm-script', 'raw-llm', 'validate', 'property-match'" }, "label": { "type": "string", "description": "Human-readable label for UI display" }, "config": { "type": "object", "additionalProperties": {}, "description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode? }. Values support {{interpolation}} from the node's inputs context. NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})." }, "next": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "type": "string" } }, { "type": "object", "additionalProperties": { "type": "string" } } ], "description": "Next node(s): string for simple chaining, string[] for fan-out to parallel nodes, or record for port-based routing ({pass: 'a', fail: 'b'})" }, "validation": { "type": "object", "properties": { "executor": { "type": "string", "default": "validate" }, "config": { "type": "object", "additionalProperties": {} }, "mustPass": { "type": "boolean", "default": false }, "retry": { "type": "object", "properties": { "maxRetries": { "type": "integer", "minimum": 0, "default": 3 }, "strategy": { "type": "string", "enum": [ "exponential", "static", "linear" ], "default": "exponential" }, "baseDelayMs": { "type": "integer", "minimum": 0, "default": 1000 }, "maxDelayMs": { "type": "integer", "minimum": 0, "default": 60000 } } } }, "required": [ "config" ] }, "retry": { "type": "object", "properties": { "maxRetries": { "type": "integer", "minimum": 0, "default": 3 }, "strategy": { "type": "string", "enum": [ "exponential", "static", "linear" ], "default": "exponential" }, "baseDelayMs": { "type": "integer", "minimum": 0, "default": 1000 }, "maxDelayMs": { "type": "integer", "minimum": 0, "default": 60000 } } }, "inputs": { "type": "object", "additionalProperties": { "type": "string" }, "description": "REQUIRED for cross-node data access. Maps local names to context paths. Without this, upstream step outputs are NOT available for interpolation — only 'trigger' and 'input' are. Example: { \"cityData\": \"generate-city\" } → use {{cityData.taskOutput.field}} in config templates. For trigger data: { \"pr\": \"trigger.pullRequest\" }." }, "inputSchema": { "type": "object", "additionalProperties": {}, "description": "JSON Schema to validate resolved inputs before execution" }, "outputSchema": { "type": "object", "additionalProperties": {}, "description": "JSON Schema to validate the executor's output (e.g. {taskId, taskOutput} for agent-task). Different from config.outputSchema which validates the agent's raw output." } }, "required": [ "id", "type", "config" ] }, "minItems": 1 }, "onNodeFailure": { "type": "string", "enum": [ "fail", "continue" ], "default": "fail", "description": "Behavior when a node's task fails or is cancelled. 'fail' (default): mark the entire run as failed. 'continue': treat the failed node as completed with error output and proceed — downstream convergence nodes receive '[FAILED: reason]' and can handle partial results." } }, "required": [ "nodes" ] }, "triggers": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "webhook" ] }, "hmacSecret": { "type": "string" }, "hmacHeader": { "type": "string", "default": "X-Hub-Signature-256", "description": "Legacy HMAC header for webhook verification. Prefer verification.header for new workflows." }, "verification": { "oneOf": [ { "type": "object", "properties": { "format": { "type": "string", "enum": [ "hmac-sha256" ] }, "header": { "type": "string", "default": "X-Hub-Signature-256", "description": "Header containing HMAC-SHA256 over the raw request body. Accepts sha256= or bare hex." } }, "required": [ "format" ] }, { "type": "object", "properties": { "format": { "type": "string", "enum": [ "timestamped-hmac-sha256" ] }, "header": { "type": "string", "minLength": 1, "description": "Header containing comma-separated timestamp/signature pairs such as t=,v1=." }, "timestampKey": { "type": "string", "default": "t", "description": "Timestamp field key in the signature header" }, "signatureKey": { "type": "string", "default": "v1", "description": "Signature field key in the signature header; multiple entries are allowed" }, "toleranceSeconds": { "type": "integer", "exclusiveMinimum": 0, "default": 300, "description": "Maximum allowed clock skew, in seconds, for replay protection" } }, "required": [ "format", "header" ] }, { "type": "object", "properties": { "format": { "type": "string", "enum": [ "token-equality" ] }, "header": { "type": "string", "minLength": 1, "description": "Header containing the shared token to compare" } }, "required": [ "format", "header" ] } ], "description": "Optional webhook verification format. Omit to keep legacy HMAC-SHA256 behavior with fallback header scanning." } }, "required": [ "type" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "schedule" ] }, "scheduleId": { "type": "string", "format": "uuid" } }, "required": [ "type", "scheduleId" ] } ] } }, "cooldown": { "type": [ "object", "null" ], "properties": { "hours": { "type": "number", "minimum": 0 }, "minutes": { "type": "number", "minimum": 0 }, "seconds": { "type": "number", "minimum": 0 } } }, "input": { "type": [ "object", "null" ], "additionalProperties": { "anyOf": [ { "type": "string", "pattern": "^\\$\\{.+\\}$" }, { "type": "string", "pattern": "^secret\\..+$" }, { "type": "string" } ] } }, "triggerSchema": { "type": [ "object", "null" ], "additionalProperties": {} }, "dir": { "type": [ "string", "null" ], "minLength": 1 }, "vcsRepo": { "type": [ "string", "null" ], "minLength": 1 }, "enabled": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "Workflow updated (version snapshot created)" }, "400": { "description": "Invalid definition" }, "404": { "description": "Workflow not found" } } }, "patch": { "summary": "Patch a workflow definition (create/update/delete nodes)", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "update": { "type": "array", "items": { "type": "object", "properties": { "nodeId": { "type": "string", "description": "ID of the node to update" }, "node": { "type": "object", "properties": { "type": { "type": "string", "description": "Executor type: 'agent-task', 'script', 'swarm-script', 'raw-llm', 'validate', 'property-match'" }, "label": { "type": "string", "description": "Human-readable label for UI display" }, "config": { "type": "object", "additionalProperties": {}, "description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode? }. Values support {{interpolation}} from the node's inputs context. NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})." }, "next": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "type": "string" } }, { "type": "object", "additionalProperties": { "type": "string" } } ], "description": "Next node(s): string for simple chaining, string[] for fan-out to parallel nodes, or record for port-based routing ({pass: 'a', fail: 'b'})" }, "validation": { "type": "object", "properties": { "executor": { "type": "string", "default": "validate" }, "config": { "type": "object", "additionalProperties": {} }, "mustPass": { "type": "boolean", "default": false }, "retry": { "type": "object", "properties": { "maxRetries": { "type": "integer", "minimum": 0, "default": 3 }, "strategy": { "type": "string", "enum": [ "exponential", "static", "linear" ], "default": "exponential" }, "baseDelayMs": { "type": "integer", "minimum": 0, "default": 1000 }, "maxDelayMs": { "type": "integer", "minimum": 0, "default": 60000 } } } }, "required": [ "config" ] }, "retry": { "type": "object", "properties": { "maxRetries": { "type": "integer", "minimum": 0, "default": 3 }, "strategy": { "type": "string", "enum": [ "exponential", "static", "linear" ], "default": "exponential" }, "baseDelayMs": { "type": "integer", "minimum": 0, "default": 1000 }, "maxDelayMs": { "type": "integer", "minimum": 0, "default": 60000 } } }, "inputs": { "type": "object", "additionalProperties": { "type": "string" }, "description": "REQUIRED for cross-node data access. Maps local names to context paths. Without this, upstream step outputs are NOT available for interpolation — only 'trigger' and 'input' are. Example: { \"cityData\": \"generate-city\" } → use {{cityData.taskOutput.field}} in config templates. For trigger data: { \"pr\": \"trigger.pullRequest\" }." }, "inputSchema": { "type": "object", "additionalProperties": {}, "description": "JSON Schema to validate resolved inputs before execution" }, "outputSchema": { "type": "object", "additionalProperties": {}, "description": "JSON Schema to validate the executor's output (e.g. {taskId, taskOutput} for agent-task). Different from config.outputSchema which validates the agent's raw output." } }, "description": "Partial node data to merge" } }, "required": [ "nodeId", "node" ] }, "description": "Nodes to update (partial merge)" }, "delete": { "type": "array", "items": { "type": "string" }, "description": "Node IDs to delete" }, "create": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique node identifier, used in 'next' and 'inputs' mappings" }, "type": { "type": "string", "description": "Executor type: 'agent-task', 'script', 'swarm-script', 'raw-llm', 'validate', 'property-match'" }, "label": { "type": "string", "description": "Human-readable label for UI display" }, "config": { "type": "object", "additionalProperties": {}, "description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode? }. Values support {{interpolation}} from the node's inputs context. NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})." }, "next": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "type": "string" } }, { "type": "object", "additionalProperties": { "type": "string" } } ], "description": "Next node(s): string for simple chaining, string[] for fan-out to parallel nodes, or record for port-based routing ({pass: 'a', fail: 'b'})" }, "validation": { "type": "object", "properties": { "executor": { "type": "string", "default": "validate" }, "config": { "type": "object", "additionalProperties": {} }, "mustPass": { "type": "boolean", "default": false }, "retry": { "type": "object", "properties": { "maxRetries": { "type": "integer", "minimum": 0, "default": 3 }, "strategy": { "type": "string", "enum": [ "exponential", "static", "linear" ], "default": "exponential" }, "baseDelayMs": { "type": "integer", "minimum": 0, "default": 1000 }, "maxDelayMs": { "type": "integer", "minimum": 0, "default": 60000 } } } }, "required": [ "config" ] }, "retry": { "type": "object", "properties": { "maxRetries": { "type": "integer", "minimum": 0, "default": 3 }, "strategy": { "type": "string", "enum": [ "exponential", "static", "linear" ], "default": "exponential" }, "baseDelayMs": { "type": "integer", "minimum": 0, "default": 1000 }, "maxDelayMs": { "type": "integer", "minimum": 0, "default": 60000 } } }, "inputs": { "type": "object", "additionalProperties": { "type": "string" }, "description": "REQUIRED for cross-node data access. Maps local names to context paths. Without this, upstream step outputs are NOT available for interpolation — only 'trigger' and 'input' are. Example: { \"cityData\": \"generate-city\" } → use {{cityData.taskOutput.field}} in config templates. For trigger data: { \"pr\": \"trigger.pullRequest\" }." }, "inputSchema": { "type": "object", "additionalProperties": {}, "description": "JSON Schema to validate resolved inputs before execution" }, "outputSchema": { "type": "object", "additionalProperties": {}, "description": "JSON Schema to validate the executor's output (e.g. {taskId, taskOutput} for agent-task). Different from config.outputSchema which validates the agent's raw output." } }, "required": [ "id", "type", "config" ] }, "description": "New nodes to add" }, "onNodeFailure": { "type": "string", "enum": [ "fail", "continue" ], "description": "Update the definition-level onNodeFailure behavior" }, "triggerSchema": { "type": [ "object", "null" ], "additionalProperties": {}, "description": "Optional JSON-Schema describing the expected trigger payload shape. Pass an object to set/replace; pass null to clear; omit to leave unchanged. Validator subset: type, required, properties, enum, const, items. Other JSON-Schema keywords are silently ignored." }, "key": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Non-unique asset directory namespace (for example shared/ or personal//drafts/). Runtime write boundaries normalize and validate the canonical form." } } } } } }, "responses": { "200": { "description": "Workflow patched (version snapshot created)" }, "400": { "description": "Invalid patch or resulting definition" }, "404": { "description": "Workflow not found" } } }, "delete": { "summary": "Delete a workflow", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "204": { "description": "Workflow deleted" }, "404": { "description": "Workflow not found" } } } }, "/api/workflows/{id}/nodes/{nodeId}": { "patch": { "summary": "Patch a single node in a workflow definition", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "nodeId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "type": { "type": "string", "description": "Executor type: 'agent-task', 'script', 'swarm-script', 'raw-llm', 'validate', 'property-match'" }, "label": { "type": "string", "description": "Human-readable label for UI display" }, "config": { "type": "object", "additionalProperties": {}, "description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode? }. Values support {{interpolation}} from the node's inputs context. NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})." }, "next": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "type": "string" } }, { "type": "object", "additionalProperties": { "type": "string" } } ], "description": "Next node(s): string for simple chaining, string[] for fan-out to parallel nodes, or record for port-based routing ({pass: 'a', fail: 'b'})" }, "validation": { "type": "object", "properties": { "executor": { "type": "string", "default": "validate" }, "config": { "type": "object", "additionalProperties": {} }, "mustPass": { "type": "boolean", "default": false }, "retry": { "type": "object", "properties": { "maxRetries": { "type": "integer", "minimum": 0, "default": 3 }, "strategy": { "type": "string", "enum": [ "exponential", "static", "linear" ], "default": "exponential" }, "baseDelayMs": { "type": "integer", "minimum": 0, "default": 1000 }, "maxDelayMs": { "type": "integer", "minimum": 0, "default": 60000 } } } }, "required": [ "config" ] }, "retry": { "type": "object", "properties": { "maxRetries": { "type": "integer", "minimum": 0, "default": 3 }, "strategy": { "type": "string", "enum": [ "exponential", "static", "linear" ], "default": "exponential" }, "baseDelayMs": { "type": "integer", "minimum": 0, "default": 1000 }, "maxDelayMs": { "type": "integer", "minimum": 0, "default": 60000 } } }, "inputs": { "type": "object", "additionalProperties": { "type": "string" }, "description": "REQUIRED for cross-node data access. Maps local names to context paths. Without this, upstream step outputs are NOT available for interpolation — only 'trigger' and 'input' are. Example: { \"cityData\": \"generate-city\" } → use {{cityData.taskOutput.field}} in config templates. For trigger data: { \"pr\": \"trigger.pullRequest\" }." }, "inputSchema": { "type": "object", "additionalProperties": {}, "description": "JSON Schema to validate resolved inputs before execution" }, "outputSchema": { "type": "object", "additionalProperties": {}, "description": "JSON Schema to validate the executor's output (e.g. {taskId, taskOutput} for agent-task). Different from config.outputSchema which validates the agent's raw output." } } } } } }, "responses": { "200": { "description": "Node patched (version snapshot created)" }, "400": { "description": "Invalid patch or resulting definition" }, "404": { "description": "Workflow or node not found" } } } }, "/api/workflows/{id}/trigger": { "post": { "summary": "Trigger a workflow execution", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "201": { "description": "Workflow run started (or skipped if cooldown active)" }, "400": { "description": "Workflow is disabled" }, "401": { "description": "Unauthorized" }, "404": { "description": "Workflow not found" } } } }, "/api/workflows/{id}/trigger/validate": { "post": { "summary": "Validate a payload against the workflow's triggerSchema (no run)", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Payload matches the workflow's triggerSchema (or workflow has none)" }, "400": { "description": "Payload failed validation; body matches the TriggerSchemaError contract" }, "404": { "description": "Workflow not found" } } } }, "/api/workflows/{id}/runs": { "get": { "summary": "List runs for a workflow", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "enum": [ "running", "waiting", "completed", "failed", "skipped", "cancelled" ] }, "required": false, "name": "status", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": [ "integer", "null" ], "minimum": 0 }, "required": false, "name": "offset", "in": "query" } ], "responses": { "200": { "description": "Workflow run list" } } } }, "/api/workflow-runs/{id}": { "get": { "summary": "Get a workflow run with steps (includes retry columns)", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Workflow run details with steps including retry info" }, "404": { "description": "Run not found" } } } }, "/api/workflow-runs/{id}/retry": { "post": { "summary": "Retry a failed workflow run", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Retry started" }, "400": { "description": "Cannot retry" } } } }, "/api/workflow-runs/{id}/cancel": { "post": { "summary": "Cancel a running or waiting workflow run", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "reason": { "type": "string" } } } } } }, "responses": { "200": { "description": "Run cancelled" }, "400": { "description": "Cannot cancel" } } } }, "/api/executor-types": { "get": { "summary": "List all executor types with their config and output schemas", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "responses": { "200": { "description": "List of executor types with schemas" } } } }, "/api/executor-types/{type}": { "get": { "summary": "Get a specific executor type with its schemas", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "type", "in": "path" } ], "responses": { "200": { "description": "Executor type details" }, "404": { "description": "Executor type not found" } } } }, "/api/webhooks/{workflowId}": { "post": { "summary": "Trigger workflow via webhook", "tags": [ "Webhooks" ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "workflowId", "in": "path" } ], "responses": { "201": { "description": "Webhook processed" }, "401": { "description": "Invalid signature" }, "404": { "description": "Workflow not found" } } } }, "/api/workflows/{id}/versions": { "get": { "summary": "List version history for a workflow", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Version list (newest first)" }, "404": { "description": "Workflow not found" } } } }, "/api/workflows/{id}/versions/{version}": { "get": { "summary": "Get a specific version snapshot of a workflow", "tags": [ "Workflows" ], "security": [ { "bearerAuth": [] } ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "integer", "minimum": 1 }, "required": true, "name": "version", "in": "path" } ], "responses": { "200": { "description": "Version snapshot" }, "404": { "description": "Version not found" } } } }, "/api/x/script/{endpointId}": { "post": { "operationId": "x_script_run", "summary": "Invoke an externally-exposed swarm script", "description": "Runs the script bound to this endpoint and returns a JSON envelope `{ ok, result, error, durationMs }` (HTTP 200) once execution is reached. Auth/routing failures use 401 (bad/missing bearer) and 404 (unknown or disabled endpoint). Optional `X-Swarm-Timeout-Ms` header (default 60000, clamped 1000–300000) sets the wall-clock timeout.", "tags": [ "External APIs" ], "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "endpointId", "in": "path" } ], "responses": { "200": { "description": "Script executed — see `ok` in the envelope" }, "401": { "description": "Missing or invalid bearer token" }, "404": { "description": "Endpoint not found or disabled" }, "501": { "description": "workspace-rw scripts are not supported" } } } } }, "webhooks": {} }