{ "openapi": "3.1.0", "info": { "title": "Agent Swarm API", "version": "1.113.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", "format": "uuid" }, "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/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)" }, "201": { "description": "Agent created" }, "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", 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 }, "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" ] } }, "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" ] } }, "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/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" } } } }, "/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" } } } }, "/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 user", "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 user 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 user 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/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", "format": "uuid" }, "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", "format": "uuid", "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/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" } } } }, "/@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": { "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": "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": { "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": { "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", "format": "uuid" }, "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" } ], "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": { "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" ], "format": "uuid" }, "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": { "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" ], "format": "uuid" }, "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-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", "format": "uuid" }, "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/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-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/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", "format": "uuid" }, "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" }, "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" }, "required": false, "name": "source", "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" }, "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" ] } }, "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}": { "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" } }, "required": [ "status" ] } } } }, "responses": { "200": { "description": "Task finished" }, "400": { "description": "Invalid status" }, "403": { "description": "Not assigned to this agent" }, "404": { "description": "Task not found" } } } }, "/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/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", "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 }, "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" }, "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." } } } } } }, "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" } ], "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": {} }