openapi: "3.1.0" info: title: Fabro Run API version: "0.2.0" description: HTTP API for managing Fabro workflow run executions. tags: - name: Discovery description: API discovery and health - name: Install description: First-run browser install workflow - name: Integrations description: External provider callbacks and integration endpoints - name: Auth description: Browser authentication - name: Runs description: Run management operations - name: Automations description: Server-managed automation definitions and automation-triggered runs - name: Environments description: Server-managed execution environment catalog - name: MCP Servers description: Server-managed MCP server definitions referenced by id from workflow configs - name: Sandboxes description: Provider-backed sandbox inventory - name: Sessions description: Ask Fabro sessions bound to runs - name: Human-in-the-Loop description: Questions, answers, and steering for runs - name: Run Outputs description: Files produced by runs - name: Run Internals description: Internal run details (stages, turns, context, configuration) - name: Workflows description: Workflow definitions and execution - name: Workflow Versions description: Immutable, content-addressed workflow packages - name: Usage description: Token counts and costs - name: Insights description: SQL query editor and history - name: Models description: Available LLM models - name: Completions description: Single-turn LLM completions - name: Settings description: Platform configuration - name: System description: Server runtime, maintenance, and event streaming security: - BearerAuth: [] - SessionCookie: [] paths: # ── Discovery ──────────────────────────────────────────────────────── /: get: operationId: getRoot tags: [Discovery] summary: API Discovery description: Returns discovery URLs for the API. security: [] responses: "200": description: Discovery URLs content: application/json: schema: $ref: "#/components/schemas/RootResponse" /health: get: operationId: getHealth tags: [Discovery] summary: Health Check description: Returns service health status. Used by load balancers and monitoring. security: [] responses: "200": description: Service is healthy content: application/json: schema: $ref: "#/components/schemas/HealthResponse" /install/session: get: operationId: getInstallSession tags: [Install] summary: Get install session description: > Returns the current browser-install session snapshot. Requires the one-time install token in `Authorization: Bearer`, `?token=`, or `X-Install-Token`. security: [] responses: "200": description: Current install session state content: application/json: schema: $ref: "#/components/schemas/InstallSessionResponse" "401": description: Invalid or missing install token headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /install/llm/test: post: operationId: testInstallLlmCredentials tags: [Install] summary: Validate install LLM credentials description: Validates an LLM API key without persisting it. Requires the one-time install token. security: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InstallLlmTestInput" responses: "200": description: Credentials validated successfully content: application/json: schema: $ref: "#/components/schemas/InstallLlmValidationResponse" "401": description: Invalid or missing install token headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Credential validation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /install/llm: put: operationId: putInstallLlm tags: [Install] summary: Save install LLM settings description: >- Records the LLM providers and API keys chosen during the browser install. An empty `providers` list marks the LLM step as completed and explicitly skipped. Requires the one-time install token. security: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InstallLlmProvidersInput" responses: "204": description: LLM settings recorded "401": description: Invalid or missing install token headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Invalid install input headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /install/server: put: operationId: putInstallServer tags: [Install] summary: Save install server configuration description: Records the canonical server URL confirmed by the operator. Requires the one-time install token. security: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InstallServerConfigInput" responses: "204": description: Server configuration recorded "401": description: Invalid or missing install token headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Invalid canonical URL headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /install/object-store/test: post: operationId: testInstallObjectStore tags: [Install] summary: Validate install object-store configuration description: Validates the browser-install object-store selection without persisting it. Requires the one-time install token. security: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InstallObjectStoreInput" responses: "200": description: Object-store configuration validated successfully content: application/json: schema: $ref: "#/components/schemas/InstallObjectStoreValidationResponse" "401": description: Invalid or missing install token headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Object-store validation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /install/object-store: put: operationId: putInstallObjectStore tags: [Install] summary: Save install object-store configuration description: Records the object-store mode selected during browser install. Requires the one-time install token. security: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InstallObjectStoreInput" responses: "204": description: Object-store configuration recorded "401": description: Invalid or missing install token headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Invalid install input headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /install/sandbox/test: post: operationId: testInstallSandbox tags: [Install] summary: Validate install sandbox configuration description: Validates the browser-install sandbox-provider selection without persisting it. For Daytona, performs a cheap authenticated call against the Daytona SDK to verify the API key. For Docker, returns ok without further checks. Requires the one-time install token. security: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InstallSandboxInput" responses: "200": description: Sandbox configuration validated successfully content: application/json: schema: $ref: "#/components/schemas/InstallSandboxValidationResponse" "401": description: Invalid or missing install token headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Sandbox validation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /install/sandbox: put: operationId: putInstallSandbox tags: [Install] summary: Save install sandbox configuration description: Records the sandbox provider selected during browser install. Requires the one-time install token. security: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InstallSandboxInput" responses: "204": description: Sandbox configuration recorded "401": description: Invalid or missing install token headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Invalid install input headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /install/github/token/test: post: operationId: testInstallGithubToken tags: [Install] summary: Validate install GitHub token description: Validates a GitHub personal access token without persisting it. Requires the one-time install token. security: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InstallGithubTokenTestInput" responses: "200": description: GitHub token validated successfully content: application/json: schema: $ref: "#/components/schemas/InstallGithubTokenTestResponse" "401": description: Invalid or missing install token headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: GitHub token validation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /install/github/token: put: operationId: putInstallGithubToken tags: [Install] summary: Save install GitHub token description: Records the GitHub personal access token chosen during the browser install. Requires the one-time install token. security: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InstallGithubTokenInput" responses: "204": description: GitHub token recorded "401": description: Invalid or missing install token headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Invalid install input headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /install/github/app/manifest: post: operationId: createInstallGithubAppManifest tags: [Install] summary: Build install GitHub App manifest description: Builds the GitHub App manifest and stores the temporary callback state for the browser install. Requires the one-time install token. security: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/InstallGithubAppManifestInput" responses: "200": description: GitHub App manifest ready for browser handoff content: application/json: schema: $ref: "#/components/schemas/InstallGithubAppManifestResponse" "401": description: Invalid or missing install token headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Invalid install input or missing prior steps headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /install/github/app/redirect: get: operationId: completeInstallGithubAppRedirect tags: [Install] summary: Complete install GitHub App redirect description: Manifest-conversion callback target used by GitHub during browser install. Authorized by the callback `state` query parameter rather than the install token. security: [] parameters: - name: code in: query required: true schema: type: string - name: state in: query required: true schema: type: string responses: "302": description: Browser redirected back into the install SPA "400": description: Invalid or expired GitHub App callback state headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "502": description: GitHub manifest conversion failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /install/finish: post: operationId: finishInstall tags: [Install] summary: Finalize browser install description: Persists settings, runtime secrets, and install outputs, then schedules the install-mode process to exit cleanly. Requires the one-time install token. security: [] responses: "202": description: Install persisted successfully; restart handoff in progress content: application/json: schema: $ref: "#/components/schemas/InstallFinishResponse" "401": description: Invalid or missing install token headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Install session is incomplete headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Install persistence failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/health: get: operationId: getApiHealth tags: [Discovery] summary: Health Check (API) description: > Returns service health status under the versioned API prefix. Mirrors `/health` for callers that prefer a uniform `/api/v1` base. security: [] responses: "200": description: Service is healthy content: application/json: schema: $ref: "#/components/schemas/HealthResponse" /api/v1/health/diagnostics: post: operationId: runDiagnostics tags: [Discovery] summary: Run server health diagnostics description: Probes external services and server configuration. May be slow. responses: "200": description: Diagnostics report content: application/json: schema: $ref: "#/components/schemas/DiagnosticsReport" "504": description: Diagnostics operation timed out headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/openapi.json: get: operationId: getOpenApiSpec tags: [Discovery] summary: OpenAPI Specification description: Returns the OpenAPI spec as JSON. security: [] responses: "200": description: OpenAPI specification content: application/json: schema: type: object /api/v1/webhooks/github: post: operationId: receiveGithubWebhook tags: [Integrations] summary: Receive GitHub Webhook description: Receives GitHub App webhook deliveries. Requests are authenticated by `X-Hub-Signature-256`, not API bearer auth. security: [] requestBody: required: true content: application/json: schema: type: object additionalProperties: true responses: "200": description: Webhook accepted "401": description: Missing or invalid webhook signature /api/v1/user: get: operationId: getUser tags: [Discovery] summary: Current User description: Returns info about the authenticated user. responses: "200": description: User info content: application/json: schema: $ref: "#/components/schemas/UserResponse" "401": description: Not authenticated headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" # ── Auth ───────────────────────────────────────────────────────────── /api/v1/auth/config: get: operationId: getAuthConfig tags: [Auth] summary: Retrieve auth configuration description: Returns the browser login methods enabled for this server. security: [] responses: "200": description: Enabled authentication methods content: application/json: schema: $ref: "#/components/schemas/AuthConfigResponse" /api/v1/auth/me: get: operationId: getAuthMe tags: [Auth] summary: Retrieve current browser user description: Returns the authenticated browser session user and demo-mode state. responses: "200": description: Current authenticated browser user content: application/json: schema: $ref: "#/components/schemas/AuthMeResponse" "401": description: Not authenticated headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/auth/sessions: get: operationId: listAuthSessions tags: [Auth] summary: List authenticated sessions description: Returns the current browser session and active CLI session chains for the authenticated user. responses: "200": description: Authenticated sessions known to the server content: application/json: schema: $ref: "#/components/schemas/AuthSessionsResponse" "401": description: Not authenticated headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/auth/sessions/{id}: delete: operationId: deleteAuthSession tags: [Auth] summary: Revoke an authenticated session description: Revokes an active CLI session chain. Browser sessions are not revocable in this API version. parameters: - name: id in: path required: true schema: type: string responses: "204": description: Session revoked "400": description: Malformed or non-revocable session id headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Not authenticated headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Session not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /auth/login/dev-token: post: operationId: loginDevToken tags: [Auth] summary: Login with development token description: Creates a browser session from an enabled development token. security: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/DevTokenLoginRequest" responses: "200": description: Browser session created content: application/json: schema: $ref: "#/components/schemas/DevTokenLoginResponse" "401": description: Invalid or disabled development token content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Session secret is not configured content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" # ── Sessions ────────────────────────────────────────────────────────── /api/v1/runs/{id}/sessions: parameters: - $ref: "#/components/parameters/RunId" get: operationId: listRunSessions tags: [Sessions] summary: List run sessions parameters: - name: page[limit] in: query schema: type: integer default: 20 minimum: 1 maximum: 100 - name: page[offset] in: query schema: type: integer default: 0 minimum: 0 - name: order in: query schema: type: string enum: [updated_desc, created_desc] default: updated_desc responses: "200": description: Ask Fabro sessions for the run content: application/json: schema: $ref: "#/components/schemas/PaginatedSessionList" post: operationId: createRunSession tags: [Sessions] summary: Create run session description: Creates a read-only Ask Fabro session bound to the run. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateRunSessionRequest" responses: "201": description: Session created content: application/json: schema: $ref: "#/components/schemas/RunSessionMetadata" "400": description: Invalid input headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/sessions/{id}: parameters: - name: id in: path required: true schema: $ref: "#/components/schemas/SessionId" get: operationId: getSession tags: [Sessions] summary: Get session responses: "200": description: Session detail content: application/json: schema: $ref: "#/components/schemas/SessionDetail" "404": description: Session not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/sessions/{id}/events: parameters: - name: id in: path required: true schema: $ref: "#/components/schemas/SessionId" get: operationId: listSessionEvents tags: [Sessions] summary: List session events description: >- Returns this session's events in order. Events are numbered per session from 1; `since_seq` is the first sequence number to include. parameters: - name: since_seq in: query schema: type: integer default: 1 minimum: 1 - name: limit in: query schema: type: integer default: 100 minimum: 1 maximum: 1000 responses: "200": description: The session's events content: application/json: schema: $ref: "#/components/schemas/PaginatedSessionEventList" "404": description: Session not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/sessions/{id}/attach: parameters: - name: id in: path required: true schema: $ref: "#/components/schemas/SessionId" get: operationId: attachSessionEvents tags: [Sessions] summary: Attach to session events description: >- Replays this session's events from `since_seq` (the next unseen event when omitted) as `SessionEvent` frames, then streams new ones as they are recorded. The stream remains open until the client disconnects or the server shuts down. parameters: - name: since_seq in: query schema: type: integer minimum: 1 responses: "200": description: Streamed session events content: text/event-stream: schema: type: string "404": description: Session not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/sessions/{id}/turns: parameters: - name: id in: path required: true schema: $ref: "#/components/schemas/SessionId" post: operationId: submitSessionTurn tags: [Sessions] summary: Submit a session turn description: >- Starts a streamed turn immediately. The stream carries the turn's `SessionEvent` frames, from `run.session.turn.started` to the event that ends the turn. Background turns are not supported in this API version. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/SubmitTurnRequest" responses: "200": description: Streamed session events headers: x-fabro-turn-id: description: Durable turn id accepted for this streamed turn. schema: $ref: "#/components/schemas/TurnId" content: text/event-stream: schema: type: string "400": description: Invalid input headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Session not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Session already has an active turn headers: x-request-id: $ref: "#/components/headers/XRequestId" x-fabro-active-turn-id: description: Durable id of the currently active turn. schema: $ref: "#/components/schemas/TurnId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/sessions/{id}/turns/{turnId}/interrupt: parameters: - name: id in: path required: true schema: $ref: "#/components/schemas/SessionId" - name: turnId in: path required: true schema: $ref: "#/components/schemas/TurnId" post: operationId: interruptSessionTurn tags: [Sessions] summary: Interrupt a session turn responses: "202": description: Interrupt requested content: application/json: schema: $ref: "#/components/schemas/SessionEvent" "404": description: Session not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Turn is not active for this session headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" # ── Workflow Versions ───────────────────────────────────────────────── /api/v1/workflow-versions: post: operationId: createWorkflowVersion tags: [Workflow Versions] summary: Create Workflow Version description: >- Validates and stores an immutable workflow package in content-addressed storage. Repeating the same canonical content returns the same identifier. Requires an authenticated user or a worker token with the `agent:run_tools` capability. Ordinary worker tokens cannot register versions. Registration creates no run and starts no execution. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/WorkflowVersion" responses: "201": description: Workflow version stored or already present content: application/json: schema: $ref: "#/components/schemas/CreateWorkflowVersionResponse" "400": description: Malformed JSON (`invalid_json`) headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "413": description: Request body exceeds 2 MiB (`workflow_version_too_large`) headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: >- Invalid workflow content (`workflow_version_invalid`) or an absent, invalid, or non-canonical dependency (`workflow_version_dependency_not_found`) headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Workflow version storage failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" # ── Runs ────────────────────────────────────────────────────────────── /api/v1/runs: get: operationId: listRuns tags: [Runs] summary: List Runs description: | Returns durable run summaries from the backing store, including runs persisted before the current server boot. Supports per-status filtering and sorting for both list and kanban renderings. Archived runs are hidden by default; pass `include_archived=true` (or `status=archived`) to include them. Runs in the `removing` bucket are hidden unless explicitly requested via `status=removing`. parameters: - $ref: "#/components/parameters/PageLimit" - $ref: "#/components/parameters/PageOffset" - $ref: "#/components/parameters/IncludeArchived" - $ref: "#/components/parameters/ParentRunId" - $ref: "#/components/parameters/RunStatusFilter" - $ref: "#/components/parameters/RunsSort" - $ref: "#/components/parameters/RunsSortDirection" responses: "200": description: Paginated durable run summaries content: application/json: schema: $ref: "#/components/schemas/PaginatedRunList" post: operationId: createRun tags: [Runs] summary: Create Run description: >- Creates a new workflow run in `submitted` status from an immutable workflow-version intent. Creation does not start or schedule the run. Failures return the standard error body. The endpoint responds `404` (`workflow_version_not_found`, `environment_not_found`), `422` (`run_intent_invalid`, `target_invalid`, `target_environment_unsupported`, `pull_request_environment_unsupported`, `workflow_version_unusable`, `run_compile_invalid`), `503` (`integration_unavailable`), or `500` (`workflow_version_store_error`, `credential_store_error`, `variable_store_error`, `run_persistence_failed`). requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/RunIntent" responses: "201": description: Run created content: application/json: schema: $ref: "#/components/schemas/Run" # Non-2xx statuses beyond 400 are deliberately documented in the # endpoint description instead of declared here: progenitor-generated # clients drop the HTTP status when a declared error response's body # is not valid JSON (e.g. a gateway's plain-text error), which breaks # the CLI's error display contract # (run_create_failure_shows_action_context_and_response_body). "400": description: Invalid JSON headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/archive: post: operationId: batchArchiveRuns tags: [Runs] summary: Archive Runs description: > Marks up to 250 terminal runs as archived in one fail-soft, non-transactional request. Each run is processed independently and successful items emit the same per-run archive events as `POST /api/v1/runs/{id}/archive`. A valid batch returns `200` even when some items fail; inspect `results` and `summary` for per-run outcomes. Invalid request bodies are rejected before mutating any run. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/BatchRunLifecycleRequest" responses: "200": description: Batch processed content: application/json: schema: $ref: "#/components/schemas/BatchRunLifecycleResponse" "400": description: Invalid batch request headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Not authenticated headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Request-level server error headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/delete: post: operationId: batchDeleteRuns tags: [Runs] summary: Delete Runs description: > Deletes up to 250 runs in one fail-soft, non-transactional request. Each run is processed independently. A valid batch returns `200` even when some items fail; inspect `results` and `summary` for per-run outcomes. Invalid request bodies are rejected before mutating any run. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/BatchDeleteRunsRequest" responses: "200": description: Batch processed content: application/json: schema: $ref: "#/components/schemas/BatchDeleteRunsResponse" "400": description: Invalid batch request headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Not authenticated headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Request-level server error headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/unarchive: post: operationId: batchUnarchiveRuns tags: [Runs] summary: Unarchive Runs description: > Restores up to 250 archived runs in one fail-soft, non-transactional request. Each run is processed independently and successful items emit the same per-run unarchive events as `POST /api/v1/runs/{id}/unarchive`. A valid batch returns `200` even when some items fail; inspect `results` and `summary` for per-run outcomes. Invalid request bodies are rejected before mutating any run. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/BatchRunLifecycleRequest" responses: "200": description: Batch processed content: application/json: schema: $ref: "#/components/schemas/BatchRunLifecycleResponse" "400": description: Invalid batch request headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Not authenticated headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Request-level server error headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/resolve: get: operationId: resolveRun tags: [Runs] summary: Resolve Run Selector description: Resolves a run selector to one durable run summary using server-owned selector semantics. parameters: - $ref: "#/components/parameters/RunSelector" responses: "200": description: Durable run summary content: application/json: schema: $ref: "#/components/schemas/Run" "400": description: Selector is invalid or ambiguous headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: No run matched the selector headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/preflight: post: operationId: runPreflight tags: [Runs] summary: Validate Workflow Manifest description: | Validates runtime readiness for a workflow manifest without creating a run. The workflow is checked as a run would be admitted: Petri compiles the bundle with the server's settings, run variables and model catalog, and every diagnostic carries Petri's code as its `rule` (`attractor.no_start`, `attractor.model.unknown`, `unsupported.template.unbound_input`), with Fabro's own `fabro.model.no_ready_provider` when a model node has no provider ready to run it. The checks then probe the sandbox, repository access and GitHub credentials. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/RunManifest" responses: "200": description: Preflight report content: application/json: schema: $ref: "#/components/schemas/PreflightResponse" "400": description: Invalid manifest or workflow headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/validate: post: operationId: validateRunManifest tags: [Runs] summary: Validate Workflow Manifest description: | Validates a workflow manifest without runtime readiness checks. The workflow is checked as a run would be admitted: Petri compiles the bundle with the server's settings, run variables and model catalog, and every diagnostic carries Petri's code as its `rule` (`attractor.no_start`, `attractor.model.unknown`, `unsupported.template.unbound_input`), with Fabro's own `fabro.model.no_ready_provider` when a model node has no provider ready to run it. `workflow` describes the admitted graph, or the DOT as written when Petri refused the workflow. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/RunManifest" responses: "200": description: Validation result content: application/json: schema: $ref: "#/components/schemas/ValidateResponse" "400": description: Invalid manifest or workflow headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/graph/render: post: operationId: renderWorkflowGraph tags: [Runs] summary: Render Workflow Graph description: | Validates and renders a workflow manifest as SVG without creating a run. The manifest is checked as `POST /validate` checks it; a workflow Petri refuses is not rendered. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/RenderWorkflowGraphRequest" responses: "200": description: Rendered graph image content: image/svg+xml: schema: type: string format: binary "400": description: Invalid manifest or workflow headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}: get: operationId: retrieveRun tags: [Runs] summary: Retrieve Run description: Returns the durable run summary for a run. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Durable run summary content: application/json: schema: $ref: "#/components/schemas/Run" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" patch: operationId: updateRun tags: [Runs] summary: Update Run description: Updates mutable run metadata. Title updates are allowed for all run states, including archived runs. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateRunRequest" responses: "200": description: Updated durable run summary content: application/json: schema: $ref: "#/components/schemas/Run" "400": description: Invalid title headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: operationId: deleteRun tags: [Runs] summary: Delete Run description: Deletes durable store state, local run scratch data, and the run-owned sandbox unless sandbox preservation is enabled. Active runs require `force=true`. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/ForceRunDelete" responses: "200": description: Run deleted and sandbox preservation details returned content: application/json: schema: $ref: "#/components/schemas/DeleteRunResponse" "204": description: Run deleted or already absent "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run is active and requires `force=true` headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/parent: put: operationId: linkRunParent tags: [Runs] summary: Link Run Parent description: Links a run under an orchestration parent. Parent links are mutable for all run states, including archived and terminal runs. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateRunParentRequest" responses: "200": description: Updated durable run summary content: application/json: schema: $ref: "#/components/schemas/Run" "400": description: Self-parent or cycle rejected headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Child or parent run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: operationId: unlinkRunParent tags: [Runs] summary: Unlink Run Parent description: Removes a run's orchestration parent. Already-root runs are returned unchanged. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Updated durable run summary content: application/json: schema: $ref: "#/components/schemas/Run" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/cancel: post: operationId: cancelRun tags: [Runs] summary: Cancel Run description: | Cancels a pending, runnable, or running run. Pre-execution runs are cancelled synchronously. Live runs return after the cancellation request is durably recorded and continue converging to a terminal cancelled state. Returns 409 if the run has already completed or been cancelled. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Run was cancelled synchronously before execution content: application/json: schema: $ref: "#/components/schemas/Run" "202": description: Cancellation was durably requested for a live run content: application/json: schema: $ref: "#/components/schemas/Run" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run is not running headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/steer: post: operationId: steerRun tags: [Human-in-the-Loop] summary: Steer Run description: | Send a mid-run steering message to a live agent stage of a running run: the stage `stage` names, or the run's one live agent stage. Without `interrupt`, the text is guidance for the stage's session, run as a follow-up turn once its current answer is reached. With `interrupt=true`, the stage's current model turn (the model request and the tool calls it is running) is stopped first, the session is kept, and the text is the stage's next input. The control is forwarded to the run's worker, and the worker's answer is this response: `202` with `outcome: delivered` (and the stage's label) once the worker delivered it, `409` with the refusal's code when the worker or Petri refused it, and `202` with `outcome: pending` when the worker gave no answer within the wait (5 s). A refused control is also a `run.notice` record on the run's event stream under the same code (`steer_refused`, `no_live_turn`, `no_such_stage`, `interrupt_refused`). parameters: - $ref: "#/components/parameters/RunId" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/SteerRunRequest" responses: "202": description: | Steer forwarded to the worker: delivered, or pending when the worker gave no answer within the wait. content: application/json: schema: $ref: "#/components/schemas/RunControlAcknowledgement" "400": description: Invalid request body headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: | Run is not currently steerable, or the worker refused the steer. The error's `code` says which: `run_not_steerable` (a terminal run, or one not running yet), `use_answer_endpoint` (the run is blocked on a question), `agent_not_steerable` (the active agent sessions have no live control channel), `steer_refused` (no live agent stage, or several and none named), `no_such_stage` (the named stage is not running), `no_live_turn` (with `interrupt=true`: the stage has no model turn in flight), `interrupt_refused` (with `interrupt=true`: no live agent stage, or several and none named). headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: Worker control channel unavailable headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/pair: get: operationId: getRunPairStatus tags: [Human-in-the-Loop] summary: Get Run Pair Status parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Current pair and active pairable targets content: application/json: schema: $ref: "#/components/schemas/RunPairStatusResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: operationId: startRunPair tags: [Human-in-the-Loop] summary: Start Run Pair description: Starts pairing with exactly one selected active API-mode agent target. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PairStartRequest" responses: "200": description: Pair mode installed for the selected target content: application/json: schema: $ref: "#/components/schemas/PairRecord" "400": description: Invalid request body headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run is not pairable, already paired, or selected target is not active/pairable headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: Worker control channel unavailable headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/pair/{pair_id}: get: operationId: getRunPair tags: [Human-in-the-Loop] summary: Get Run Pair parameters: - $ref: "#/components/parameters/RunId" - name: pair_id in: path required: true schema: $ref: "#/components/schemas/PairId" responses: "200": description: Pair record content: application/json: schema: $ref: "#/components/schemas/PairRecord" "404": description: Run or pair not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: operationId: endRunPair tags: [Human-in-the-Loop] summary: End Run Pair parameters: - $ref: "#/components/parameters/RunId" - name: pair_id in: path required: true schema: $ref: "#/components/schemas/PairId" responses: "200": description: Pair ended content: application/json: schema: $ref: "#/components/schemas/PairRecord" "404": description: Run or pair not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Pair is not current or active headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: Worker control channel unavailable headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/pair/{pair_id}/messages: post: operationId: sendRunPairMessage tags: [Human-in-the-Loop] summary: Send Run Pair Message parameters: - $ref: "#/components/parameters/RunId" - name: pair_id in: path required: true schema: $ref: "#/components/schemas/PairId" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PairMessageRequest" responses: "202": description: Pair message accepted by the runtime content: application/json: schema: $ref: "#/components/schemas/PairMessageRecord" "400": description: Invalid request body headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run or pair not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Pair is not current/active, target is gone, or message was rejected headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: Worker control channel unavailable headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/pair/{pair_id}/transcript: get: operationId: getRunPairTranscript tags: [Human-in-the-Loop] summary: Get Run Pair Transcript parameters: - $ref: "#/components/parameters/RunId" - name: pair_id in: path required: true schema: $ref: "#/components/schemas/PairId" - $ref: "#/components/parameters/SinceSeq" - $ref: "#/components/parameters/EventLimit" responses: "200": description: Compact transcript entries for the pair window content: application/json: schema: $ref: "#/components/schemas/PairTranscriptResponse" "400": description: Invalid query parameter headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run or pair not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/interrupt: post: operationId: interruptRun tags: [Human-in-the-Loop] summary: Interrupt Run description: | Stop the current model turn of a live agent stage (the stage `stage` names, or the run's one live agent stage) and keep its session. With `text`, the text is the stage's next input; without, the stage waits for the next steer message before starting another model turn. The control is forwarded to the run's worker, and the worker's answer is this response: `202` with `outcome: delivered` (and the stage's label) once the worker stopped the turn, `409` with the refusal's code when the worker or Petri refused it (a stage with no model turn in flight, such as an agent between turns or a human gate; a stage that is not running; no live agent stage, or several unnamed), and `202` with `outcome: pending` when the worker gave no answer within the wait (5 s). A refused interrupt is also a `run.notice` record on the run's event stream under the same code (`no_live_turn`, `no_such_stage`, `interrupt_refused`). A delivered interrupt is the stage's `control.requested` record with `$interrupt`, followed by an `attractor.turn.interrupted` progress record. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: false content: application/json: schema: $ref: "#/components/schemas/InterruptRunRequest" responses: "202": description: | Interrupt forwarded to the worker: delivered, or pending when the worker gave no answer within the wait. content: application/json: schema: $ref: "#/components/schemas/RunControlAcknowledgement" "400": description: Invalid request body headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: | Run is not currently interruptible, or the worker refused the interrupt. The error's `code` says which: `run_not_interruptible` (a terminal run, or one not running yet), `agent_not_steerable` (the active agent sessions have no live control channel), `no_live_turn` (the stage has no model turn in flight), `no_such_stage` (the named stage is not running), `interrupt_refused` (no live agent stage, or several and none named). headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: Worker control channel unavailable headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/start: post: operationId: startRun tags: [Runs] summary: Start Run description: Requests start for a submitted run. User-created runs become runnable; parent-generated child runs may become pending until approved. Provide `resume=true` to resume an interrupted run from checkpoint. Returns 409 if the run is not startable. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: false content: application/json: schema: $ref: "#/components/schemas/StartRunRequest" responses: "200": description: Run started content: application/json: schema: $ref: "#/components/schemas/Run" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run is not in submitted status headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/approve: post: operationId: approveRun tags: [Runs] summary: Approve Run description: Approves a pending run that requires pre-execution approval and makes it runnable. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Run approved content: application/json: schema: $ref: "#/components/schemas/Run" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run is not pending approval headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/deny: post: operationId: denyRun tags: [Runs] summary: Deny Run description: Denies a pending run that requires pre-execution approval and fails it with `approval_denied`. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: false content: application/json: schema: $ref: "#/components/schemas/DenyRunRequest" responses: "200": description: Run denied content: application/json: schema: $ref: "#/components/schemas/Run" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run is not pending approval headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/pause: post: operationId: pauseRun tags: [Runs] summary: Pause Run description: Pauses a running run. Returns 409 if the run is not running. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Run paused content: application/json: schema: $ref: "#/components/schemas/Run" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run is not running headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/unpause: post: operationId: unpauseRun tags: [Runs] summary: Unpause Run description: Resumes a paused run. Returns 409 if the run is not paused. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Run unpaused content: application/json: schema: $ref: "#/components/schemas/Run" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run is not paused headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/archive: post: operationId: archiveRun tags: [Runs] summary: Archive Run description: > Marks a terminal run (`succeeded`, `failed`, or `dead`) as `archived`. Archived runs are hidden from default listings and are read-only until unarchived. Idempotent on already-archived runs. Returns 409 if the run is not terminal. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Run archived (or already archived) content: application/json: schema: $ref: "#/components/schemas/Run" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run is not terminal and cannot be archived headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/retry: post: operationId: retryRun tags: [Runs] summary: Retry Run description: > Creates a new run from the terminal source run's last checkpoint and starts it. When the source failed on a stage, that stage runs again on the files of the stage before it; otherwise the new run continues from the last checkpoint as it stands. The new run records `retried_from` and `fork_source_ref`; the source run is left unchanged. Active and archived runs are not retryable. parameters: - $ref: "#/components/parameters/RunId" responses: "201": description: New retry run created and started content: application/json: schema: $ref: "#/components/schemas/Run" "400": description: The source has no checkpoint to retry from headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Source run is not retryable headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/rewind: post: operationId: rewindRun tags: [Runs] summary: Rewind Run description: > Creates a new run from a checkpoint of a terminal source run and starts it, then archives the source run and records `run.superseded_by` on it. Returns 207 when the new run was created but the source archive step failed. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: false content: application/json: schema: $ref: "#/components/schemas/RewindRequest" responses: "200": description: Source archived and new run created content: application/json: schema: $ref: "#/components/schemas/RewindResponse" "207": description: New run created but source archive failed content: application/json: schema: $ref: "#/components/schemas/RewindResponse" "400": description: Invalid rewind target headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Source run is archived or is not terminal headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/fork: post: operationId: forkRun tags: [Runs] summary: Fork Run description: > Creates a new run from a checkpoint of the source run and starts it. The new run holds the source's records up to the checkpoint's position and continues from there in a fresh workspace restored to the checkpoint's commit. The source run is left untouched. A checkpoint inside a parallel branch cannot be forked at; fork at the parallel stage instead. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: false content: application/json: schema: $ref: "#/components/schemas/ForkRequest" responses: "200": description: New run created and started content: application/json: schema: $ref: "#/components/schemas/ForkResponse" "400": description: Invalid fork target headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Source run is archived headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/timeline: get: operationId: getRunTimeline tags: [Runs] summary: Get Run Timeline description: > Returns the run's checkpoints in the order they were recorded, each at its Petri position with the commit it made and the stage it belongs to, and where the run was forked from when it is a fork. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Run checkpoint timeline content: application/json: schema: $ref: "#/components/schemas/RunTimelineResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/unarchive: post: operationId: unarchiveRun tags: [Runs] summary: Unarchive Run description: > Restores an archived run to its prior terminal status. Idempotent on runs that are terminal but not archived (returns the current status without emitting an event). Returns 409 if the run is active. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Run unarchived (or already not archived) content: application/json: schema: $ref: "#/components/schemas/Run" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run is active and cannot be unarchived headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/graph: get: operationId: retrieveRunGraph tags: [Runs] summary: Render SVG description: Renders the workflow graph as an SVG image using Graphviz. parameters: - $ref: "#/components/parameters/RunId" - name: direction in: query required: false description: Optional Graphviz rank direction override for the rendered graph. schema: type: string enum: - LR - TB - BT - RL responses: "200": description: SVG image of the workflow graph content: image/svg+xml: schema: type: string "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/graph/source: get: operationId: retrieveRunGraphSource tags: [Runs] summary: Retrieve Graphviz DOT source description: Returns the raw Graphviz DOT source for the workflow graph (the contents of the workflow's `.fabro` file). parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Graphviz DOT source content: text/vnd.graphviz: schema: type: string "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/state: get: operationId: getRunState tags: [Run Internals] summary: Get Run State description: Returns the internal event-sourced run projection. This is not a stable public contract. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Current run projection content: application/json: schema: $ref: "#/components/schemas/RunProjection" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/logs: get: operationId: getRunLogs tags: [Run Internals] summary: Get Run Logs description: Returns the worker tracing log for a run when it is available. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Per-run worker tracing log content: text/plain; charset=utf-8: schema: type: string "404": description: Run not found, or no run log has been written yet headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/pull_request: post: operationId: createRunPullRequest tags: [Runs] summary: Create Run Pull Request description: | Durably requests creation of a pull request for a completed run. The server generates the pull request content and creates the GitHub pull request after this request returns. Poll the URL in the Location response header until the creation succeeds or fails. If a creation is already pending for the run, the response returns that creation unchanged; any different `model` or `force` values in the new request are ignored. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateRunPullRequestRequest" responses: "202": description: Pull request creation was durably accepted headers: Location: description: URL for the latest pull request creation on this run. schema: type: string format: uri-reference Retry-After: description: Suggested number of seconds before polling the creation status. schema: type: integer minimum: 0 content: application/json: schema: $ref: "#/components/schemas/PullRequestCreation" "400": description: Pull request creation does not apply to this run headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: >- Pull request already exists for this run. Clients can GET /runs/{id}/pull_request to retrieve the stored record. headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: GitHub integration is unavailable on the server headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: operationId: linkRunPullRequest tags: [Runs] summary: Link Run Pull Request description: Links or replaces the GitHub pull request association for a run without modifying the remote pull request. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/LinkRunPullRequestRequest" responses: "200": description: Pull request linked content: application/json: schema: $ref: "#/components/schemas/PullRequestLink" "400": description: Pull request link request is invalid headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: operationId: unlinkRunPullRequest tags: [Runs] summary: Unlink Run Pull Request description: Removes Fabro's stored pull request association for a run without modifying the remote pull request. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Pull request unlinked content: application/json: schema: $ref: "#/components/schemas/PullRequestLink" "404": description: Run or stored pull request record not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" get: operationId: getRunPullRequest tags: [Runs] summary: Get Run Pull Request description: Returns the stored pull request record for a run plus live GitHub details when available. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Pull request detail content: application/json: schema: $ref: "#/components/schemas/PullRequestResponse" "404": description: Run or stored pull request record not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/pull_request/creation: get: operationId: getRunPullRequestCreation tags: [Runs] summary: Get Run Pull Request Creation description: Returns the latest explicit pull request creation requested for this run. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Latest pull request creation state content: application/json: schema: $ref: "#/components/schemas/PullRequestCreation" "404": description: Run or pull request creation not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/pull_request/merge: post: operationId: mergeRunPullRequest tags: [Runs] summary: Merge Run Pull Request description: Merges the stored pull request for a run on GitHub. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/MergeRunPullRequestRequest" responses: "200": description: Pull request merged content: application/json: schema: $ref: "#/components/schemas/MergeRunPullRequestResponse" "400": description: Pull request merge does not apply to this run headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run or stored pull request record not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "502": description: GitHub rejected the merge request headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: GitHub integration is unavailable on the server headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/pull_request/close: post: operationId: closeRunPullRequest tags: [Runs] summary: Close Run Pull Request description: Closes the stored pull request for a run on GitHub. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Pull request closed content: application/json: schema: $ref: "#/components/schemas/CloseRunPullRequestResponse" "400": description: Pull request close does not apply to this run headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run or stored pull request record not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "502": description: GitHub rejected the close request headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: GitHub integration is unavailable on the server headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/events: get: operationId: listRunEvents tags: [Run Internals] summary: List Run Events description: | Returns one page of the run's stream (`PaginatedRunStreamList`): one ordered delivery of Petri's own `RunEvent`s and Fabro's platform records in the `RunStreamItem` envelope, in `stream_seq` order. The cursor is `after`: the last `stream_seq` the client saw, exclusive; the first page is `after=0`. A client that reconnects resumes from its last `stream_seq` and deduplicates by each item's `id`; every item is delivered once, in order, with no gap. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/EventLimit" - $ref: "#/components/parameters/StreamAfter" responses: "200": description: One page of the run's stream content: application/json: schema: $ref: "#/components/schemas/PaginatedRunStreamList" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/attach: get: operationId: attachRunEvents tags: [Run Internals] summary: Attach Run Events description: | Opens an ordered server-sent event stream of the run's stream, replaying committed items and continuing with live ones while the run remains active. Each `data:` frame is one `RunStreamItem`. The stream starts after `after` (the last `stream_seq` the client saw; `0` replays the whole run; the next unseen item when omitted). It ends once the run is no longer active and every committed item has been sent. A reconnecting client passes its last `stream_seq` as `after` and deduplicates by `id`. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/StreamAfter" responses: "200": description: Server-sent event stream content: text/event-stream: schema: type: string "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/blobs: post: operationId: writeRunBlob tags: [Run Internals] summary: Write Run Blob description: Writes an opaque binary blob and returns its content-addressed blob hash. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: true content: application/octet-stream: schema: type: string format: binary responses: "200": description: Blob written content: application/json: schema: $ref: "#/components/schemas/WriteBlobResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/blobs/{blobHash}: get: operationId: readRunBlob tags: [Run Internals] summary: Read Run Blob description: Reads a previously stored blob by hash. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/BlobHash" responses: "200": description: Blob contents content: application/octet-stream: schema: type: string format: binary "404": description: Run or blob not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" # ── Petri run store (worker) ────────────────────────────────────────── # # The Petri run store over HTTP: what a run's worker process uses to reach # the run's Petri records in the server's database. Every endpoint is # worker-scoped: the worker token's run must be the path's run. `id` is # the Petri run key, which is the Fabro run id. Errors carry a # machine-readable `code`; `petri_run_leased` carries the holding owner # under `meta.owner`, and `petri_record_conflict` carries the refused # position under `meta.log` and `meta.seq`. /api/v1/runs/{id}/petri/open: post: operationId: openPetriRun tags: [Run Internals] summary: Open Petri Run description: | Opens the run in the Petri run store for the worker. `create` inserts the run and takes its writer lease for `owner`; `write` takes the lease of an existing run; `read` takes no lease. The lease is idempotent per owner: a retry by the owner that holds it gets the same lease. Another live owner is refused with `petri_run_leased`. The lease ends when the worker releases it, when the server observes the worker exit, or by operator release, never by timeout. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PetriOpenRequest" responses: "200": description: Run opened content: application/json: schema: $ref: "#/components/schemas/PetriOpenResponse" "404": description: Run not in the store (`petri_run_not_found`) headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: | The run exists (`petri_run_exists`, on `create`) or another live owner holds its lease (`petri_run_leased`, with the holder under `meta.owner`). headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/petri/release: post: operationId: releasePetriRun tags: [Run Internals] summary: Release Petri Run description: | Ends the worker's writer lease on the run when `owner` still holds it: what a worker sends when it drops its store handle. A lease that already moved to another owner is left alone. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PetriReleaseRequest" responses: "204": description: Lease released, or not held by this owner /api/v1/runs/{id}/petri/logs/{log}/records: get: operationId: listPetriRecords tags: [Run Internals] summary: List Petri Records description: Every record of one log of the run, in `seq` order, unchanged. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/PetriLog" responses: "200": description: The log's records content: application/json: schema: $ref: "#/components/schemas/PetriRecordList" "404": description: Run not in the store (`petri_run_not_found`) headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: operationId: appendPetriRecords tags: [Run Internals] summary: Append Petri Records description: | Appends one batch of records to one log at the sequences they carry, durably, in one transaction. A record equal to the one already stored at its `seq` is accepted without a second append, so a batch whose reply was lost is safe to resend. A different record at a taken `seq`, or a `seq` past the log's end, is refused with `petri_record_conflict` and the batch stores nothing. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/PetriLog" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PetriAppendRequest" responses: "204": description: Records durable "404": description: Run not in the store (`petri_run_not_found`) headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: | A record conflicts with the log (`petri_record_conflict`, with the position under `meta.log` and `meta.seq`), or `owner` no longer holds the run's lease (`petri_stale_owner`). headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/petri/blobs: post: operationId: writePetriBlob tags: [Run Internals] summary: Write Petri Blob description: | Stores a blob by content for the run's owner and returns its SHA-256 digest, the same content address Fabro's blob store uses. Idempotent by construction. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/PetriOwner" requestBody: required: true content: application/octet-stream: schema: type: string format: binary responses: "200": description: Blob stored content: application/json: schema: $ref: "#/components/schemas/WriteBlobResponse" "404": description: Run not in the store (`petri_run_not_found`) headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: "`owner` no longer holds the run's lease (`petri_stale_owner`)" headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/petri/blobs/{blobHash}: get: operationId: readPetriBlob tags: [Run Internals] summary: Read Petri Blob description: The blob with this digest, if the store holds one. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/BlobHash" responses: "200": description: Blob contents content: application/octet-stream: schema: type: string format: binary "404": description: Run not in the store (`petri_run_not_found`) or no such blob (`petri_blob_not_found`) headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/petri/platform-records: get: operationId: listPetriPlatformRecords tags: [Run Internals] summary: List Petri Platform Records description: | The run's platform records (Fabro's own facts about a Petri run: a checkpoint commit, a pull request, a notification), in `seq` order, optionally of one kind. What a run's worker reads to find an effect it already performed before performing it again. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/PetriPlatformRecordKind" responses: "200": description: The run's platform records content: application/json: schema: $ref: "#/components/schemas/PetriPlatformRecordList" post: operationId: appendPetriPlatformRecord tags: [Run Internals] summary: Append Petri Platform Record description: | Stores one platform record at the run's next `seq`, tied to the Petri stage named by `execution` and `firing` when it belongs to one. The record is the JSON of a Fabro platform record, tagged by `kind`. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PetriPlatformRecordAppendRequest" responses: "200": description: The record as stored content: application/json: schema: $ref: "#/components/schemas/PetriPlatformRecord" "400": description: The record is not a platform record headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/stages/{stageId}/logs/output: get: operationId: getRunStageCommandLog tags: [Run Internals] summary: Tail Command Log description: Returns a byte-offset slice of a command stage output log. Bytes are base64-encoded and are not snapped to UTF-8 boundaries. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/StageId" - $ref: "#/components/parameters/CommandLogOffset" - $ref: "#/components/parameters/CommandLogLimit" responses: "200": description: Command log bytes. content: application/json: schema: $ref: "#/components/schemas/CommandLogResponse" "400": description: Invalid stage, offset, or limit. headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run or stage not found. headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/questions: get: operationId: listRunQuestions tags: [Human-in-the-Loop] summary: List Run Questions description: Returns pending human-in-the-loop questions for a run. Questions are generated when the workflow needs user input to proceed. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/PageLimit" - $ref: "#/components/parameters/PageOffset" responses: "200": description: Array of pending questions content: application/json: schema: $ref: "#/components/schemas/PaginatedApiQuestionList" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/questions/{qid}/answer: post: operationId: submitRunAnswer tags: [Human-in-the-Loop] summary: Submit Run Answer description: Submits an answer to a pending question. The answer can be freeform text or a selected option key, depending on the question type. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/QuestionId" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/SubmitAnswerRequest" responses: "204": description: Answer accepted "400": description: Invalid option key headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Question no longer exists or already answered headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/stages: get: operationId: listRunStages tags: [Run Internals] summary: List Run Stages description: Returns the ordered list of stages in a run's workflow graph with their current status and timing. Stages are bounded by the workflow graph size, typically fewer than 20. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/PageLimit" - $ref: "#/components/parameters/PageOffset" responses: "200": description: Array of run stages content: application/json: schema: $ref: "#/components/schemas/PaginatedRunStageList" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/stages/{stageId}/context-window: get: operationId: getRunStageContextWindow tags: [Run Internals] summary: Get Stage Context Window description: | Returns the latest best-effort model-visible context-window usage snapshot for an agent stage. Known stages without applicable or observed data return `available: false`; missing runs or stages return 404. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/StageId" responses: "200": description: Latest context-window snapshot or a typed unavailable state. content: application/json: schema: $ref: "#/components/schemas/StageContextWindow" "404": description: Run or stage not found. headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/artifacts: get: operationId: listRunArtifacts tags: [Run Internals] summary: List Run Artifacts description: Lists captured artifact files for a run. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Artifact files captured for the run content: application/json: schema: $ref: "#/components/schemas/RunArtifactListResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/artifacts/download: get: operationId: downloadRunArtifacts tags: [Run Internals] summary: Download Run Artifacts description: | Streams a ZIP archive with the latest captured version of each artifact path. Stage order, retry number, and then stage ID determine the latest version, matching the artifacts page. Captures from the graph's boundary nodes are excluded, identified by their `start` and `exit` handler type rather than by node name. The archive streams, so the response status is sent before the first artifact is read. A failure after that point aborts the transfer rather than returning `500`. The ZIP central directory is written last, so a truncated download does not open as a valid archive. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: ZIP archive containing the latest artifact files headers: Content-Disposition: description: Attachment filename for the ZIP archive schema: type: string content: application/zip: schema: type: string format: binary "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Artifact archive could not be prepared headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/files: get: operationId: listRunFiles tags: [Run Outputs] summary: List Run Files Changed description: | Returns the set of file changes produced by a run as a list of before/after diffs. While the run's sandbox is reachable, diffs are resolved live against the sandbox working tree at the current HEAD. Degraded responses keep the same `data: FileDiff[]` shape. File contents are null on every entry; non-sensitive non-flagged entries include `unified_patch`, while sensitive / binary / symlink / submodule / truncated entries render through the same placeholder flags used by the live path. Responses are bounded by per-file (256 KiB / 20k lines), per-run aggregate (5 MiB), and per-request (200 files) caps. Files exceeding a cap are returned with `truncated: true` and empty `contents`. Sensitive paths (credentials, keys) are elided with `sensitive: true` and empty `contents`. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/PageLimit" - $ref: "#/components/parameters/PageOffset" - name: scope in: query required: false description: Diff scope to return. Defaults to committed changes only. Sandbox-backed responses honor all scopes for tracked files; untracked files are excluded. Final-patch fallback responses always represent the stored committed/final diff. schema: type: string default: committed enum: - committed - uncommitted - all - name: from_sha in: query required: false description: Explicit start SHA for a commit-range diff. Must be supplied together with `to_sha`; when present, `scope` must be omitted and the response scope is `range`. schema: type: string pattern: "^[0-9a-f]{7,40}$" - name: to_sha in: query required: false description: Explicit end SHA for a commit-range diff. Must be supplied together with `from_sha`; when present, `scope` must be omitted and the response scope is `range`. schema: type: string pattern: "^[0-9a-f]{7,40}$" responses: "200": description: File diffs for the run content: application/json: schema: $ref: "#/components/schemas/PaginatedRunFileList" "400": description: Malformed query parameter (invalid SHA format, one-sided SHA range, or `scope` combined with an explicit SHA range). headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found (or caller lacks access; returned as 404 to prevent enumeration). headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: Transient sandbox subprocess failure (timeout, process kill). Safe to retry. headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/commits: get: operationId: listRunCommits tags: [Run Outputs] summary: List Run Commits description: | Returns commits on the run branch since the run's base SHA, sourced directly from sandbox Git. The list uses first-parent chronological history and is capped by `limit` (default and maximum: 100). Commit data is Git-authoritative; Fabro-generated commit messages are not required for correctness. parameters: - $ref: "#/components/parameters/RunId" - name: limit in: query required: false description: Maximum number of commits to return. Defaults to 100 and is capped at 100. schema: type: integer minimum: 1 maximum: 100 default: 100 responses: "200": description: Commits on the run branch since the run base. content: application/json: schema: $ref: "#/components/schemas/PaginatedRunCommitList" "400": description: Malformed run id or query parameter. headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run not found. headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run has no active sandbox or no base SHA. headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: Sandbox Git history is temporarily unavailable. headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/stages/{stageId}/artifacts: get: operationId: listStageArtifacts tags: [Run Internals] summary: List Stage Artifacts description: Lists artifact filenames stored for a stage. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/StageId" responses: "200": description: Artifact filenames for the stage content: application/json: schema: $ref: "#/components/schemas/ArtifactListResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/stages/{stageId}/artifacts/download: get: operationId: getStageArtifact tags: [Run Internals] summary: Get Stage Artifact description: Downloads an artifact by filename. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/StageId" - $ref: "#/components/parameters/ArtifactFilename" - $ref: "#/components/parameters/ArtifactRetry" responses: "200": description: Artifact contents content: application/octet-stream: schema: type: string format: binary "400": description: Missing filename or retry headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Run, stage, or artifact not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/usage: get: operationId: retrieveRunUsage tags: [Run Outputs] summary: Retrieve Run Usage description: Returns token counts and costs broken down by stage and model for a specific run. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Usage data content: application/json: schema: $ref: "#/components/schemas/RunUsage" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/settings: get: operationId: retrieveRunSettings tags: [Run Internals] summary: Retrieve Run Settings description: Returns the persisted dense `WorkflowSettings` snapshot used to launch this run. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Run settings content: application/json: schema: $ref: "#/components/schemas/WorkflowSettings" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/preview: post: operationId: generatePreviewUrl tags: [Human-in-the-Loop] summary: Preview URL description: Generates a preview URL for a port exposed by the run's sandbox environment. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PreviewUrlRequest" responses: "201": description: Preview URL created content: application/json: schema: $ref: "#/components/schemas/PreviewUrlResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run has no active sandbox headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/ssh: post: operationId: createRunSshAccess tags: [Human-in-the-Loop] summary: Sandbox Access Command description: Creates a command for connecting to the run's sandbox environment. Daytona runs return a time-limited SSH command; Docker runs return a local docker exec command. parameters: - $ref: "#/components/parameters/RunId" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/SshAccessRequest" responses: "201": description: Sandbox access command created content: application/json: schema: $ref: "#/components/schemas/SshAccessResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run has no active sandbox or provider does not support access commands headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/sandboxes: get: operationId: listSandboxes tags: [Sandboxes] summary: List Sandboxes description: Lists Fabro-managed sandboxes directly from configured sandbox providers. responses: "200": description: Provider-backed sandbox inventory content: application/json: schema: $ref: "#/components/schemas/SandboxListResponse" /api/v1/sandboxes/{id}: get: operationId: retrieveSandbox tags: [Sandboxes] summary: Retrieve Sandbox description: Retrieves a Fabro-managed sandbox by provider-native id by searching all configured sandbox providers. parameters: - in: path name: id required: true schema: type: string responses: "200": description: Sandbox found content: application/json: schema: $ref: "#/components/schemas/SandboxInfo" "404": description: No provider found a Fabro-managed sandbox with this id headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: More than one provider matched this sandbox id headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "502": description: Provider lookup failed before a definitive result could be determined headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/sandbox: get: operationId: retrieveRunSandbox tags: [Human-in-the-Loop] summary: Retrieve Run Sandbox Details description: Returns the sandbox owned by this run as fabro's record of it plus the sandbox driver's status (identity, state, image or snapshot, resources, network policy, labels, and timestamps). parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Sandbox details content: application/json: schema: $ref: "#/components/schemas/SandboxDetails" "404": description: Run not found or run has no sandbox headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Sandbox provider exists but inspection failed because the sandbox is gone or inaccessible headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "501": description: Sandbox provider has no details implementation headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/sandbox/services: get: operationId: listSandboxServices tags: [Human-in-the-Loop] summary: List Sandbox Services description: Lists listening TCP services discovered inside the run sandbox. parameters: - $ref: "#/components/parameters/RunId" responses: "200": description: Listening TCP services content: application/json: schema: $ref: "#/components/schemas/SandboxServiceListResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run has no active sandbox or service discovery failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/sandbox/vnc: post: operationId: createSandboxVncPreview tags: [Human-in-the-Loop] summary: Create Sandbox VNC Preview description: Starts or ensures Daytona Computer Use for the run sandbox and returns a signed noVNC preview URL. parameters: - $ref: "#/components/parameters/RunId" responses: "201": description: Signed noVNC preview URL created content: application/json: schema: $ref: "#/components/schemas/VncPreviewResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run has no active sandbox, Computer Use startup failed, or signed preview generation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "501": description: Sandbox provider does not support VNC previews headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/sandbox/files: get: operationId: listSandboxFiles tags: [Human-in-the-Loop] summary: List Sandbox Files description: Lists directory entries from the run's sandbox environment. parameters: - $ref: "#/components/parameters/RunId" - in: query name: path required: true schema: type: string - in: query name: depth required: false schema: type: integer minimum: 1 responses: "200": description: Directory entries content: application/json: schema: $ref: "#/components/schemas/SandboxFileListResponse" "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run has no active sandbox headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/runs/{id}/sandbox/file: get: operationId: getSandboxFile tags: [Human-in-the-Loop] summary: Download Sandbox File description: Downloads a file from the run's sandbox environment. parameters: - $ref: "#/components/parameters/RunId" - in: query name: path required: true schema: type: string responses: "200": description: File contents content: application/octet-stream: schema: type: string format: binary "404": description: Run or file not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run has no active sandbox headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: operationId: putSandboxFile tags: [Human-in-the-Loop] summary: Upload Sandbox File description: Uploads a file into the run's sandbox environment. parameters: - $ref: "#/components/parameters/RunId" - in: query name: path required: true schema: type: string requestBody: required: true content: application/octet-stream: schema: type: string format: binary responses: "204": description: File written "404": description: Run not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Run has no active sandbox headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" # ── Automations ────────────────────────────────────────────────────── /api/v1/automations: get: operationId: listAutomations tags: [Automations] summary: List automations description: Returns all configured automation definitions. responses: "200": description: Automation definitions content: application/json: schema: $ref: "#/components/schemas/AutomationListResponse" post: operationId: createAutomation tags: [Automations] summary: Create automation description: Creates a new automation definition. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateAutomationRequest" responses: "201": description: Automation created content: application/json: schema: $ref: "#/components/schemas/Automation" "400": description: Malformed JSON request body headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Automation id already exists headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Automation failed domain validation headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/automations/{id}: get: operationId: retrieveAutomation tags: [Automations] summary: Retrieve automation description: Returns one automation definition by id. parameters: - $ref: "#/components/parameters/AutomationId" responses: "200": description: Automation definition headers: ETag: $ref: "#/components/headers/ETag" content: application/json: schema: $ref: "#/components/schemas/Automation" "404": description: Automation not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: operationId: replaceAutomation tags: [Automations] summary: Replace automation description: Replaces an automation definition when `If-Match` matches the current automation revision. parameters: - $ref: "#/components/parameters/AutomationId" - $ref: "#/components/parameters/IfMatch" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ReplaceAutomationRequest" responses: "200": description: Automation replaced headers: ETag: $ref: "#/components/headers/ETag" content: application/json: schema: $ref: "#/components/schemas/Automation" "400": description: Malformed JSON request body or invalid revision header headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Automation not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Automation revision mismatch headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Automation failed domain validation headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "428": description: Missing required `If-Match` header headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: operationId: deleteAutomation tags: [Automations] summary: Delete automation description: Deletes an automation definition when `If-Match` matches the current automation revision. parameters: - $ref: "#/components/parameters/AutomationId" - $ref: "#/components/parameters/IfMatch" responses: "204": description: Automation deleted "400": description: Invalid revision header headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Automation not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Automation revision mismatch headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "428": description: Missing required `If-Match` header headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/automations/{id}/runs: get: operationId: listAutomationRuns tags: [Automations] summary: List automation runs description: Returns durable runs created by one automation. parameters: - $ref: "#/components/parameters/AutomationId" - $ref: "#/components/parameters/PageLimit" - $ref: "#/components/parameters/PageOffset" responses: "200": description: Paginated durable runs for the automation content: application/json: schema: $ref: "#/components/schemas/PaginatedRunList" "400": description: Invalid pagination parameter headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Automation not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: operationId: createAutomationRun tags: [Automations] summary: Create automation run description: Creates a new run by firing the automation's enabled API trigger. parameters: - $ref: "#/components/parameters/AutomationId" responses: "201": description: Run created content: application/json: schema: $ref: "#/components/schemas/Run" "404": description: Automation not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Automation has no enabled API trigger headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Automation target could not be materialized into a run headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" # ── MCP Servers ────────────────────────────────────────────────────── /api/v1/mcp-servers: get: operationId: listMcpServers tags: [MCP Servers] summary: List MCP servers description: Returns all server-managed MCP server definitions with transport env/header values omitted. responses: "200": description: MCP server definitions content: application/json: schema: $ref: "#/components/schemas/McpServerListResponse" "500": description: MCP server store operation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: operationId: createMcpServer tags: [MCP Servers] summary: Create MCP server description: Creates a new MCP server definition. The id is the runtime MCP server name used in qualified tool names. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateMcpServerRequest" responses: "201": description: MCP server created headers: ETag: $ref: "#/components/headers/ETag" content: application/json: schema: $ref: "#/components/schemas/McpServer" "400": description: Malformed JSON request body headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: MCP server id already exists headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: MCP server failed domain validation headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: MCP server store operation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/mcp-servers/{id}: get: operationId: retrieveMcpServer tags: [MCP Servers] summary: Retrieve MCP server description: Returns one MCP server definition by id with transport env/header values omitted. parameters: - $ref: "#/components/parameters/McpServerId" responses: "200": description: MCP server definition headers: ETag: $ref: "#/components/headers/ETag" content: application/json: schema: $ref: "#/components/schemas/McpServer" "400": description: Invalid MCP server id headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: MCP server not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: MCP server store operation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: operationId: replaceMcpServer tags: [MCP Servers] summary: Replace MCP server description: Replaces an MCP server definition when `If-Match` matches the current MCP server revision. parameters: - $ref: "#/components/parameters/McpServerId" - $ref: "#/components/parameters/IfMatch" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ReplaceMcpServerRequest" responses: "200": description: MCP server replaced headers: ETag: $ref: "#/components/headers/ETag" content: application/json: schema: $ref: "#/components/schemas/McpServer" "400": description: Malformed JSON request body, invalid MCP server id, or invalid revision header headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: MCP server not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: MCP server revision mismatch headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: MCP server failed domain validation headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "428": description: Missing required `If-Match` header headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: MCP server store operation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: operationId: deleteMcpServer tags: [MCP Servers] summary: Delete MCP server description: Deletes an MCP server definition when `If-Match` matches the current MCP server revision. parameters: - $ref: "#/components/parameters/McpServerId" - $ref: "#/components/parameters/IfMatch" responses: "204": description: MCP server deleted "400": description: Invalid MCP server id or revision header headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: MCP server not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: MCP server revision mismatch headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "428": description: Missing required `If-Match` header headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: MCP server store operation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" # ── Environments ───────────────────────────────────────────────────── /api/v1/environments: get: operationId: listEnvironments tags: [Environments] summary: List environments description: Returns all server-managed environment definitions, sorted by id. responses: "200": description: Environment definitions content: application/json: schema: $ref: "#/components/schemas/EnvironmentListResponse" "500": description: Environment store operation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" post: operationId: createEnvironment tags: [Environments] summary: Create environment description: | Creates a server-owned environment definition in the environment catalog. REST environment requests only accept inline Dockerfile content; local Dockerfile paths are supported by workflow/settings files but rejected by this API. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateEnvironmentRequest" responses: "201": description: Environment created content: application/json: schema: $ref: "#/components/schemas/Environment" "400": description: Malformed JSON request body headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Environment id already exists headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Environment failed domain validation headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Environment store operation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/environments/{id}: get: operationId: retrieveEnvironment tags: [Environments] summary: Retrieve environment description: Returns one server-managed environment definition by id. parameters: - $ref: "#/components/parameters/EnvironmentId" responses: "200": description: Environment definition headers: ETag: $ref: "#/components/headers/ETag" content: application/json: schema: $ref: "#/components/schemas/Environment" "400": description: Invalid environment id headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Environment not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Environment store operation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: operationId: replaceEnvironment tags: [Environments] summary: Replace environment description: | Replaces an environment definition when `If-Match` matches the current environment revision. The path id is authoritative; the request body omits `id`. parameters: - $ref: "#/components/parameters/EnvironmentId" - $ref: "#/components/parameters/IfMatch" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ReplaceEnvironmentRequest" responses: "200": description: Environment replaced headers: ETag: $ref: "#/components/headers/ETag" content: application/json: schema: $ref: "#/components/schemas/Environment" "400": description: Malformed JSON request body, invalid environment id, or invalid revision header headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Environment not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Environment revision mismatch or protected environment conflict headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Environment failed domain validation headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "428": description: Missing required `If-Match` header headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Environment store operation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: operationId: deleteEnvironment tags: [Environments] summary: Delete environment description: Deletes a non-default environment definition when `If-Match` matches the current environment revision. parameters: - $ref: "#/components/parameters/EnvironmentId" - $ref: "#/components/parameters/IfMatch" responses: "204": description: Environment deleted "400": description: Invalid environment id or revision header headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Environment not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "409": description: Environment revision mismatch or protected environment conflict headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "428": description: Missing required `If-Match` header headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Environment store operation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" # ── Workflows ──────────────────────────────────────────────────────── /api/v1/workflows: get: operationId: listWorkflows tags: [Workflows] summary: List workflows description: Returns workflow definitions available to the browser workflow pages. Real-mode servers may return 501 until workflow cataloging is implemented. parameters: - $ref: "#/components/parameters/PageLimit" - $ref: "#/components/parameters/PageOffset" responses: "200": description: Paginated workflow summaries content: application/json: schema: $ref: "#/components/schemas/PaginatedWorkflowListResponse" "501": description: Workflow cataloging is not implemented in real mode headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/workflows/{name}: get: operationId: retrieveWorkflow tags: [Workflows] summary: Retrieve workflow description: Returns a single workflow definition and its dense settings snapshot. parameters: - name: name in: path required: true description: Workflow slug or name. schema: type: string responses: "200": description: Workflow details content: application/json: schema: $ref: "#/components/schemas/WorkflowDetailResponse" "404": description: Workflow not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "501": description: Workflow cataloging is not implemented in real mode headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/workflows/{name}/runs: get: operationId: listWorkflowRuns tags: [Workflows] summary: List workflow runs description: Returns durable runs associated with one workflow. parameters: - name: name in: path required: true description: Workflow slug or name. schema: type: string - $ref: "#/components/parameters/PageLimit" - $ref: "#/components/parameters/PageOffset" responses: "200": description: Paginated durable runs for the workflow content: application/json: schema: $ref: "#/components/schemas/PaginatedRunList" "404": description: Workflow not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "501": description: Workflow cataloging is not implemented in real mode headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" # ── Insights ────────────────────────────────────────────────────────── /api/v1/insights/queries: get: operationId: listSavedQueries tags: [Insights] summary: List Saved Queries description: Returns a paginated list of saved SQL queries for the insights editor. parameters: - $ref: "#/components/parameters/PageLimit" - $ref: "#/components/parameters/PageOffset" responses: "200": description: Paginated list of saved queries content: application/json: schema: $ref: "#/components/schemas/PaginatedSavedQueryList" post: operationId: createSavedQuery tags: [Insights] summary: Create Saved Query description: Saves a new named SQL query for later reuse. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/SaveQueryRequest" responses: "201": description: Query saved content: application/json: schema: $ref: "#/components/schemas/SavedQuery" /api/v1/insights/queries/{id}: get: operationId: retrieveSavedQuery tags: [Insights] summary: Retrieve Saved Query description: Returns a single saved query by ID. parameters: - $ref: "#/components/parameters/InsightQueryId" responses: "200": description: Saved query content: application/json: schema: $ref: "#/components/schemas/SavedQuery" "404": description: Query not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: operationId: updateSavedQuery tags: [Insights] summary: Update Saved Query description: Replaces the name and SQL of an existing saved query. parameters: - $ref: "#/components/parameters/InsightQueryId" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/SaveQueryRequest" responses: "200": description: Query updated content: application/json: schema: $ref: "#/components/schemas/SavedQuery" "404": description: Query not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: operationId: deleteSavedQuery tags: [Insights] summary: Delete Saved Query description: Permanently removes a saved query. parameters: - $ref: "#/components/parameters/InsightQueryId" responses: "204": description: Query deleted "404": description: Query not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/insights/execute: post: operationId: executeQuery tags: [Insights] summary: Execute Query description: Executes an ad-hoc SQL query against the analytics database and returns columnar results. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ExecuteQueryRequest" responses: "200": description: Query results content: application/json: schema: $ref: "#/components/schemas/ExecuteQueryResponse" "400": description: Bad SQL or query error headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/insights/history: get: operationId: listQueryHistory tags: [Insights] summary: List Query History description: Returns a paginated history of recently executed queries with timing and row counts. parameters: - $ref: "#/components/parameters/PageLimit" - $ref: "#/components/parameters/PageOffset" responses: "200": description: Paginated list of history entries content: application/json: schema: $ref: "#/components/schemas/PaginatedHistoryEntryList" # ── Usage ──────────────────────────────────────────────────────────── /api/v1/usage: get: operationId: getAggregateUsage tags: [Usage] summary: Aggregate Usage description: Returns aggregate token counts and costs across all completed runs since server start. responses: "200": description: Aggregate usage data content: application/json: schema: $ref: "#/components/schemas/AggregateUsage" # ── System ─────────────────────────────────────────────────────────── /api/v1/attach: get: operationId: attachEvents tags: [System] summary: Attach Global Events description: >- Opens a server-sent event stream of every run's stream across the server: each `data:` frame is one `RunStreamItem`, as it is committed. parameters: - name: run_id in: query required: false description: Optional comma-separated list of run IDs to include. schema: type: string responses: "200": description: Server-sent event stream content: text/event-stream: schema: type: string /api/v1/system/info: get: operationId: getSystemInfo tags: [System] summary: Retrieve System Info description: Returns runtime details about the active Fabro server process. responses: "200": description: System information content: application/json: schema: $ref: "#/components/schemas/SystemInfoResponse" /api/v1/system/resources: get: operationId: getSystemResources tags: [System] summary: Retrieve System Resources description: Returns server-visible CPU, memory, and storage filesystem resource usage. responses: "200": description: System resource usage content: application/json: schema: $ref: "#/components/schemas/SystemResourcesResponse" /api/v1/system/integrations: get: operationId: getSystemIntegrations tags: [System] summary: Retrieve System Integrations description: Returns runtime integration status computed from server configuration, vault credentials, and live connection state. responses: "200": description: Runtime integration status content: application/json: schema: $ref: "#/components/schemas/SystemIntegrationsResponse" /api/v1/system/df: get: operationId: getSystemDiskUsage tags: [System] summary: Retrieve System Disk Usage description: Returns disk usage for the server storage directory. parameters: - name: verbose in: query required: false description: Include per-run disk usage rows. schema: type: boolean default: false responses: "200": description: Disk usage summary content: application/json: schema: $ref: "#/components/schemas/DiskUsageResponse" /api/v1/system/repair/runs: get: operationId: getSystemRepairRuns tags: [System] summary: List Run Repair Issues description: Lists cataloged runs that cannot be loaded from durable storage. responses: "200": description: Run repair issues content: application/json: schema: $ref: "#/components/schemas/SystemRepairRunsResponse" /api/v1/system/prune/runs: post: operationId: pruneRuns tags: [System] summary: Prune Runs description: Deletes completed runs matching the provided filters, or previews the deletion set when dry-run is enabled. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PruneRunsRequest" responses: "200": description: Prune result content: application/json: schema: $ref: "#/components/schemas/PruneRunsResponse" "400": description: Invalid prune request headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" # ── Secrets ────────────────────────────────────────────────────────── /api/v1/secrets: get: operationId: listSecrets tags: [Secrets] summary: List vault secrets description: Returns workflow-visible vault secret names and timestamps. Secret values are never exposed. responses: "200": description: Secret metadata list content: application/json: schema: $ref: "#/components/schemas/SecretListResponse" post: operationId: createSecret tags: [Secrets] summary: Store or update a vault secret description: Stores a secret in the workflow-visible vault. Anything stored here may be used by workflows. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateSecretRequest" responses: "200": description: Secret stored content: application/json: schema: $ref: "#/components/schemas/SecretMetadata" "400": description: Invalid secret name or request body headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: operationId: deleteSecretByName tags: [Secrets] summary: Delete a vault secret requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/DeleteSecretRequest" responses: "204": description: Secret deleted "400": description: Invalid secret name or request body headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Secret not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Secret store write failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" # ── Variables ──────────────────────────────────────────────────────── /api/v1/variables: get: operationId: listVariables tags: [Variables] summary: List variables description: Returns non-sensitive variables, including values. responses: "200": description: Variable list content: application/json: schema: $ref: "#/components/schemas/VariableListResponse" post: operationId: createVariable tags: [Variables] summary: Store or update a variable description: Stores a non-sensitive variable for run config interpolation. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateVariableRequest" responses: "200": description: Variable stored content: application/json: schema: $ref: "#/components/schemas/Variable" "400": description: Invalid variable name or request body headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Variable store write failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/variables/{name}: parameters: - name: name in: path required: true schema: type: string pattern: "^[A-Za-z_][A-Za-z0-9_]*$" description: Variable name. get: operationId: getVariable tags: [Variables] summary: Get a variable responses: "200": description: Variable content: application/json: schema: $ref: "#/components/schemas/Variable" "400": description: Invalid variable name headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Variable not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" put: operationId: updateVariable tags: [Variables] summary: Replace a variable value description: Replaces a variable value and preserves the existing description when omitted. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateVariableRequest" responses: "200": description: Variable updated content: application/json: schema: $ref: "#/components/schemas/Variable" "400": description: Invalid variable name or request body headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Variable not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Variable store write failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" delete: operationId: deleteVariable tags: [Variables] summary: Delete a variable responses: "204": description: Variable deleted "400": description: Invalid variable name headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Variable not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Variable store write failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" # ── Repos ──────────────────────────────────────────────────────────── /api/v1/repos/github/{owner}/{name}: get: operationId: getGithubRepo tags: [Repos] summary: Check server access to a GitHub repository parameters: - name: owner in: path required: true schema: type: string - name: name in: path required: true schema: type: string responses: "200": description: Repository access details content: application/json: schema: $ref: "#/components/schemas/RepoCheckResponse" # ── Models ─────────────────────────────────────────────────────────── /api/v1/models: get: operationId: listModels tags: [Models] summary: List Models description: | Returns one row per provider/model offering from the catalog. Model IDs are unique within a provider; `(provider, id)` is the resource identity. parameters: - $ref: "#/components/parameters/ModelProviderFilter" - $ref: "#/components/parameters/ModelQueryFilter" - $ref: "#/components/parameters/PageLimit" - $ref: "#/components/parameters/PageOffset" responses: "200": description: Paginated list of models content: application/json: schema: $ref: "#/components/schemas/PaginatedModelList" "400": description: Invalid filter value headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/models/{id}/test: post: operationId: testModel tags: [Models] summary: Test Model description: Tests a model by sending a simple prompt and reporting pass/fail. parameters: - name: id in: path required: true schema: type: string description: The canonical model ID or an alias. - $ref: "#/components/parameters/ModelTestProviderParam" - $ref: "#/components/parameters/ModelTestModeParam" - $ref: "#/components/parameters/ModelTestReasoningEffortParam" responses: "200": description: Test result content: application/json: schema: $ref: "#/components/schemas/ModelTestResult" "400": description: Invalid test mode or reasoning effort headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Model not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/providers: get: operationId: listProviders tags: [Models] summary: List Providers description: Returns LLM providers from the catalog with effective config and configured status. responses: "200": description: Provider list content: application/json: schema: $ref: "#/components/schemas/ProviderList" /api/v1/providers/{provider}/credentials/test: post: operationId: testProviderCredentials tags: [Models] summary: Test Provider Credentials description: Validates an LLM provider API key against the server's effective catalog without persisting it. parameters: - name: provider in: path required: true schema: type: string description: The provider identifier. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ProviderCredentialTestRequest" responses: "200": description: Credentials validated successfully content: application/json: schema: $ref: "#/components/schemas/ProviderCredentialTestResponse" "400": description: Invalid provider credential request headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: Provider not found headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "422": description: Credential validation failed headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /api/v1/providers/test: post: operationId: testProviders tags: [Models] summary: Test Providers description: > Tests every configured LLM provider once using the catalog probe model. Provider-level failures are returned in the response body with HTTP 200. responses: "200": description: Provider test results content: application/json: schema: $ref: "#/components/schemas/ProviderTestList" # ── Completions ─────────────────────────────────────────────────────── /api/v1/completions: post: operationId: createCompletion tags: [Completions] summary: Create Completion description: | Generate a text completion. Set `stream: true` for SSE streaming. All SSE frames use `event: stream_event` with a JSON-serialized lithos `StreamEvent` payload, discriminated by `type`: started, content_block_start, text_delta, reasoning_delta, tool_call_delta, content_block_end, usage, rate_limits, ended, and error. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateCompletionRequest" responses: "200": description: Completion result (JSON when stream=false, SSE when stream=true) content: application/json: schema: $ref: "#/components/schemas/CompletionResponse" "400": description: Invalid request headers: x-request-id: $ref: "#/components/headers/XRequestId" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" # ── Settings ────────────────────────────────────────────────────────── /api/v1/settings: get: operationId: retrieveServerSettings tags: [Settings] summary: Retrieve Server Settings description: > Returns the server's current in-memory settings view as the typed `ServerSettings` payload. responses: "200": description: Server settings content: application/json: schema: $ref: "#/components/schemas/ServerSettings" components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: opaque description: > Raw dev token passed as `Authorization: Bearer fabro_dev_...` when `server.auth.methods` includes `dev-token`. SessionCookie: type: apiKey in: cookie name: __fabro_session description: > Private session cookie issued after a successful web login. The server verifies and decodes the cookie before authenticating the request. parameters: RunId: name: id in: path required: true description: Unique run identifier (ULID). schema: type: string example: 01JNQVR7M0EJ5GKAT2SC4ERS1Z AutomationId: name: id in: path required: true description: Unique automation identifier. schema: type: string pattern: "^[a-z0-9][a-z0-9-]{0,62}$" example: nightly-deps EnvironmentId: name: id in: path required: true description: Unique environment identifier. schema: type: string pattern: "^[a-z0-9][a-z0-9-]{0,62}$" example: docker McpServerId: name: id in: path required: true description: Stable MCP server identifier, used as the runtime MCP server name in qualified tool names. schema: type: string pattern: "^[a-z0-9][a-z0-9-]{0,62}$" example: sentry IfMatch: name: If-Match in: header required: true description: Current resource revision used for optimistic concurrency, as returned in the `ETag` response header. schema: type: string example: '"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"' RunSelector: name: selector in: query required: true description: Run selector, such as a run ID prefix, workflow slug, or workflow name. schema: type: string example: nightly-build StageId: name: stageId in: path required: true description: Identifier of a stage within a run's workflow graph, serialized as `node_id@visit`. schema: type: string example: code@2 CommandLogOffset: name: offset in: query required: false description: Byte offset to start reading from. Defaults to `0`. schema: type: integer minimum: 0 default: 0 example: 65536 CommandLogLimit: name: limit in: query required: false description: Maximum bytes to return. Defaults to 65536 and is capped at 1048576. schema: type: integer minimum: 1 maximum: 1048576 default: 65536 example: 65536 BlobHash: name: blobHash in: path required: true description: Content-addressed blob hash. schema: $ref: "#/components/schemas/BlobHash" example: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 PetriLog: name: log in: path required: true description: >- A Petri log of the run, as its id renders: `coordinator`, `resources`, or `execution ` for execution `n`. The space is percent-encoded on the wire. schema: type: string example: execution 0 PetriOwner: name: owner in: query required: true description: The owner id the worker opened the run's writer lease with. schema: type: string example: 18f3c2a9e1b4-42017-0-9f3a1c7e2b5d PetriPlatformRecordKind: name: kind in: query required: false description: >- Only the platform records of this kind, as its `kind` tag spells it (`checkpoint`, `pull_request.created`, ...). schema: type: string example: checkpoint ArtifactFilename: name: filename in: query required: true description: Relative artifact path. `/` is allowed as a path separator. Backslash, empty segments, and traversal segments (`.` and `..`) are invalid. schema: type: string example: src/lib.rs ArtifactRetry: name: retry in: query required: true description: Retry attempt number for the artifact. schema: type: integer format: int32 minimum: 0 example: 1 SinceSeq: name: since_seq in: query required: false description: First event sequence number to include. schema: type: integer minimum: 1 default: 1 example: 42 EventLimit: name: limit in: query required: false description: Maximum number of events to return. schema: type: integer minimum: 1 maximum: 1000 default: 100 example: 100 StreamAfter: name: after in: query required: false description: | Run stream cursor for a Petri run: the last `stream_seq` the client saw, exclusive. `0` starts at the first item. schema: type: integer format: uint64 minimum: 0 default: 0 example: 42 QuestionId: name: qid in: path required: true description: Unique identifier of a pending question. schema: type: string example: q-001 InsightQueryId: name: id in: path required: true description: Unique identifier of a saved query. schema: type: string example: "1" CheckpointFilter: name: checkpoint in: query required: false description: Filter to a specific checkpoint ID. Omit to include all changes. schema: type: string example: cp-3 PageLimit: name: page[limit] in: query required: false description: Maximum number of items to return per page. schema: type: integer minimum: 1 maximum: 100 default: 20 example: 20 PageOffset: name: page[offset] in: query required: false description: Number of items to skip before returning results. schema: type: integer minimum: 0 default: 0 example: 0 IncludeArchived: name: include_archived in: query required: false description: Whether to include archived runs in the response. Defaults to `false`. schema: type: boolean default: false example: false ParentRunId: name: parent_id in: query required: false description: Return only runs currently linked to this orchestration parent. schema: type: string example: 01JNQVR7M0EJ5GKAT2SC4ERS1Z RunStatusFilter: name: status in: query required: false style: form explode: true description: | Filter runs by status bucket. Repeatable. When omitted, runs in the `removing` bucket are hidden; pass `status=removing` to include them. Archived runs are hidden unless `include_archived=true` or `status=archived` is passed. schema: type: array items: $ref: "#/components/schemas/BoardColumn" example: [running, blocked] RunsSort: name: sort in: query required: false description: Field to sort by. Defaults to `created_at`. schema: type: string enum: [created_at, updated_at, status, elapsed, repo, title, workflow, changes, size] default: created_at example: created_at RunsSortDirection: name: direction in: query required: false description: Sort direction. Defaults to `desc`. schema: type: string enum: [asc, desc] default: desc example: desc ForceRunDelete: name: force in: query required: false description: Whether to force deletion of an active run. Defaults to `false`. schema: type: boolean default: false example: false ModelProviderFilter: name: provider in: query required: false description: Filter models by provider ID. Unknown provider IDs return an empty result set. schema: $ref: "#/components/schemas/ProviderId" example: anthropic ModelQueryFilter: name: query in: query required: false description: Case-insensitive substring search across `id`, `display_name`, and `aliases`. schema: type: string example: opus ModelTestModeParam: name: mode in: query required: false description: Test mode for the single-model test endpoint. Defaults to `basic`. schema: $ref: "#/components/schemas/ModelTestMode" example: basic ModelTestProviderParam: name: provider in: query required: false description: | Pin the test to this provider's offering. When omitted, the server selects among ready providers by catalog priority. schema: $ref: "#/components/schemas/ProviderId" example: openrouter ModelTestReasoningEffortParam: name: reasoning_effort in: query required: false description: Optional native reasoning-effort level for the model test. schema: $ref: "#/components/schemas/ReasoningEffort" example: high headers: XRequestId: description: > Server-generated request identifier emitted on every response and referenced on standard error responses for correlating client errors with server logs. schema: type: string format: uuid ETag: description: Current resource revision for optimistic concurrency. Supply this value via `If-Match` on subsequent mutating requests. schema: type: string example: '"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"' schemas: AuthConfigResponse: description: Browser login methods enabled by server auth settings. type: object required: - methods properties: methods: type: array items: type: string example: ["dev-token", "github"] AuthMeResponse: description: Current authenticated browser user and session state. type: object required: - user - provider - demoMode properties: user: $ref: "#/components/schemas/AuthSessionUser" provider: type: string example: dev-token demoMode: type: boolean AuthSessionsResponse: type: object required: - sessions properties: sessions: type: array items: $ref: "#/components/schemas/AuthSession" AuthSession: type: object required: - id - kind - current - provider - login - label - createdAt - lastSeenAt - expiresAt - revocable properties: id: type: string kind: type: string enum: [browser, cli] current: type: boolean provider: type: string example: github login: type: string label: type: string userAgent: type: string nullable: true createdAt: type: string format: date-time lastSeenAt: type: string format: date-time expiresAt: type: string format: date-time revocable: type: boolean AuthSessionUser: description: Browser session user profile. type: object required: - login - name - email - avatarUrl - userUrl properties: login: type: string name: type: string email: type: string idpIssuer: type: string idpSubject: type: string avatarUrl: type: string userUrl: type: string DevTokenLoginRequest: description: Browser login payload for development-token auth. type: object required: - token properties: token: type: string DevTokenLoginResponse: description: Browser development-token login result. type: object required: - ok properties: ok: type: boolean InstallSessionResponse: description: Current browser-install session snapshot with secrets redacted. type: object required: - completed_steps - prefill properties: completed_steps: type: array items: type: string llm: oneOf: - $ref: "#/components/schemas/InstallLlmSummary" - type: "null" server: oneOf: - $ref: "#/components/schemas/InstallServerConfigInput" - type: "null" object_store: oneOf: - $ref: "#/components/schemas/InstallObjectStoreSummary" - type: "null" sandbox: oneOf: - $ref: "#/components/schemas/InstallSandboxSummary" - type: "null" github: oneOf: - $ref: "#/components/schemas/InstallGithubSummary" - type: "null" prefill: $ref: "#/components/schemas/InstallPrefill" InstallPrefill: description: Server-detected defaults used to prefill the browser install wizard. type: object required: - canonical_url - object_store_local_root properties: canonical_url: type: string format: uri object_store_local_root: type: string InstallLlmValidationResponse: description: Successful response from install-time LLM credential validation. type: object required: - ok properties: ok: type: boolean example: true InstallLlmTestInput: description: Input for install-time LLM credential validation. Supported providers in install v1 are `anthropic`, `openai`, and `gemini`. type: object required: - provider - api_key properties: provider: type: string example: anthropic api_key: type: string InstallLlmProvidersInput: description: >- LLM providers selected during browser install. An empty `providers` list explicitly marks the LLM step as completed and skipped. type: object required: - providers properties: providers: type: array description: >- LLM providers to persist. An empty list records an explicit skip: the LLM step is marked complete with zero credentials. items: $ref: "#/components/schemas/InstallLlmProviderInput" InstallLlmProviderInput: description: One persisted LLM provider configuration collected during browser install. Supported providers in install v1 are `anthropic`, `openai`, and `gemini`. type: object required: - provider - api_key properties: provider: type: string example: anthropic api_key: type: string InstallLlmSummary: description: >- Redacted summary of persisted LLM install choices. Present with an empty `providers` list when the LLM step was explicitly skipped; `null` on the install session means the step is still incomplete. type: object properties: providers: type: array items: type: object required: - provider - configured properties: provider: type: string configured: type: boolean InstallServerConfigInput: description: Canonical server URL confirmed during browser install. type: object required: - canonical_url properties: canonical_url: type: string format: uri InstallObjectStoreValidationResponse: description: Successful response from install-time object-store validation. type: object required: - ok properties: ok: type: boolean example: true InstallObjectStoreInput: description: Object-store mode selected during browser install. type: object required: - provider properties: provider: type: string enum: [local, s3] root: type: string bucket: type: string region: type: string credential_mode: type: string enum: [runtime, access_key] access_key_id: type: string secret_access_key: type: string InstallObjectStoreSummary: description: Redacted summary of the object-store mode selected during browser install. type: object required: - provider properties: provider: type: string enum: [local, s3] root: type: string bucket: type: string region: type: string credential_mode: type: string enum: [runtime, access_key] manual_credentials_saved: type: boolean InstallSandboxValidationResponse: description: Successful response from install-time sandbox validation. type: object required: - ok properties: ok: type: boolean example: true InstallSandboxInput: description: Sandbox provider selected during browser install. `api_key` is required for Daytona and ignored for Docker. `allow_local` enables the local sandbox provider alongside the selected runtime; it defaults to true when omitted. type: object required: - provider properties: provider: type: string enum: [docker, daytona] api_key: type: string allow_local: type: boolean InstallSandboxSummary: description: Redacted summary of the sandbox provider selected during browser install. type: object required: - provider properties: provider: type: string enum: [docker, daytona] api_key_saved: type: boolean allow_local: type: boolean InstallGithubTokenTestInput: description: Input for install-time GitHub token validation. type: object required: - token properties: token: type: string InstallGithubTokenTestResponse: description: Successful response from install-time GitHub token validation. type: object required: - username properties: username: type: string InstallGithubTokenInput: description: GitHub personal access token chosen during browser install. type: object required: - token - username properties: token: type: string username: type: string InstallGithubAppManifestInput: description: Input required to build the browser-install GitHub App manifest. type: object required: - owner - app_name - allowed_username properties: owner: $ref: "#/components/schemas/InstallGithubAppOwner" app_name: type: string allowed_username: type: string InstallGithubAppOwner: description: Owner of the GitHub App being created during browser install. type: object required: - kind properties: kind: type: string enum: [personal, org] slug: type: string description: Required when `kind` is `org`; the organization slug. InstallGithubAppManifestResponse: description: Browser handoff payload for the GitHub App creation flow. type: object required: - manifest - github_form_action - state properties: manifest: type: object additionalProperties: true github_form_action: type: string format: uri state: description: | CSRF token the browser must echo back to GitHub as a hidden `state` form field alongside `manifest`. GitHub preserves it on the redirect to `redirect_url` so the server can match the callback to this pending install. type: string InstallGithubSummary: description: Redacted summary of the GitHub install strategy selected during browser install. type: object required: - strategy properties: strategy: type: string enum: [token, app] username: type: string owner: $ref: "#/components/schemas/InstallGithubAppOwner" app_name: type: string slug: type: string allowed_username: type: string InstallFinishResponse: description: Response returned after install outputs are persisted successfully. type: object required: - status - restart_url properties: status: type: string enum: [completing] restart_url: type: string format: uri dev_token: type: string description: | Dev token used to bootstrap login. Only included when the operator chose the personal access token flow; GitHub App installs rely on OAuth and do not receive a dev token. # ── Automations ────────────────────────────────────────────────────── AutomationGitWorkflowSource: description: >- Explicit GitHub coordinate from which an automation acquires workflow bytes. The branch is the fallback selector and audit context. An optional tag overrides the branch, and an optional exact SHA overrides both without requiring branch ancestry. This source is independent of the run target and does not provide its working branch. type: object additionalProperties: false required: - repo - branch properties: repo: type: string minLength: 3 maxLength: 140 pattern: "^[A-Za-z0-9][A-Za-z0-9-]*/[A-Za-z0-9._-]+$" description: GitHub repository slug in `owner/name` form. example: acme/workflows branch: type: string minLength: 1 maxLength: 255 pattern: "^[A-Za-z0-9/._-]+$" description: >- Required bare branch name used when neither tag nor SHA is present. It is retained as context when an override is present and is not an ancestry constraint. example: main tag: type: string minLength: 1 maxLength: 255 pattern: "^[A-Za-z0-9/._-]+$" description: >- Optional bare tag name. Without `sha`, this tag is resolved whenever the automation fires. Prefixes such as `refs/tags/` are rejected. example: v1.2.3 sha: type: string pattern: "^[0-9A-Fa-f]{40}$" description: >- Optional exact commit, authoritative over tag and branch. The server lowercase-normalizes it and fetches it directly; it need not be reachable from the named branch. ResolvedAutomationGitWorkflowSource: description: >- Workflow source coordinate and exact commit captured when an automation run was created. The requested selectors remain available for audit context while `resolved_sha` identifies the immutable source revision that supplied the workflow bytes. type: object additionalProperties: false required: - repo - branch - resolved_sha properties: repo: type: string description: GitHub repository slug in `owner/name` form. branch: type: string description: Required branch fallback and audit context. tag: type: string description: Optional tag requested by the automation. sha: type: string pattern: "^[0-9a-f]{40}$" description: Optional exact commit requested by the automation. resolved_sha: type: string pattern: "^[0-9a-f]{40}$" description: Exact lowercase Git commit that supplied the workflow bytes. Automation: description: Public automation definition. type: object additionalProperties: false required: - id - revision - name - description - environment_id - last_error - target - workflow - triggers properties: id: type: string pattern: "^[a-z0-9][a-z0-9-]{0,62}$" example: nightly-deps revision: type: string pattern: "^[0-9a-f]{64}$" description: Stable revision used with `If-Match` for optimistic concurrency. example: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef name: type: string example: Nightly dependency update description: type: ["string", "null"] example: Keeps dependencies fresh. environment_id: type: ["string", "null"] description: | Server-managed Docker or Daytona environment selected when the automation fires. Null only for an incomplete definition migrated from a release that predated environment selection. example: daytona-smoke last_error: type: ["string", "null"] description: Most recent scheduled-run failure, cleared after a scheduled run is queued successfully. target: $ref: "#/components/schemas/RunTarget" workflow: type: string description: >- Workflow slug or path resolved in the run-target checkout when `workflow_source` is omitted, or in the explicit workflow-source checkout when present. example: dependency-update workflow_source: $ref: "#/components/schemas/AutomationGitWorkflowSource" triggers: type: array items: $ref: "#/components/schemas/AutomationTrigger" AutomationTrigger: description: | Automation trigger configuration. Unknown `type` discriminator values are reported by handlers as domain validation errors with HTTP 422. oneOf: - $ref: "#/components/schemas/AutomationApiTrigger" - $ref: "#/components/schemas/AutomationScheduleTrigger" discriminator: propertyName: type mapping: api: "#/components/schemas/AutomationApiTrigger" schedule: "#/components/schemas/AutomationScheduleTrigger" AutomationApiTrigger: description: Trigger that allows callers to create runs through the automation API. type: object additionalProperties: false required: - id - type - enabled properties: id: type: string pattern: "^[a-z0-9][a-z0-9_-]{0,62}$" example: manual type: type: string enum: [api] enabled: type: boolean example: true AutomationScheduleTrigger: description: Cron schedule trigger evaluated in UTC. type: object additionalProperties: false required: - id - type - enabled - expression properties: id: type: string pattern: "^[a-z0-9][a-z0-9_-]{0,62}$" example: nightly type: type: string enum: [schedule] enabled: type: boolean example: true expression: type: string description: Five-field cron expression evaluated in UTC. example: "0 3 * * *" CreateAutomationRequest: description: Request body for creating an automation. type: object additionalProperties: false required: - id - name - environment_id - target - workflow - triggers properties: id: type: string pattern: "^[a-z0-9][a-z0-9-]{0,62}$" example: nightly-deps name: type: string example: Nightly dependency update description: type: ["string", "null"] example: Keeps dependencies fresh. environment_id: type: string description: Server-managed Docker or Daytona environment selected when the automation fires. example: daytona-smoke target: $ref: "#/components/schemas/RunTarget" workflow: type: string description: >- Workflow slug or path resolved in the run-target checkout when `workflow_source` is omitted, or in the explicit workflow-source checkout when present. example: dependency-update workflow_source: $ref: "#/components/schemas/AutomationGitWorkflowSource" triggers: type: array items: $ref: "#/components/schemas/AutomationTrigger" ReplaceAutomationRequest: description: Request body for replacing an automation. type: object additionalProperties: false required: - name - environment_id - target - workflow - triggers properties: name: type: string example: Nightly dependency update description: type: ["string", "null"] example: Keeps dependencies fresh. environment_id: type: string description: Server-managed Docker or Daytona environment selected when the automation fires. example: daytona-smoke target: $ref: "#/components/schemas/RunTarget" workflow: type: string description: >- Workflow slug or path resolved in the run-target checkout when `workflow_source` is omitted, or in the explicit workflow-source checkout when present. example: dependency-update workflow_source: $ref: "#/components/schemas/AutomationGitWorkflowSource" triggers: type: array items: $ref: "#/components/schemas/AutomationTrigger" AutomationListResponse: description: List envelope for automation definitions. type: object additionalProperties: false required: - data - meta properties: data: type: array items: $ref: "#/components/schemas/Automation" meta: $ref: "#/components/schemas/AutomationListMeta" AutomationListMeta: description: Metadata for automation list responses. type: object additionalProperties: false required: - total properties: total: type: integer format: int64 minimum: 0 description: Total number of configured automation definitions. # ── MCP Servers ────────────────────────────────────────────────────── McpServer: description: Public server-managed MCP server definition. Transport env/header values are never returned. type: object additionalProperties: false required: - id - revision - display_name - description - transport - startup_timeout_secs - tool_timeout_secs properties: id: type: string description: Stable MCP server identifier, used as the runtime MCP server name in qualified tool names. pattern: "^[a-z0-9][a-z0-9-]{0,62}$" example: sentry revision: type: string pattern: "^[0-9a-f]{64}$" description: Stable revision used with `If-Match` for optimistic concurrency. example: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef display_name: type: string description: Human-readable label for display in management UIs. example: Sentry description: type: ["string", "null"] example: Production Sentry MCP server. transport: $ref: "#/components/schemas/McpTransportView" startup_timeout_secs: type: integer format: int64 minimum: 0 description: Seconds to wait for the MCP server to become ready at connect time. example: 10 tool_timeout_secs: type: integer format: int64 minimum: 0 description: Seconds to allow each MCP tool call before timing out. example: 60 CreateMcpServerRequest: description: Request body for creating an MCP server definition. type: object additionalProperties: false required: - id - display_name - transport - startup_timeout_secs - tool_timeout_secs properties: id: type: string description: Stable MCP server identifier, used as the runtime MCP server name in qualified tool names. pattern: "^[a-z0-9][a-z0-9-]{0,62}$" example: sentry display_name: type: string description: Human-readable label for display in management UIs. example: Sentry description: type: ["string", "null"] example: Production Sentry MCP server. transport: $ref: "#/components/schemas/McpTransport" startup_timeout_secs: type: integer format: int64 minimum: 0 example: 10 tool_timeout_secs: type: integer format: int64 minimum: 0 example: 60 ReplaceMcpServerRequest: description: Request body for replacing an MCP server definition. The path id is authoritative. type: object additionalProperties: false required: - display_name - transport - startup_timeout_secs - tool_timeout_secs properties: display_name: type: string description: Human-readable label for display in management UIs. example: Sentry description: type: ["string", "null"] example: Production Sentry MCP server. transport: $ref: "#/components/schemas/McpTransport" startup_timeout_secs: type: integer format: int64 minimum: 0 example: 10 tool_timeout_secs: type: integer format: int64 minimum: 0 example: 60 # Write requests use the same transport schema as run config. Read responses # use a value-omitting view so secret-bearing env/header values are never returned. McpTransportView: description: MCP server transport configuration returned by catalog read APIs. oneOf: - $ref: "#/components/schemas/McpTransportViewStdio" - $ref: "#/components/schemas/McpTransportViewHttp" - $ref: "#/components/schemas/McpTransportViewSandbox" discriminator: propertyName: type mapping: stdio: "#/components/schemas/McpTransportViewStdio" http: "#/components/schemas/McpTransportViewHttp" sandbox: "#/components/schemas/McpTransportViewSandbox" McpTransportViewStdio: description: Stdio transport view. Environment variable values are omitted. type: object additionalProperties: false required: [type, command, env_keys] properties: type: type: string enum: [stdio] command: type: array minItems: 1 description: Command and arguments used to launch the MCP server. items: type: string env_keys: type: array description: Environment variable names configured for this transport. items: type: string McpTransportViewHttp: description: HTTP transport view. Header values are omitted. type: object additionalProperties: false required: [type, url, header_keys] properties: type: type: string enum: [http] protocol: $ref: "#/components/schemas/McpHttpProtocol" url: type: string format: uri header_keys: type: array description: HTTP header names configured for this transport. items: type: string McpTransportViewSandbox: description: Sandbox transport view. Environment variable values are omitted. type: object additionalProperties: false required: [type, command, port, env_keys] properties: type: type: string enum: [sandbox] protocol: $ref: "#/components/schemas/McpHttpProtocol" command: type: array minItems: 1 description: Command and arguments used to launch the in-sandbox MCP server. items: type: string port: type: integer format: int32 minimum: 1 maximum: 65535 env_keys: type: array description: Environment variable names configured for this transport. items: type: string McpServerListResponse: description: List envelope for MCP server definitions. type: object additionalProperties: false required: - data - meta properties: data: type: array items: $ref: "#/components/schemas/McpServer" meta: $ref: "#/components/schemas/McpServerListMeta" McpServerListMeta: description: Metadata for MCP server list responses. type: object additionalProperties: false required: - total properties: total: type: integer format: int64 minimum: 0 description: Total number of server-managed MCP server definitions. # ── Environments ───────────────────────────────────────────────────── Environment: description: Public server-managed environment definition. type: object additionalProperties: false required: - id - revision - provider - image - resources - network - lifecycle - labels - env properties: id: type: string pattern: "^[a-z0-9][a-z0-9-]{0,62}$" example: docker revision: type: string pattern: "^[0-9a-f]{64}$" description: Stable revision used with `If-Match` for optimistic concurrency. example: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef provider: $ref: "#/components/schemas/SandboxProviderKind" cwd: type: ["string", "null"] description: Local-provider command working directory for this environment. Docker and Daytona ignore this value. example: /srv/fabro/workspaces/team-a image: $ref: "#/components/schemas/EnvironmentApiImageSettings" resources: $ref: "#/components/schemas/EnvironmentResourcesSettings" network: $ref: "#/components/schemas/EnvironmentNetworkSettings" lifecycle: $ref: "#/components/schemas/EnvironmentLifecycleSettings" labels: $ref: "#/components/schemas/StringMap" env: type: object additionalProperties: $ref: "#/components/schemas/InterpString" CreateEnvironmentRequest: description: Request body for creating a server-managed environment. type: object additionalProperties: false required: - id - provider - image - resources - network - lifecycle - labels - env properties: id: type: string pattern: "^[a-z0-9][a-z0-9-]{0,62}$" example: docker provider: $ref: "#/components/schemas/SandboxProviderKind" cwd: type: ["string", "null"] description: Local-provider command working directory for this environment. Docker and Daytona ignore this value. example: /srv/fabro/workspaces/team-a image: $ref: "#/components/schemas/EnvironmentApiImageSettings" resources: $ref: "#/components/schemas/EnvironmentResourcesSettings" network: $ref: "#/components/schemas/EnvironmentNetworkSettings" lifecycle: $ref: "#/components/schemas/EnvironmentLifecycleSettings" labels: $ref: "#/components/schemas/StringMap" env: type: object additionalProperties: $ref: "#/components/schemas/InterpString" ReplaceEnvironmentRequest: description: Request body for replacing a server-managed environment. The path id is authoritative. type: object additionalProperties: false required: - provider - image - resources - network - lifecycle - labels - env properties: provider: $ref: "#/components/schemas/SandboxProviderKind" cwd: type: ["string", "null"] description: Local-provider command working directory for this environment. Docker and Daytona ignore this value. example: /srv/fabro/workspaces/team-a image: $ref: "#/components/schemas/EnvironmentApiImageSettings" resources: $ref: "#/components/schemas/EnvironmentResourcesSettings" network: $ref: "#/components/schemas/EnvironmentNetworkSettings" lifecycle: $ref: "#/components/schemas/EnvironmentLifecycleSettings" labels: $ref: "#/components/schemas/StringMap" env: type: object additionalProperties: $ref: "#/components/schemas/InterpString" EnvironmentApiImageSettings: description: REST-safe environment image settings. Dockerfile sources are inline-only; local paths are rejected by the REST API. type: object additionalProperties: false required: [docker, dockerfile] properties: docker: type: ["string", "null"] dockerfile: oneOf: - $ref: "#/components/schemas/EnvironmentApiDockerfileSourceInline" - type: "null" EnvironmentApiDockerfileSourceInline: type: object additionalProperties: false required: [type, value] properties: type: type: string enum: [inline] value: type: string EnvironmentListResponse: description: List envelope for environment definitions. type: object additionalProperties: false required: - data - meta properties: data: type: array items: $ref: "#/components/schemas/Environment" meta: $ref: "#/components/schemas/EnvironmentListMeta" EnvironmentListMeta: description: Metadata for environment list responses. type: object additionalProperties: false required: - total properties: total: type: integer format: int64 minimum: 0 description: Total number of server-managed environment definitions. # ── Pagination ─────────────────────────────────────────────────────── PaginationMeta: description: Pagination metadata included in every paginated response. type: object required: - has_more properties: has_more: type: boolean description: Whether additional pages of results are available. total: type: integer format: int64 minimum: 0 description: | Total number of items matching the current filters. Optional — only populated by endpoints that compute the full count cheaply (e.g. in-memory filtering). When omitted, clients should rely on `has_more` and cursor through pages. example: true PaginatedRunList: description: Paginated list of runs. type: object required: - data - meta properties: data: type: array items: $ref: "#/components/schemas/Run" meta: $ref: "#/components/schemas/PaginationMeta" BatchRunLifecycleRequest: description: Run IDs to archive or unarchive as one bounded fail-soft batch. type: object additionalProperties: false required: - run_ids properties: run_ids: type: array description: Run IDs to process, in result order. minItems: 1 maxItems: 250 uniqueItems: true items: type: string example: 01HZX6M29F1CD5YYMHT1F5D7WQ BatchRunLifecycleResponse: description: Per-run results for a fail-soft batch archive or unarchive request. type: object additionalProperties: false required: - results - summary properties: results: type: array description: Results ordered exactly like the request `run_ids`. items: $ref: "#/components/schemas/BatchRunLifecycleResult" summary: $ref: "#/components/schemas/BatchRunLifecycleSummary" BatchRunLifecycleResult: description: Result for one run in a batch archive or unarchive request. type: object additionalProperties: false required: - run_id - ok - outcome properties: run_id: type: string description: Run ID from the request item. ok: type: boolean description: Whether this item succeeded. outcome: type: string enum: - archived - already_archived - unarchived - not_archived - not_found - conflict - error description: Machine-readable item outcome. run: $ref: "#/components/schemas/Run" description: Decorated run summary for successful items when it can be loaded. error: $ref: "#/components/schemas/ErrorResponseEntry" description: Structured item error for failed items. BatchRunLifecycleSummary: description: Aggregate counts for a batch archive or unarchive request. type: object additionalProperties: false required: - requested - succeeded - failed properties: requested: type: integer minimum: 0 description: Number of requested run IDs. succeeded: type: integer minimum: 0 description: Number of item results with `ok=true`. failed: type: integer minimum: 0 description: Number of item results with `ok=false`. BatchDeleteRunsRequest: description: Run IDs to delete as one bounded fail-soft batch. type: object additionalProperties: false required: - run_ids properties: run_ids: type: array description: Run IDs to process, in result order. minItems: 1 maxItems: 250 uniqueItems: true items: type: string example: 01HZX6M29F1CD5YYMHT1F5D7WQ force: type: boolean description: Whether to force deletion of active runs. Defaults to `false`. default: false BatchDeleteRunsResponse: description: Per-run results for a fail-soft batch delete request. type: object additionalProperties: false required: - results - summary properties: results: type: array description: Results ordered exactly like the request `run_ids`. items: $ref: "#/components/schemas/BatchDeleteRunsResult" summary: $ref: "#/components/schemas/BatchDeleteRunsSummary" BatchDeleteRunsResult: description: Result for one run in a batch delete request. type: object additionalProperties: false required: - run_id - ok - outcome properties: run_id: type: string description: Run ID from the request item. ok: type: boolean description: Whether this item succeeded. outcome: type: string enum: - deleted - already_absent - sandbox_preserved - conflict - error description: Machine-readable item outcome. sandbox: $ref: "#/components/schemas/DeleteRunSandbox" description: Sandbox handoff details when `outcome` is `sandbox_preserved`. error: $ref: "#/components/schemas/ErrorResponseEntry" description: Structured item error for failed items. BatchDeleteRunsSummary: description: Aggregate counts for a batch delete request. type: object additionalProperties: false required: - requested - succeeded - failed properties: requested: type: integer minimum: 0 description: Number of requested run IDs. succeeded: type: integer minimum: 0 description: Number of item results with `ok=true`. failed: type: integer minimum: 0 description: Number of item results with `ok=false`. PairId: type: string description: Durable run pair identifier. example: 01HZX6M29F1CD5YYMHT1F5D7WQ PairMessageId: type: string description: Durable pair message identifier. example: 01HZX6M4D7Y1QW0Q0P6V8Z4DR5 PairStatus: type: string enum: [active, ended, failed] PairTarget: type: object additionalProperties: false required: - stage_id - node_label properties: stage_id: type: string example: code@1 node_label: type: string example: Code PairRecord: type: object required: - pair_id - run_id - status - started_at - target properties: pair_id: $ref: "#/components/schemas/PairId" run_id: type: string status: $ref: "#/components/schemas/PairStatus" started_at: type: string format: date-time ended_at: type: ["string", "null"] format: date-time failure_reason: type: ["string", "null"] target: $ref: "#/components/schemas/PairTarget" RunPairStatusResponse: type: object required: - run_id - targets properties: run_id: type: string current_pair: oneOf: - $ref: "#/components/schemas/PairRecord" - type: "null" targets: type: array items: $ref: "#/components/schemas/PairTarget" PairStartRequest: type: object additionalProperties: false required: - stage_id properties: stage_id: type: string example: code@1 PairMessageRequest: type: object required: - text properties: text: type: string minLength: 1 maxLength: 8192 client_message_id: type: string PairMessageRecord: type: object required: - message_id - pair_id - run_id - stage_id - text - accepted_at properties: message_id: $ref: "#/components/schemas/PairMessageId" client_message_id: type: ["string", "null"] pair_id: $ref: "#/components/schemas/PairId" run_id: type: string stage_id: type: string example: code@1 text: type: string accepted_at: type: string format: date-time PairTranscriptResponse: type: object required: - data - meta properties: data: type: array items: $ref: "#/components/schemas/PairTranscriptEntry" meta: type: object required: - next_since_seq - has_more properties: next_since_seq: type: integer minimum: 1 has_more: type: boolean PairTranscriptEntry: oneOf: - $ref: "#/components/schemas/PairTranscriptUserMessage" - $ref: "#/components/schemas/PairTranscriptSystemMessage" - $ref: "#/components/schemas/PairTranscriptAssistantMessage" - $ref: "#/components/schemas/PairTranscriptToolCall" - $ref: "#/components/schemas/PairTranscriptError" - $ref: "#/components/schemas/PairTranscriptWarning" discriminator: propertyName: kind PairTranscriptUserMessage: type: object required: [kind, seq, event_id, ts, pair_id, target, message_id, text] properties: kind: type: string enum: [user_message] seq: type: integer minimum: 1 event_id: type: string ts: type: string format: date-time pair_id: $ref: "#/components/schemas/PairId" target: $ref: "#/components/schemas/PairTarget" message_id: $ref: "#/components/schemas/PairMessageId" client_message_id: type: ["string", "null"] text: type: string PairTranscriptSystemMessage: type: object required: [kind, seq, event_id, ts, pair_id, target, system_message_kind, text] properties: kind: type: string enum: [system_message] seq: type: integer minimum: 1 event_id: type: string ts: type: string format: date-time pair_id: $ref: "#/components/schemas/PairId" target: $ref: "#/components/schemas/PairTarget" system_message_kind: type: string enum: [human_joined, human_left] text: type: string PairTranscriptAssistantMessage: type: object additionalProperties: false required: - kind - seq - event_id - ts - pair_id - target - text - tool_call_count properties: kind: type: string enum: [assistant_message] seq: type: integer format: uint32 event_id: type: string ts: type: string format: date-time pair_id: $ref: "#/components/schemas/PairId" target: $ref: "#/components/schemas/PairTarget" text: type: string tool_call_count: type: integer minimum: 0 PairTranscriptToolCall: type: object required: [kind, seq, event_id, ts, pair_id, target, tool_call_id, tool_name, status, summary, is_error, truncated, detail_ref] properties: kind: type: string enum: [tool_call] seq: type: integer minimum: 1 event_id: type: string ts: type: string format: date-time pair_id: $ref: "#/components/schemas/PairId" target: $ref: "#/components/schemas/PairTarget" tool_call_id: type: string tool_name: type: string status: type: string enum: [started, completed] summary: type: string is_error: type: boolean truncated: type: boolean detail_ref: $ref: "#/components/schemas/PairTranscriptDetailRef" PairTranscriptError: type: object required: [kind, seq, event_id, ts, pair_id, target, message, detail_ref] properties: kind: type: string enum: [error] seq: type: integer minimum: 1 event_id: type: string ts: type: string format: date-time pair_id: $ref: "#/components/schemas/PairId" target: $ref: "#/components/schemas/PairTarget" message: type: string detail_ref: $ref: "#/components/schemas/PairTranscriptDetailRef" PairTranscriptWarning: type: object required: [kind, seq, event_id, ts, pair_id, target, warning_kind, message, detail_ref] properties: kind: type: string enum: [warning] seq: type: integer minimum: 1 event_id: type: string ts: type: string format: date-time pair_id: $ref: "#/components/schemas/PairId" target: $ref: "#/components/schemas/PairTarget" warning_kind: type: string message: type: string detail_ref: $ref: "#/components/schemas/PairTranscriptDetailRef" PairTranscriptDetailRef: type: object required: [seq] properties: seq: type: integer minimum: 1 tool_call_id: type: string SessionId: description: Durable session identifier. type: string example: 01HZX6M0P7SE4VJ9Y3X2B8E9QF TurnId: description: Durable session turn identifier. type: string example: 01HZX6M29F1CD5YYMHT1F5D7WQ SessionStatus: type: string enum: [idle, running, failed] PermissionLevel: description: Agent tool permission level applied to a session. type: string enum: [read-only, read-write, full] SessionTurn: description: Currently active durable session turn. type: object required: - id - started_at - input properties: id: $ref: "#/components/schemas/TurnId" started_at: type: string format: date-time input: type: string RunSessionMetadata: description: Ask Fabro session metadata derived from the owning run event stream. type: object required: - id - run_id - status - active_turn - created_at - updated_at properties: id: $ref: "#/components/schemas/SessionId" run_id: type: string title: type: ["string", "null"] status: $ref: "#/components/schemas/SessionStatus" model: type: ["string", "null"] description: Canonical model ID selected when the session was created. provider: oneOf: - $ref: "#/components/schemas/ProviderId" - type: "null" description: Provider selected when the session was created. active_turn: oneOf: - $ref: "#/components/schemas/SessionTurn" - type: "null" created_at: type: string format: date-time updated_at: type: string format: date-time SessionSummary: description: List projection of an Ask Fabro session. type: object required: - id - run_id - status - active_turn - created_at - updated_at properties: id: $ref: "#/components/schemas/SessionId" run_id: type: string title: type: ["string", "null"] status: $ref: "#/components/schemas/SessionStatus" model: type: ["string", "null"] description: Canonical model ID selected when the session was created. provider: oneOf: - $ref: "#/components/schemas/ProviderId" - type: "null" description: Provider selected when the session was created. active_turn: oneOf: - $ref: "#/components/schemas/SessionTurn" - type: "null" created_at: type: string format: date-time updated_at: type: string format: date-time SessionDetail: description: >- Session metadata plus the sequence number of the session's latest event. The conversation itself is held by the server's durable session record and is not returned over the API. type: object required: - id - run_id - status - active_turn - created_at - updated_at - last_seq properties: id: $ref: "#/components/schemas/SessionId" run_id: type: string title: type: ["string", "null"] status: $ref: "#/components/schemas/SessionStatus" model: type: ["string", "null"] description: Canonical model ID selected when the session was created. provider: oneOf: - $ref: "#/components/schemas/ProviderId" - type: "null" description: Provider selected when the session was created. active_turn: oneOf: - $ref: "#/components/schemas/SessionTurn" - type: "null" created_at: type: string format: date-time updated_at: type: string format: date-time last_seq: type: integer minimum: 0 CreateRunSessionRequest: type: object properties: title: type: string model: type: string description: | Catalog model ID or alias, optionally qualified as `provider:selector`. A provider-qualified selector may be a canonical model ID, alias, or provider API ID. A value counts as qualified only when the text before the first `:` names a known provider, so model IDs containing a colon stay whole. Legacy `provider/model` references remain accepted. The server stores the canonical model ID. provider: $ref: "#/components/schemas/ProviderId" description: Optional provider pin. Provider-qualified model references remain accepted for compatibility. SubmitTurnRequest: type: object required: - input properties: input: type: string turn_id: $ref: "#/components/schemas/TurnId" PaginatedSessionList: description: Paginated list of sessions. type: object required: - data - meta properties: data: type: array items: $ref: "#/components/schemas/SessionSummary" meta: $ref: "#/components/schemas/PaginationMeta" SessionEventName: description: What a session event records. type: string enum: - run.session.created - run.session.turn.started - run.session.user_message - run.session.assistant_delta - run.session.assistant_message - run.session.tool_call.started - run.session.tool_call.completed - run.session.turn.succeeded - run.session.turn.failed - run.session.turn.interrupted SessionEvent: description: >- One recorded event of an Ask Fabro session: its position in the session (`seq`, from 1), the session and run it belongs to, when it was recorded, the event's name and its properties. Every event but `run.session.created` carries the `turn_id` it belongs to in its properties. type: object required: - seq - session_id - run_id - ts - event - properties properties: seq: type: integer minimum: 1 session_id: $ref: "#/components/schemas/SessionId" run_id: type: string ts: type: string format: date-time event: $ref: "#/components/schemas/SessionEventName" properties: type: object additionalProperties: true PaginatedSessionEventList: description: A page of a session's events, in sequence order. type: object required: - data - meta properties: data: type: array items: $ref: "#/components/schemas/SessionEvent" meta: $ref: "#/components/schemas/PaginationMeta" WorkflowScheduleSummary: description: Workflow schedule summary shown in workflow lists. type: object required: - expression properties: expression: type: string next_run: type: ["string", "null"] format: date-time WorkflowLastRunSummary: description: Most recent run timestamp for a workflow. type: object properties: ran_at: type: ["string", "null"] format: date-time WorkflowListItem: description: Workflow summary shown in workflow list pages. type: object required: - name - slug - filename properties: name: type: string slug: type: string filename: type: string last_run: oneOf: - $ref: "#/components/schemas/WorkflowLastRunSummary" - type: "null" schedule: oneOf: - $ref: "#/components/schemas/WorkflowScheduleSummary" - type: "null" PaginatedWorkflowListResponse: description: Paginated list of workflows. type: object required: - data properties: data: type: array items: $ref: "#/components/schemas/WorkflowListItem" pagination: $ref: "#/components/schemas/PaginationMeta" WorkflowDetailResponse: description: Workflow definition and dense settings snapshot. type: object required: - name - slug - description - filename - settings - graph properties: name: type: string slug: type: string description: type: string filename: type: string settings: $ref: "#/components/schemas/WorkflowSettings" graph: type: string PaginatedModelList: description: Paginated list of models. type: object required: - data - meta properties: data: type: array items: $ref: "#/components/schemas/Model" meta: $ref: "#/components/schemas/PaginationMeta" ProviderList: description: List of LLM providers from the catalog. type: object required: - data properties: data: type: array items: $ref: "#/components/schemas/Provider" ProviderCredentialTestRequest: description: API key to validate against an LLM provider without persisting it. type: object required: - api_key properties: api_key: type: string ProviderCredentialTestResponse: description: Successful response from provider credential validation. type: object required: - ok properties: ok: type: boolean example: true ProviderTestList: description: Results from testing all configured LLM providers. type: object required: - data - summary properties: data: type: array items: $ref: "#/components/schemas/ProviderTestResult" summary: $ref: "#/components/schemas/ProviderTestSummary" ProviderTestResult: description: Result of testing one configured LLM provider. type: object required: - provider - model_id - status - error_message properties: provider: $ref: "#/components/schemas/ProviderId" model_id: type: ["string", "null"] description: Catalog probe model ID used for the provider, or null when no probe was sent. example: "gpt-5.4-mini" status: $ref: "#/components/schemas/ProviderTestStatus" error_message: type: ["string", "null"] description: Error details when status is "error". ProviderTestSummary: description: Aggregate provider test status and counts. type: object required: - status - total - passed - failed properties: status: $ref: "#/components/schemas/ProviderTestStatus" total: type: integer format: int32 minimum: 0 description: Number of configured providers tested or evaluated. passed: type: integer format: int32 minimum: 0 description: Number of providers whose probe succeeded. failed: type: integer format: int32 minimum: 0 description: Number of providers with configuration, auth, registration, or probe errors. ProviderTestStatus: description: Provider test status. type: string enum: - ok - error Provider: description: An LLM provider from the catalog with effective config and configured status. type: object required: - id - display_name - adapter - base_url - priority - model_count - configured properties: id: $ref: "#/components/schemas/ProviderId" display_name: type: string description: Human-readable provider name. example: "Anthropic" adapter: type: string description: "lithos adapter id the provider uses: `http` or `bedrock`, or a custom adapter's id." example: "http" base_url: type: string description: Effective API base URL, including any operator override. example: "https://api.anthropic.com" api_key_url: type: ["string", "null"] description: URL where an operator can obtain an API key for this provider. priority: type: integer format: int32 description: Catalog ordering priority; higher sorts first. aliases: type: array items: type: string description: Alternative identifiers that resolve to this provider. model_count: type: integer format: int32 minimum: 0 description: Number of catalog models belonging to this provider. default_model: type: ["string", "null"] description: Catalog default model ID for this provider, if any. configured: type: boolean description: | Whether credential material is present for this provider on the server when this response was produced. Does NOT imply requests will succeed. expected_secret_name: type: ["string", "null"] description: | Suggested vault secret name for configuring this provider, derived from the first vault credential reference in the provider catalog. Null when the provider has no vault credential (e.g. no-auth or env-only providers). Used to prefill the create-secret form. ProviderId: description: LLM provider identifier. type: string example: anthropic ModelLimits: description: Token limits for a model. type: object required: - context_window - max_output properties: context_window: type: integer format: int64 description: Maximum context window size in tokens. example: 1000000 max_output: type: ["integer", "null"] format: int64 description: Maximum output tokens, if known. example: 128000 ReasoningEffort: description: Native reasoning-effort level requested for an LLM call. type: string enum: - minimal - low - medium - high - xhigh - max ModelFeatures: description: "Capability flags for a model, from the lithos catalog." type: object required: - tools - vision - reasoning - prompt_cache - sampling properties: tools: type: boolean description: Whether the model supports tool use. vision: type: boolean description: Whether the model supports image inputs. reasoning: type: boolean description: Whether the model supports extended reasoning. prompt_cache: type: boolean description: Whether the model endpoint supports prompt caching. sampling: type: boolean description: Whether the model accepts classic sampling parameters (temperature, top_p). ModelCosts: description: Pricing per million tokens in USD. type: object required: - input_cost_per_mtok - output_cost_per_mtok - cache_input_cost_per_mtok properties: input_cost_per_mtok: type: ["number", "null"] format: double description: Cost per million input tokens in USD. example: 15.0 output_cost_per_mtok: type: ["number", "null"] format: double description: Cost per million output tokens in USD. example: 75.0 cache_input_cost_per_mtok: type: ["number", "null"] format: double description: Cost per million cached input tokens in USD. example: 1.50 ModelControls: description: Request-control values accepted by a provider/model offering. type: object required: - reasoning_effort properties: reasoning_effort: type: array description: >- Exact reasoning-effort values accepted by this offering. An empty array means the request control is unsupported. items: $ref: "#/components/schemas/ReasoningEffort" Model: description: | One provider's offering of an LLM model. The `id` is unique within `provider`; `(provider, id)` is the stable resource identity. type: object required: - id - provider - family - display_name - limits - training - knowledge_cutoff - features - controls - costs - estimated_output_tps - aliases - default - small_default - configured properties: id: type: string description: Canonical human-facing model ID, unique within the provider. example: "claude-opus-4-6" provider: $ref: "#/components/schemas/ProviderId" family: type: string description: Model family grouping. example: "claude-4" display_name: type: string description: Human-readable model name. example: "Claude Opus 4.6" limits: $ref: "#/components/schemas/ModelLimits" training: type: ["string", "null"] description: Training data cutoff date (YYYY-MM-DD). example: "2025-08-01" knowledge_cutoff: type: ["string", "null"] description: Public knowledge cutoff label, if known. example: "May 2025" features: $ref: "#/components/schemas/ModelFeatures" controls: $ref: "#/components/schemas/ModelControls" costs: $ref: "#/components/schemas/ModelCosts" estimated_output_tps: type: ["number", "null"] format: double description: Estimated output tokens per second. aliases: type: array items: type: string description: Alternative names that resolve to this model. example: ["opus"] default: type: boolean description: Whether this is the default model for its provider. small_default: type: boolean description: Whether this is the provider's small/default utility model. configured: type: boolean description: | Whether credential material is present for this model's provider on the server (vault entry or environment variable). Does NOT imply the credential is valid or that requests will succeed; call `POST /models/{id}/test` to verify usability. ModelTestResult: description: Result of testing a model in `basic` or `deep` mode. type: object required: - model_id - provider - status properties: model_id: type: string description: The canonical model ID that was tested. example: "claude-opus-4-6" provider: $ref: "#/components/schemas/ProviderId" status: type: string enum: - ok - error - skip description: Whether the model responded successfully, failed, or was skipped because its provider is not configured. error_message: type: ["string", "null"] description: Error details when status is "error". ModelTestMode: description: Single-model test mode. type: string enum: - basic - deep # ── Completion Schemas ───────────────────────────────────────────── CompletionMessage: description: "A lithos `Message`. `content` parts are discriminated by `type`." type: object required: [role, content] properties: role: type: string enum: [system, developer, user, assistant, tool] description: The role of the message author. content: type: array description: Content parts of the message. items: $ref: "#/components/schemas/CompletionContentPart" name: type: string description: Optional name for the message author. tool_call_id: type: string description: Tool call ID for tool result messages. CompletionContentPart: description: >- A lithos `ContentPart`, discriminated by `type`: `text` ({text}), `image`, `audio`, `document` ({source, ...}), `reasoning` ({text, signature, redacted}), `tool_call` ({id, name, input}), `tool_result` ({tool_call_id, content, is_error}), `json` ({value}), and `opaque` ({kind, data}). type: object required: [type] properties: type: type: string description: Content part type. additionalProperties: true CompletionToolDefinition: description: >- A lithos `ToolDefinition`. `kind` is `{type: function, input_schema}` for JSON-argument tools or `{type: custom, format}` for free-form input. type: object required: [name, description, kind] properties: name: type: string description: Tool name. description: type: string description: Human-readable tool description. kind: $ref: "#/components/schemas/CompletionToolDefinitionKind" CompletionToolDefinitionKind: description: >- lithos `ToolDefinitionKind`: `{type: function, input_schema}` for JSON-argument tools or `{type: custom, format}` for free-form input. type: object required: [type] properties: type: type: string enum: [function, custom] additionalProperties: true CompletionResponseFormat: description: >- lithos `ResponseFormat`, discriminated by `type`: `text`, `json_object`, or `json_schema` ({name, schema}). type: object required: [type] properties: type: type: string enum: [text, json_object, json_schema] additionalProperties: true CompletionToolChoice: description: "A lithos `ToolChoice`, discriminated by `type`." type: object required: [type] properties: type: type: string enum: [auto, none, required, tool] description: Tool selection mode. name: type: string description: Required when type is `tool`. CreateCompletionRequest: description: >- A lithos `Request` plus `stream`. Field names match the lithos wire form so a serialized lithos request can be posted as-is. type: object required: [messages] properties: messages: type: array description: The conversation messages. items: $ref: "#/components/schemas/CompletionMessage" model: type: string description: >- Model selector: `provider/model`, a model id or alias, or a provider id. The server picks a ready-provider default when omitted. provider: type: string description: Optional provider pin for a bare model selector. system: type: string description: System prompt (convenience; prepended as a system message). stream: type: boolean default: true description: Stream response via SSE. tools: type: array description: Tool definitions available to the model. items: $ref: "#/components/schemas/CompletionToolDefinition" tool_choice: $ref: "#/components/schemas/CompletionToolChoice" response_format: $ref: "#/components/schemas/CompletionResponseFormat" schema: description: >- JSON Schema for structured output. Forces a non-streaming response whose `output` is the parsed object. max_output_tokens: type: integer format: int64 temperature: type: number format: double top_p: type: number format: double stop_sequences: type: array items: type: string description: Stop sequences. reasoning_effort: $ref: "#/components/schemas/ReasoningEffort" description: Reasoning effort level. speed: $ref: "#/components/schemas/Speed" description: Requested speed tier. metadata: type: object description: Request tags forwarded to providers that accept them. additionalProperties: type: string provider_options: type: object description: Raw provider options keyed by provider id. additionalProperties: true TokenCounts: description: > lithos `TokenCounts`: five disjoint token buckets. Every token is counted in exactly one, so their plain sum is the total. `input` excludes cache reads and writes, while `output` excludes reasoning tokens when the provider reports them separately. A bucket that is absent reads as zero. type: object properties: input: type: integer format: uint64 minimum: 0 default: 0 description: Prompt tokens that were neither read from nor written to a cache. output: type: integer format: uint64 minimum: 0 default: 0 description: Completion tokens that are not reasoning tokens. reasoning: type: integer format: uint64 minimum: 0 default: 0 description: Completion tokens spent on reasoning, priced at the output rate. cache_read: type: integer format: uint64 minimum: 0 default: 0 description: Prompt tokens served from a provider cache. cache_write: type: integer format: uint64 minimum: 0 default: 0 description: Prompt tokens written into a provider cache. ModelHandle: description: A resolved provider and model identity. type: object required: [provider, model] properties: provider: $ref: "#/components/schemas/ProviderId" model: type: string description: Canonical model id within the provider. Cost: description: "lithos `Cost`: a USD amount in micros and where it came from." type: object required: [usd_micros, source] properties: usd_micros: type: integer format: uint64 minimum: 0 source: $ref: "#/components/schemas/CostSource" Usage: description: >- lithos `Usage`: token counts and, when known, what they cost. `cost` is absent when there is no cost data, never zero. A sum has a cost only when every part that used tokens was priced; its `source` is the parts' shared source, or `application` when they differ. type: object required: [tokens] properties: tokens: $ref: "#/components/schemas/TokenCounts" cost: $ref: "#/components/schemas/Cost" ModelUsage: description: >- Usage grouped under one model: one response, or one model's share of a stage. type: object required: [model, usage] properties: model: $ref: "#/components/schemas/UsageModelRef" usage: $ref: "#/components/schemas/Usage" CompletionResponse: description: >- A lithos `Response`, returned verbatim. The server prices the response: `cost` is the catalog estimate or the provider's own figure. When the request carried `schema`, `output` holds the parsed object. type: object required: [model, content, finish_reason, usage] properties: output: description: Parsed structured output when `schema` was provided. id: type: ["string", "null"] model: $ref: "#/components/schemas/ModelHandle" content: type: array items: $ref: "#/components/schemas/CompletionContentPart" suppressed_tool_calls: type: array description: Tool calls withheld because the turn ended early. items: type: object additionalProperties: true finish_reason: type: string description: "Why generation stopped: stop, length, tool_call, content_filter, error, incomplete, or a provider-specific reason." usage: $ref: "#/components/schemas/TokenCounts" cost: $ref: "#/components/schemas/Cost" rate_limits: type: object additionalProperties: true warnings: type: array items: type: object required: [code, message] properties: code: type: string message: type: string raw: description: The provider's success payload, when available. CostSource: type: string description: > Where a cost came from: `catalog` (estimated from catalog prices), `provider` (the provider's own reported cost), or `application` (a sum the caller assembled from differently sourced parts). enum: [catalog, provider, application] PaginatedSavedQueryList: description: Paginated list of saved queries. type: object required: - data - meta properties: data: type: array items: $ref: "#/components/schemas/SavedQuery" meta: $ref: "#/components/schemas/PaginationMeta" PaginatedHistoryEntryList: description: Paginated list of query history entries. type: object required: - data - meta properties: data: type: array items: $ref: "#/components/schemas/HistoryEntry" meta: $ref: "#/components/schemas/PaginationMeta" PaginatedApiQuestionList: description: Paginated list of pending questions. type: object required: - data - meta properties: data: type: array items: $ref: "#/components/schemas/ApiQuestion" meta: $ref: "#/components/schemas/PaginationMeta" PaginatedRunStageList: description: Paginated list of run stages. type: object required: - data - meta properties: data: type: array items: $ref: "#/components/schemas/RunStage" meta: $ref: "#/components/schemas/PaginationMeta" # ── Run Schemas ────────────────────────────────────────────────────── RunStatus: description: > Execution status of a run. Archive state is represented separately on `RunLifecycle.archived` so terminal status payloads remain intact. oneOf: - $ref: "#/components/schemas/RunStatusSubmitted" - $ref: "#/components/schemas/RunStatusPending" - $ref: "#/components/schemas/RunStatusRunnable" - $ref: "#/components/schemas/RunStatusStarting" - $ref: "#/components/schemas/RunStatusRunning" - $ref: "#/components/schemas/RunStatusBlocked" - $ref: "#/components/schemas/RunStatusPaused" - $ref: "#/components/schemas/RunStatusRemoving" - $ref: "#/components/schemas/RunStatusSucceeded" - $ref: "#/components/schemas/RunStatusFailed" - $ref: "#/components/schemas/RunStatusDead" discriminator: propertyName: kind mapping: submitted: "#/components/schemas/RunStatusSubmitted" pending: "#/components/schemas/RunStatusPending" runnable: "#/components/schemas/RunStatusRunnable" starting: "#/components/schemas/RunStatusStarting" running: "#/components/schemas/RunStatusRunning" blocked: "#/components/schemas/RunStatusBlocked" paused: "#/components/schemas/RunStatusPaused" removing: "#/components/schemas/RunStatusRemoving" succeeded: "#/components/schemas/RunStatusSucceeded" failed: "#/components/schemas/RunStatusFailed" dead: "#/components/schemas/RunStatusDead" RunStatusSubmitted: type: object required: - kind properties: kind: type: string enum: - submitted RunStatusPending: type: object required: - kind - reason properties: kind: type: string enum: - pending reason: $ref: "#/components/schemas/PendingReason" RunStatusRunnable: type: object required: - kind properties: kind: type: string enum: - runnable RunStatusStarting: type: object required: - kind properties: kind: type: string enum: - starting RunStatusRunning: type: object required: - kind properties: kind: type: string enum: - running RunStatusBlocked: type: object required: - kind - blocked_reason properties: kind: type: string enum: - blocked blocked_reason: $ref: "#/components/schemas/BlockedReason" RunStatusPaused: type: object required: - kind - prior_block properties: kind: type: string enum: - paused prior_block: oneOf: - $ref: "#/components/schemas/BlockedReason" - type: "null" RunStatusRemoving: type: object required: - kind properties: kind: type: string enum: - removing RunStatusSucceeded: type: object required: - kind - reason properties: kind: type: string enum: - succeeded reason: $ref: "#/components/schemas/SuccessReason" RunStatusFailed: type: object required: - kind - reason properties: kind: type: string enum: - failed reason: $ref: "#/components/schemas/FailureReason" RunStatusDead: type: object required: - kind properties: kind: type: string enum: - dead SuccessReason: description: Reason attached to a successful terminal run status. type: string enum: - completed - partial_success FailureReason: description: Reason attached to a failed terminal run status. type: string enum: - workflow_error - publish_failed - cancelled - approval_denied - terminated - transient_infra - budget_exhausted - launch_failed - bootstrap_failed - sandbox_init_failed PendingReason: description: Reason a pre-execution run is pending instead of runnable. type: string enum: - approval_required RunRunnableSource: description: Source that made a run runnable. type: string enum: - start_requested - approved FailureCategory: description: Product-level classification for grouping and retry policy. type: string enum: - transient_infra - deterministic - budget_exhausted - compilation_loop - canceled - structural FailureSignature: description: Stable normalized signature for grouping related failures. type: string ExecOutputTail: description: Redacted tail of command stdout/stderr captured for diagnostics. type: object properties: stdout: type: ["string", "null"] stderr: type: ["string", "null"] stdout_truncated: type: boolean default: false stderr_truncated: type: boolean default: false FailureDetail: description: Rich diagnostic detail for a failed stage or terminal run. type: object required: - message - category properties: message: type: string causes: type: array items: type: string category: $ref: "#/components/schemas/FailureCategory" system_actor: oneOf: - $ref: "#/components/schemas/SystemActorKind" - type: "null" signature: oneOf: - $ref: "#/components/schemas/FailureSignature" - type: "null" exec_output_tail: oneOf: - $ref: "#/components/schemas/ExecOutputTail" - type: "null" RunFailure: description: Terminal run failure reason and rich diagnostics. type: object required: - reason - detail properties: reason: $ref: "#/components/schemas/FailureReason" detail: $ref: "#/components/schemas/FailureDetail" WorkflowPath: description: >- Canonical portable path inside one workflow version. Paths are UTF-8, relative, at most 240 bytes and 16 components, and cannot contain empty, dot, parent, backslash, control, tilde-root, or drive-letter segments. Map keys receive stricter byte and structural validation in the domain model than OpenAPI can express. type: string minLength: 1 maxLength: 240 example: graphs/main.fabro WorkflowVersionId: description: >- SHA-256 identity of validated canonical workflow-version bytes. Hex input is case-insensitive; Fabro emits the canonical lowercase form. type: string pattern: "^[0-9A-Fa-f]{64}$" example: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" WorkflowVersion: description: >- Complete immutable package for one rooted workflow. It contains at most 512 files and 512 workflow dependencies, each file is at most 512 KiB of UTF-8 content, and its compact canonical JSON representation is at most 2 MiB. type: object additionalProperties: false required: - entrypoint - files - workflow_dependencies properties: entrypoint: $ref: "#/components/schemas/WorkflowPath" files: type: object description: >- Workflow-local text files keyed by canonical path. Keys receive stricter domain validation than OpenAPI can express; each value is limited to 512 KiB of UTF-8 bytes. maxProperties: 512 propertyNames: $ref: "#/components/schemas/WorkflowPath" additionalProperties: type: string workflow_dependencies: type: object description: >- Exact stored workflow-version IDs keyed by resolved child-workflow path. Keys receive stricter domain validation than OpenAPI can express. maxProperties: 512 propertyNames: $ref: "#/components/schemas/WorkflowPath" additionalProperties: $ref: "#/components/schemas/WorkflowVersionId" CreateWorkflowVersionResponse: description: Identity of the stored immutable workflow version. type: object additionalProperties: false required: - workflow_version_id properties: workflow_version_id: $ref: "#/components/schemas/WorkflowVersionId" RunIntent: description: >- A request to create, but not start, one run from an immutable workflow version and an explicit workspace target. type: object additionalProperties: false required: - workflow_version_id - target - args properties: workflow_version_id: $ref: "#/components/schemas/WorkflowVersionId" target: $ref: "#/components/schemas/RunTarget" args: $ref: "#/components/schemas/RunIntentArgs" environment_id: type: string description: Server environment catalog ID. Omission selects `default`. parent_id: type: string description: Optional orchestration parent run ID. title: type: string maxLength: 100 description: Optional explicit run title, normalized by the server. goal: type: string description: Optional inline goal override. RunIntentArgs: description: Structured run overrides accepted by workflow-version creation. type: object additionalProperties: false properties: model: type: string provider: type: string description: LLM provider; this does not select the sandbox environment. inputs: type: object additionalProperties: anyOf: - type: string - type: number - type: integer - type: boolean labels: type: object additionalProperties: type: string dry_run: type: boolean description: >- Overrides `run.execution.mode`: true selects `dry_run`, false selects `normal`, and omission inherits the lower-precedence setting. auto_approve: type: boolean description: >- Overrides `run.execution.approval`: true selects `auto`, false selects `prompt`, and omission inherits the lower-precedence setting. preserve_sandbox: type: boolean description: >- Overrides `run.environment.lifecycle.preserve`; omission inherits the lower-precedence setting. RunTarget: description: Workspace content and location requested for a run. oneOf: - $ref: "#/components/schemas/GitRunTarget" - $ref: "#/components/schemas/NoneRunTarget" - $ref: "#/components/schemas/FolderRunTarget" discriminator: propertyName: kind mapping: git: "#/components/schemas/GitRunTarget" none: "#/components/schemas/NoneRunTarget" folder: "#/components/schemas/FolderRunTarget" GitRunTarget: description: >- Public github.com repository target. The branch names the attached working branch. An optional tag selects a release at worker start, and an optional exact SHA is authoritative when both are present. type: object additionalProperties: false required: - kind - repo - branch properties: kind: type: string enum: [git] repo: type: string description: GitHub repository slug in `owner/name` form. example: acme/my-app branch: type: string description: Required attached working branch name, preserved exactly. example: feature/foo tag: type: string minLength: 1 description: >- Optional bare tag name. Prefixes such as `refs/tags/` and `tags/` are rejected. Without `sha`, the worker resolves this tag when the sandbox starts and fails if it is unavailable. example: v1.2.3 sha: type: string pattern: "^[0-9A-Fa-f]{40}$" description: >- Optional exact commit. The server lowercase-normalizes its syntax but does not resolve it, prove branch ancestry, or prove that it matches an accompanying tag. When present, this exact commit wins. NoneRunTarget: description: >- Empty workspace with no repository. Docker and Daytona accept this target and suppress cloning even when workflow settings enable it. Local environments reject it; Local scratch allocation is a separate future capability. type: object additionalProperties: false required: - kind properties: kind: type: string enum: [none] FolderRunTarget: description: >- Existing directory on the Fabro server, executed in place by a Local environment. The submitted path must be absolute and name an existing directory; Fabro resolves symlinks and persists its canonical UTF-8 path. This target is intended for trusted single-tenant deployments. Docker and Daytona environments always reject it. This target does not add Local Git cloning or Local scratch workspaces. Folder runs execute in place without Fabro Git checkpoints, so fork and rewind are unavailable. type: object additionalProperties: false required: - kind - path properties: kind: type: string enum: [folder] path: type: string minLength: 1 description: Absolute path on the Fabro server, not on the API caller's machine. RunManifest: description: Self-contained workflow run manifest. type: object required: - version - cwd - target - workflows properties: version: type: integer description: Manifest schema version. example: 1 parent_id: type: ["string", "null"] description: Optional orchestration parent run ID. Fork and rewind lineage use separate fields and should not set this value. example: "01HV6D7S5YF4Z4B2M7K4N0Q6T8" title: type: ["string", "null"] maxLength: 100 description: Optional explicit run title. The server trims leading/trailing whitespace, rejects blank values, rejects control characters and newline characters, and requires at most 100 characters. example: "Add rate limiting to auth endpoints" cwd: type: string description: CLI working directory at invocation time. example: "/tmp/project" git: $ref: "#/components/schemas/GitContext" goal: $ref: "#/components/schemas/ManifestGoal" args: $ref: "#/components/schemas/ManifestArgs" target: $ref: "#/components/schemas/ManifestTarget" configs: type: array items: $ref: "#/components/schemas/ManifestConfig" workflows: type: object additionalProperties: $ref: "#/components/schemas/ManifestWorkflow" GitContext: description: Observable git state captured before the run starts. type: object required: - origin_url - branch - dirty properties: origin_url: type: string description: Remote origin URL with any embedded credentials removed. example: "https://github.com/acme/my-app.git" branch: type: string description: Current branch name. example: feature/foo sha: type: ["string", "null"] description: Current commit SHA, when known. example: abc123def dirty: $ref: "#/components/schemas/DirtyStatus" GitIdentitySource: description: Where a run's Git author/committer identity came from. type: string enum: - explicit - github_app - github_pat - default GitIdentity: description: > The Git author and committer identity a run resolved once and uses for every commit it creates: engine checkpoints, metadata commits, and any commit a workflow command or agent tool runs. type: object required: - name - email - source properties: name: type: string example: "fabro-sh[bot]" email: type: string example: "123456+fabro-sh[bot]@users.noreply.github.com" source: $ref: "#/components/schemas/GitIdentitySource" ManifestGoal: description: Resolved goal kind and content. type: object required: - type - text properties: type: type: string enum: - value - file - graph text: type: string description: Resolved goal content. ManifestArgs: description: Sparse command-local args that affect run settings. type: object properties: model: type: string provider: type: string environment: type: string description: Named environment slug to select for the run. verbose: type: boolean dry_run: type: boolean auto_approve: type: boolean preserve_sandbox: type: boolean label: type: array items: type: string input: type: array description: Raw repeated CLI input overrides, each in `KEY=VALUE` form. items: type: string ManifestTarget: type: object required: - path properties: path: type: string description: Resolved path that keys into the workflows map. example: .fabro/workflows/smoke/workflow.fabro ManifestConfig: type: object required: - type properties: type: type: string enum: - project - user path: type: ["string", "null"] source: type: ["string", "null"] ManifestWorkflowConfig: type: object required: - path - source properties: path: type: string source: type: string ManifestFileEntry: description: A bundled file with discovery metadata. type: object required: - content - ref properties: content: type: string ref: $ref: "#/components/schemas/ManifestFileRef" ManifestFileRef: type: object required: - type - original properties: type: type: string enum: - file_inline - import - dockerfile original: type: string from: type: ["string", "null"] ManifestWorkflow: type: object required: - source properties: source: type: string config: $ref: "#/components/schemas/ManifestWorkflowConfig" files: type: object additionalProperties: $ref: "#/components/schemas/ManifestFileEntry" PreflightResponse: type: object required: - ok - workflow - checks properties: ok: type: boolean description: Whether preflight passed using the CLI-compatible success rule. workflow: $ref: "#/components/schemas/PreflightWorkflowSummary" checks: $ref: "#/components/schemas/PreflightCheckReport" ValidateResponse: type: object required: - ok - workflow properties: ok: type: boolean description: Whether validation passed with no error diagnostics. workflow: $ref: "#/components/schemas/PreflightWorkflowSummary" RenderWorkflowGraphRequest: type: object required: - manifest properties: manifest: $ref: "#/components/schemas/RunManifest" format: $ref: "#/components/schemas/RenderWorkflowGraphFormat" direction: $ref: "#/components/schemas/RenderWorkflowGraphDirection" RenderWorkflowGraphFormat: type: string enum: - svg RenderWorkflowGraphDirection: type: string enum: - lr - tb PreflightWorkflowSummary: type: object required: - name - nodes - edges - goal - diagnostics properties: name: type: string graph_path: type: ["string", "null"] nodes: type: integer edges: type: integer goal: type: string diagnostics: type: array items: $ref: "#/components/schemas/WorkflowDiagnostic" WorkflowDiagnostic: description: | One diagnostic about a workflow. `rule` is the stable code of the check that raised it: Petri's codes (`attractor.*`, `unsupported.*`, `deprecated.*`, `info.*`, `fabro.hooks.*`) for the compile, and `fabro.model.no_ready_provider` for Fabro's own provider check. type: object required: - rule - severity - message properties: rule: type: string description: The stable code of the check that raised the diagnostic. severity: type: string enum: - error - warning - info message: type: string node_id: type: ["string", "null"] edge: type: ["array", "null"] minItems: 2 maxItems: 2 items: type: string fix: type: ["string", "null"] source_path: type: ["string", "null"] line: type: ["integer", "null"] format: int32 column: type: ["integer", "null"] format: int32 span_start: type: ["integer", "null"] format: int64 span_len: type: ["integer", "null"] format: int64 related: type: array items: $ref: "#/components/schemas/RelatedWorkflowDiagnostic" default: [] RelatedWorkflowDiagnostic: type: object required: - message properties: message: type: string source_path: type: ["string", "null"] line: type: ["integer", "null"] format: int32 column: type: ["integer", "null"] format: int32 PreflightCheckReport: type: object required: - title - sections properties: title: type: string sections: type: array items: $ref: "#/components/schemas/PreflightCheckSection" PreflightCheckSection: type: object required: - title - checks properties: title: type: string checks: type: array items: $ref: "#/components/schemas/PreflightCheckResult" PreflightCheckResult: type: object required: - name - status - summary - details properties: name: type: string status: type: string enum: - pass - warning - error summary: type: string details: type: array items: $ref: "#/components/schemas/PreflightCheckDetail" remediation: type: ["string", "null"] PreflightCheckDetail: type: object required: - text - warn properties: text: type: string warn: type: boolean SteerRunRequest: description: Request body for steering a running run mid-execution. type: object required: - text properties: text: type: string description: The steering message text to deliver as a user turn. minLength: 1 maxLength: 8192 example: Try a different approach interrupt: type: boolean description: | When true, stop the stage's current model turn first and make this text its next input, in one control. When false (default), the text is guidance the agent runs as a follow-up turn once its current answer is reached. default: false stage: type: string description: | The agent stage to steer: its stage identifier (`node_id@visit`) or its node name. Omit it to steer the run's one live agent stage; a run with several live agent stages then refuses the steer with a `run.notice` record. minLength: 1 maxLength: 200 example: code@2 RunControlAcknowledgement: description: | The worker's answer to a steer or an interrupt, as the endpoint's `202` body. type: object required: - outcome properties: outcome: $ref: "#/components/schemas/RunControlOutcome" stage: type: string description: >- The label of the stage the control was delivered to (`node@visit`, or `node/e@visit`); absent when the outcome is `pending`. RunControlOutcome: description: | What became of a forwarded control: `delivered` once the worker delivered it to its stage; `pending` when the worker gave no answer within the wait, in which case the run's event stream says what became of it (a `run.notice` record on refusal). type: string enum: - delivered - pending InterruptRunRequest: description: Request body for interrupting a live agent stage's model turn. type: object properties: stage: type: string description: | The agent stage to interrupt: its stage identifier (`node_id@visit`) or its node name. Omit it to interrupt the run's one live agent stage. minLength: 1 maxLength: 200 example: code@2 text: type: string description: | The stage's next input once its turn is stopped. Omit it to let the stage wait for the next steer message. minLength: 1 maxLength: 8192 example: Stop and summarize what you have so far. StartRunRequest: description: Request body for starting or resuming a run. type: object properties: resume: type: boolean description: Resume from checkpoint instead of starting from submitted state. default: false DenyRunRequest: description: Request body for denying a pending run approval request. type: object properties: reason: type: string description: Optional human-readable reason for denying execution. Empty or whitespace-only values are stored as absent. example: Not approved for execution UpdateRunRequest: description: Request body for updating mutable run metadata. type: object required: - title properties: title: type: string maxLength: 100 description: New run title. The server trims leading/trailing whitespace, rejects blank values, rejects control characters and newline characters, and requires at most 100 characters. example: "Add rate limiting to auth endpoints" DeleteRunResponse: description: Returned when a run is deleted but its sandbox is intentionally preserved. type: object required: [deleted, sandbox_preserved, sandbox] properties: deleted: type: boolean sandbox_preserved: type: boolean sandbox: $ref: "#/components/schemas/DeleteRunSandbox" DeleteRunSandbox: type: object required: [provider, id] properties: provider: $ref: "#/components/schemas/SandboxProviderKind" id: type: string ApiQuestion: description: A pending human-in-the-loop question generated by a workflow stage. type: object required: - id - text - stage - question_type - options - allow_freeform properties: id: type: string description: Unique question identifier. example: q-001 text: type: string description: The question text displayed to the user. example: Should we proceed with the proposed changes? stage: type: string description: Workflow stage identifier that produced the question. example: gate question_type: $ref: "#/components/schemas/QuestionType" options: type: array description: Available options for selection-based questions. Empty for freeform questions. items: $ref: "#/components/schemas/InterviewOption" allow_freeform: type: boolean description: Whether the user may provide freeform text in addition to selecting options. example: true timeout_seconds: type: ["number", "null"] format: double description: Timeout for the question when configured by the workflow. example: 30 context_display: type: ["string", "null"] description: Optional contextual text shown alongside the question. example: Latest draft review_target: description: Optional validated external resource that is the primary subject of this review question. oneOf: - $ref: "#/components/schemas/ReviewTarget" - type: "null" QuestionType: description: The interaction type of a human-in-the-loop question. type: string enum: - yes_no - multiple_choice - multi_select - freeform - confirmation SubmitAnswerRequest: description: > Request body for submitting an answer to a pending question. The `kind` discriminator determines which answer shape is submitted. oneOf: - $ref: "#/components/schemas/SubmitAnswerYesRequest" - $ref: "#/components/schemas/SubmitAnswerNoRequest" - $ref: "#/components/schemas/SubmitAnswerSelectedRequest" - $ref: "#/components/schemas/SubmitAnswerMultiSelectedRequest" - $ref: "#/components/schemas/SubmitAnswerTextRequest" discriminator: propertyName: kind mapping: "yes": "#/components/schemas/SubmitAnswerYesRequest" "no": "#/components/schemas/SubmitAnswerNoRequest" selected: "#/components/schemas/SubmitAnswerSelectedRequest" multi_selected: "#/components/schemas/SubmitAnswerMultiSelectedRequest" text: "#/components/schemas/SubmitAnswerTextRequest" SubmitAnswerYesRequest: type: object required: - kind properties: kind: type: string enum: ["yes"] description: Affirmative answer for yes/no and confirmation questions. SubmitAnswerNoRequest: type: object required: - kind properties: kind: type: string enum: ["no"] description: Negative answer for yes/no questions. SubmitAnswerSelectedRequest: type: object required: - kind - option_key properties: kind: type: string enum: [selected] description: Single selected option answer. option_key: type: string description: Key of the selected option. example: option_a SubmitAnswerMultiSelectedRequest: type: object required: - kind - option_keys properties: kind: type: string enum: [multi_selected] description: Multiple selected option answer. option_keys: type: array items: type: string description: Keys of selected options. example: ["option_a", "option_b"] SubmitAnswerTextRequest: type: object required: - kind - text properties: kind: type: string enum: [text] description: Freeform text answer. text: type: string description: Freeform answer text. example: "Yes, proceed with the changes." ErrorResponseEntry: description: A single error entry in an error response. type: object required: - status - title - detail properties: status: type: string description: HTTP status code as a string. example: "404" title: type: string description: Short error classification. example: Not Found detail: type: string description: Human-readable error description. example: Run not found. code: type: string description: Optional machine-readable error code for structured client handling. example: access_token_expired request_id: type: string format: uuid description: Server-generated request identifier; matches the x-request-id response header. meta: type: object additionalProperties: true description: >- Optional structured details specific to the error `code`, for clients that act on them. Each code documents the members it sets. ErrorResponse: description: Standard error response containing one or more error entries. type: object required: - errors properties: errors: type: array description: List of error entries. items: $ref: "#/components/schemas/ErrorResponseEntry" request_id: type: string format: uuid description: Server-generated request identifier; matches the x-request-id response header. leftover_env_keys: type: array description: >- Optional list of runtime env keys that were written before an install failure. Currently populated by `POST /install/finish` failure responses only. items: type: string removed_env_keys: type: array description: >- Optional list of runtime env keys that were actually removed before an install failure. Currently populated by `POST /install/finish` failure responses only. items: type: string AuthMethod: description: Runtime user authentication method. type: string enum: - github - dev_token SystemActorKind: type: string enum: - engine - watchdog - timeout IdpIdentity: type: object required: - issuer - subject properties: issuer: type: string subject: type: string RunServerProvenance: type: object required: - version properties: version: type: string RunClientProvenance: type: object properties: user_agent: type: string name: type: string version: type: string RunProvenance: type: object required: - subject properties: server: oneOf: - $ref: "#/components/schemas/RunServerProvenance" - type: "null" client: oneOf: - $ref: "#/components/schemas/RunClientProvenance" - type: "null" subject: $ref: "#/components/schemas/Principal" Principal: oneOf: - $ref: "#/components/schemas/PrincipalUser" - $ref: "#/components/schemas/PrincipalWorker" - $ref: "#/components/schemas/PrincipalWebhook" - $ref: "#/components/schemas/PrincipalSlack" - $ref: "#/components/schemas/PrincipalAgent" - $ref: "#/components/schemas/PrincipalSystem" discriminator: propertyName: kind mapping: user: "#/components/schemas/PrincipalUser" worker: "#/components/schemas/PrincipalWorker" webhook: "#/components/schemas/PrincipalWebhook" slack: "#/components/schemas/PrincipalSlack" agent: "#/components/schemas/PrincipalAgent" system: "#/components/schemas/PrincipalSystem" PrincipalUser: type: object required: - kind - identity - login - auth_method properties: kind: type: string enum: [user] identity: $ref: "#/components/schemas/IdpIdentity" login: type: string auth_method: $ref: "#/components/schemas/AuthMethod" avatar_url: type: ["string", "null"] PrincipalWorker: type: object required: - kind - run_id properties: kind: type: string enum: [worker] run_id: type: string PrincipalWebhook: type: object required: - kind - delivery_id properties: kind: type: string enum: [webhook] delivery_id: type: string PrincipalSlack: type: object required: - kind - team_id - user_id properties: kind: type: string enum: [slack] team_id: type: string user_id: type: string user_name: type: ["string", "null"] PrincipalAgent: type: object required: - kind properties: kind: type: string enum: [agent] session_id: type: ["string", "null"] parent_session_id: type: ["string", "null"] model: type: ["string", "null"] PrincipalSystem: type: object required: - kind - system_kind properties: kind: type: string enum: [system] system_kind: $ref: "#/components/schemas/SystemActorKind" AgentSessionActivatedProps: description: Properties for the `agent.session.activated` event. type: object required: - capabilities - visit properties: thread_id: type: ["string", "null"] provider: type: ["string", "null"] model: type: ["string", "null"] reasoning_effort: oneOf: - $ref: "#/components/schemas/ReasoningEffort" - type: "null" speed: oneOf: - $ref: "#/components/schemas/Speed" - type: "null" permission_level: oneOf: - $ref: "#/components/schemas/PermissionLevel" - type: "null" capabilities: type: array items: type: string enum: [steer] visit: type: integer minimum: 1 AgentEventProps: description: >- Properties for every `agent.*` and `todo.*` event: the stage that owns the session plus the coding agent's own event envelope. `event` is the externally tagged coding event, `{"ToolCallStarted": {...}}` or a bare `"SessionEnded"`. Variant names are permanent API; their payloads are documented by the pebble coding agent. type: object required: - stage - visit - event - timestamp - session_id properties: stage: type: string description: Graph node id of the stage that owns the session. visit: type: integer minimum: 1 seq: type: integer format: uint64 minimum: 0 description: Position in the session's event stream. stream_id: type: string description: The event stream this event belongs to. event: description: The externally tagged coding agent event. timestamp: type: string format: date-time session_id: type: string parent_session_id: type: ["string", "null"] tool_call_id: type: ["string", "null"] ReasoningOutput: description: >- Readable model reasoning normalized into a provider-neutral shape. Both members may be present for the same response, and at least one is present whenever the object is emitted. Opaque provider material (signatures, item IDs, encrypted or redacted payloads) never appears here. oneOf: - $ref: "#/components/schemas/ReasoningOutputWithSummary" - $ref: "#/components/schemas/ReasoningOutputTraceOnly" ReasoningOutputWithSummary: type: object required: - summary properties: summary: type: string description: Model-authored summary of its reasoning. trace: type: string description: Verbatim readable reasoning text, when the provider returns it. ReasoningOutputTraceOnly: type: object required: - trace not: required: - summary properties: trace: type: string description: Verbatim readable reasoning text, when the provider returns it. AgentToolsAvailableProps: description: Properties for the `agent.tools.available` event. type: object required: - tools - visit properties: tools: type: array description: Effective model-callable tools exposed to the stage session. items: $ref: "#/components/schemas/ToolSummary" visit: type: integer minimum: 1 RunSupersededByProps: description: Properties for the `run.superseded_by` audit event emitted on a rewound source run after archive succeeds. type: object required: - new_run_id - target_checkpoint_ordinal - target_node_id - target_visit properties: new_run_id: type: string target_checkpoint_ordinal: type: integer minimum: 1 target_node_id: type: string target_visit: type: integer minimum: 1 RunStreamItemKind: description: Which item shape a run stream item carries. type: string enum: [petri, platform] RunStreamItem: description: | One item of a Petri run's stream: a Petri `RunEvent` or a Fabro platform record in Fabro's envelope. `stream_seq` is the durable per-run delivery sequence the projector assigned when the item's record was committed: dense, strictly increasing within the run, and the cursor for `after`. `id` is the item's own identity, kept beside the cursor so a client deduplicates by it: for a Petri event the `EventId` as `//` (`coordinator/3/0`, `execution 1/23/0`); for a platform record its `seq`. Petri's `EventId` is per log and has no platform variant, so it is never the cursor. A `petri` item is a Petri `RunEvent` passed through unchanged: `{id: {log, execution?, seq, index}, origin, recorded_at, observed_at?, context: {invocation, execution, parent?}, subject?, record?, derived?}`. Its vocabulary is Petri's public event contract (`crates/core/execution/EVENTS.md` in the Petri repository), not Fabro's: the recorded event's name is `record.body.event` (`.`, e.g. `visit.started`, `step.finished`, `run.finished`), a derived view event's is `derived.event`, and the stage a subject names is `(context.execution, subject.firing)` with `subject.node.name` and `subject.visit` as its display label. The server reports the contract version it serves in `PaginatedRunStreamList.event_contract_version`. A `platform` item is a stored platform record: `{seq, recorded_at, record: {kind, ...}, position?: {execution, firing}}`. `record.kind` is one of `run.created`, `run.lifecycle`, `run.title`, `run.parent`, `run.archived`, `run.unarchived`, `run.superseded`, `run.notice`, `interview.answered`, `run.branch`, `git.identity`, `checkpoint`, `pull_request.created`, `notification.sent`, `run.paired`. type: object required: - run_id - stream_seq - kind - id - recorded_at - item properties: run_id: type: string stream_seq: type: integer format: uint64 minimum: 0 description: The delivery sequence; the cursor. kind: $ref: "#/components/schemas/RunStreamItemKind" id: type: string description: The item's own identity, for deduplication. recorded_at: type: integer format: uint64 minimum: 0 description: Milliseconds since the Unix epoch when the item's record was appended. item: type: object additionalProperties: true description: The Petri `RunEvent` or the stored platform record, unchanged. PaginatedRunStreamList: description: | One page of a Petri run's stream, in `stream_seq` order. `event_contract_version` is Petri's `EVENT_CONTRACT_VERSION` the server was built against: the version of the event contract every `petri` item follows. type: object required: - data - meta - event_contract_version properties: data: type: array items: $ref: "#/components/schemas/RunStreamItem" meta: $ref: "#/components/schemas/PaginationMeta" event_contract_version: type: integer format: uint32 minimum: 0 example: 3 BlobHash: description: >- Content-addressed SHA-256 hash of a stored blob. Hex input is case-insensitive; Fabro emits the canonical lowercase form. type: string pattern: "^[0-9A-Fa-f]{64}$" example: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 WriteBlobResponse: description: Content-addressed hash of a stored blob. type: object required: - hash properties: hash: $ref: "#/components/schemas/BlobHash" PetriAccess: description: >- How a worker opens a Petri run. `create` inserts the run and takes its writer lease, `write` takes the lease of an existing run, `read` takes no lease. type: string enum: - create - write - read PetriOpenRequest: description: An open of a Petri run for a worker. type: object required: - access properties: access: $ref: "#/components/schemas/PetriAccess" owner: type: string nullable: true description: >- The owner id the writer lease is taken for. Required for `create` and `write`, absent for `read`. example: 18f3c2a9e1b4-42017-0-9f3a1c7e2b5d PetriOpenResponse: description: A Petri run opened for a worker. type: object required: - locator properties: locator: type: string description: Where the run lives, for messages. example: "sqlite database /var/lib/fabro/db/fabro.sqlite3, run `01JNQVR7M0EJ5GKAT2SC4ERS1Z`" PetriReleaseRequest: description: A release of a Petri run's writer lease by its owner. type: object required: - owner properties: owner: type: string description: The owner id that holds the lease. example: 18f3c2a9e1b4-42017-0-9f3a1c7e2b5d PetriRecord: description: >- One stored line of a Petri log: the record as JSON, with `seq` and `recorded_at` lifted out of it so the store can key and index without reading into the JSON. What the store hands back equals what it was given as a JSON value. type: object required: - seq - recorded_at - record properties: seq: type: integer format: uint64 description: The record's position in its log, from 0. example: 7 recorded_at: type: integer format: uint64 description: Milliseconds since the Unix epoch when Petri appended the record. example: 1758067200123 record: type: object additionalProperties: true description: The record itself, stored and read back unchanged. PetriAppendRequest: description: One batch of records for one Petri log. type: object required: - owner - records properties: owner: type: string description: The owner id the worker holds the run's writer lease with. example: 18f3c2a9e1b4-42017-0-9f3a1c7e2b5d records: type: array items: $ref: "#/components/schemas/PetriRecord" PetriRecordList: description: Every record of one Petri log, in `seq` order. type: object required: - records properties: records: type: array items: $ref: "#/components/schemas/PetriRecord" PetriPlatformRecord: description: >- One of Fabro's platform records of a Petri run, as stored: the record's JSON tagged by `kind`, its position in the run's platform record sequence, and the Petri stage it belongs to when it belongs to one. type: object required: - seq - recorded_at - record properties: seq: type: integer format: uint64 description: The record's position in the run's platform records, from 1. example: 4 recorded_at: type: integer format: uint64 description: Milliseconds since the Unix epoch when the record was stored. example: 1758067200123 record: type: object additionalProperties: true description: The platform record itself, tagged by `kind`. execution: type: integer format: uint64 description: The Petri execution the record belongs to, with `firing`. firing: type: integer format: uint64 description: The Petri firing the record belongs to, with `execution`. PetriPlatformRecordAppendRequest: description: One platform record to store for the run. type: object required: - record properties: record: type: object additionalProperties: true description: The platform record, tagged by `kind`. execution: type: integer format: uint64 description: The Petri execution the record belongs to, with `firing`. firing: type: integer format: uint64 description: The Petri firing the record belongs to, with `execution`. PetriPlatformRecordList: description: The run's platform records, in `seq` order. type: object required: - records properties: records: type: array items: $ref: "#/components/schemas/PetriPlatformRecord" CommandTermination: description: Terminal state for a command execution. type: string enum: - exited - timed_out - cancelled CommandLogResponse: description: Byte-offset command log slice. type: object required: - offset - next_offset - total_bytes - bytes_base64 - eof - cas_ref - live_streaming properties: offset: type: integer minimum: 0 description: Actual byte offset used for this slice. example: 0 next_offset: type: integer minimum: 0 description: Byte offset for the next tail request. example: 4096 total_bytes: type: integer minimum: 0 description: Total bytes currently available for the output log. example: 8192 bytes_base64: type: string description: Base64-encoded raw log bytes. example: aGVsbG8K eof: type: boolean description: Whether the output log is finalized. example: false cas_ref: oneOf: - type: string pattern: '^blob://sha256/[0-9a-f]{64}$' - type: "null" description: Final CAS reference once the command has completed. live_streaming: type: boolean description: Whether the sandbox provided live output while the command was running. example: true ArtifactEntry: description: A single artifact file for a stage. type: object required: - filename - retry - size properties: filename: type: string description: Artifact filename. example: src/lib.rs retry: type: integer format: int32 minimum: 0 description: Retry attempt number. example: 1 size: type: integer format: int64 minimum: 0 description: Artifact size in bytes. example: 1234 ArtifactListResponse: description: List of artifact files for a stage. type: object required: - data properties: data: type: array items: $ref: "#/components/schemas/ArtifactEntry" RunArtifactEntry: description: A captured artifact file for a run. type: object required: - stage_id - node_slug - retry - relative_path - size properties: stage_id: type: string description: Stage ID in `node@visit` form. node_slug: type: string description: Node slug that produced the artifact. retry: type: integer format: int32 minimum: 0 description: Retry attempt number. relative_path: type: string description: Artifact path relative to the stage artifact capture directory. size: type: integer format: int64 minimum: 0 description: Artifact size in bytes. RunArtifactListResponse: description: List of captured artifact files for a run. type: object required: - data properties: data: type: array items: $ref: "#/components/schemas/RunArtifactEntry" BlockedReason: description: Specific reason a run is blocked on external intervention. type: string enum: - human_input_required RunControlAction: description: Run control action requested by the API. type: string enum: - cancel - pause - unpause StageOutcome: description: Terminal execution outcome of a workflow stage. type: string enum: - succeeded - partially_succeeded - failed - skipped StageCompletion: description: Terminal completion metadata for a projected workflow stage. type: object required: - outcome - timestamp properties: outcome: $ref: "#/components/schemas/StageOutcome" notes: type: ["string", "null"] failure_reason: type: ["string", "null"] timestamp: type: string format: date-time ContextWindowCategory: description: Category of model-visible input/context tokens. type: string enum: - system_prompt - tools - mcp_tools - skills - memory - conversation - other ContextWindowCountMethod: description: Method used to produce the context-window token total and breakdown. type: string enum: - provider_api_scaled_breakdown - response_usage_scaled_breakdown - local_estimate ContextWindowStaleness: description: Freshness of the returned context-window data. type: string enum: - live - stored - unavailable StageContextWindowUnavailableReason: description: Why context-window data is unavailable for a known run stage. type: string enum: - not_agent_stage - not_observed - provider_unconfigured ContextWindowWarning: description: Content-free warning about context-window count quality or attribution. type: object required: - code - message properties: code: type: string description: Stable warning code. example: provider_token_count_failed message: type: string description: Human-readable warning that must not include prompt, memory, message, or tool-argument content. example: provider input token counting failed; returned local estimate ContextWindowBreakdownItem: description: Token usage for one content category. type: object required: - category - tokens - usage_percent properties: category: $ref: "#/components/schemas/ContextWindowCategory" tokens: type: integer format: uint64 minimum: 0 example: 30000 usage_percent: type: number format: double minimum: 0 example: 7.5 ContextWindowSnapshot: description: Durable content-free context-window snapshot recorded by the coding agent. type: object required: - provider - model - context_window_tokens - input_tokens - usage_percent - count_method - staleness - generated_at - breakdown - warnings properties: provider: type: string example: openai model: type: string example: gpt-5.4 context_window_tokens: type: integer format: uint64 minimum: 0 example: 400000 input_tokens: type: integer format: uint64 minimum: 0 example: 123456 usage_percent: type: number format: double minimum: 0 example: 30.86 count_method: $ref: "#/components/schemas/ContextWindowCountMethod" staleness: $ref: "#/components/schemas/ContextWindowStaleness" generated_at: type: string format: date-time example: "2026-05-23T12:34:56Z" event_seq: type: ["integer", "null"] format: uint64 minimum: 0 description: Sequence of the agent event this snapshot was taken at, when known. example: 42 breakdown: type: array items: $ref: "#/components/schemas/ContextWindowBreakdownItem" warnings: type: array items: $ref: "#/components/schemas/ContextWindowWarning" StageContextWindow: description: Best-effort context-window usage for one agent stage. type: object required: - stage_id - available - unavailable_reason - provider - model - context_window_tokens - input_tokens - usage_percent - count_method - staleness - generated_at - event_seq - breakdown - warnings properties: stage_id: type: string description: Stage ID in `node@visit` form. example: implement@1 available: type: boolean description: Whether context-window data is available for this known stage. unavailable_reason: oneOf: - $ref: "#/components/schemas/StageContextWindowUnavailableReason" - type: "null" provider: type: ["string", "null"] example: openai model: type: ["string", "null"] example: gpt-5.4 context_window_tokens: type: ["integer", "null"] format: uint64 minimum: 0 example: 400000 input_tokens: type: ["integer", "null"] format: uint64 minimum: 0 example: 123456 usage_percent: type: ["number", "null"] format: double minimum: 0 example: 30.86 count_method: oneOf: - $ref: "#/components/schemas/ContextWindowCountMethod" - type: "null" staleness: $ref: "#/components/schemas/ContextWindowStaleness" generated_at: type: ["string", "null"] format: date-time example: "2026-05-23T12:34:56Z" event_seq: type: ["integer", "null"] format: uint64 minimum: 0 description: >- The coding agent's own event sequence for the snapshot, when it carried one; not the run event sequence. example: 42 breakdown: type: array items: $ref: "#/components/schemas/ContextWindowBreakdownItem" warnings: type: array items: $ref: "#/components/schemas/ContextWindowWarning" ParallelBranchResult: description: The outcome and isolated context updates from one parallel branch. type: object required: - id - status - context_updates properties: id: type: string index: type: integer minimum: 0 description: >- Zero-based input item or outgoing-edge position. Absent only on parallel results written before indexed branch identity was added. item_label: type: string description: >- Human-readable for_each item identity, derived from name, then label, then the zero-based input index. status: $ref: "#/components/schemas/StageOutcome" context_updates: type: object additionalProperties: true StageProjection: description: Observable projection data for one workflow stage execution. type: object required: - first_event_seq - usage - state properties: first_event_seq: type: integer format: uint32 minimum: 1 prompt: type: ["string", "null"] response: type: ["string", "null"] completion: oneOf: - $ref: "#/components/schemas/StageCompletion" - type: "null" provider_used: oneOf: - $ref: "#/components/schemas/StageModelUsage" - type: "null" description: Provider and model metadata recorded for the stage attempt. diff: type: ["string", "null"] script_invocation: type: ["object", "null"] description: Command and environment recorded when the stage script ran. script_timing: type: ["object", "null"] description: Wall-clock and step timing metadata for the stage script. parallel_results: type: ["array", "null"] items: $ref: "#/components/schemas/ParallelBranchResult" description: Ordered per-branch results produced by a parallel stage. parallel_branch_id: oneOf: - $ref: "#/components/schemas/ParallelBranchId" - type: "null" output: type: ["string", "null"] output_bytes: type: ["integer", "null"] minimum: 0 live_streaming: type: ["boolean", "null"] termination: oneOf: - $ref: "#/components/schemas/CommandTermination" - type: "null" started_at: type: ["string", "null"] format: date-time description: Wall-clock time the latest attempt of this stage started, if known. timing: oneOf: - $ref: "#/components/schemas/StageTiming" - type: "null" description: | Per-attempt timing breakdown for the latest terminal attempt: wall time plus the active inference/tool breakdown. Null while the stage is still in flight; the live estimate is derived from `live_inference_ms`, `live_tool_ms`, and any open bracket. live_inference_ms: type: integer format: uint64 minimum: 0 default: 0 description: | Inference time accumulated from closed brackets during the current attempt. Live estimate only — the authoritative value arrives with the terminal event and lands in `timing`. Excludes the currently open bracket, whose span is measured from `inference.started_at`. example: 78230 live_tool_ms: type: integer format: uint64 minimum: 0 default: 0 description: | Tool time accumulated from closed tool batches during the current attempt. A batch spans the first dispatched call through the completion that drains the last outstanding one, so tools running concurrently within a turn are counted once. example: 7588 tool_batch: oneOf: - $ref: "#/components/schemas/StageToolBatchProjection" - type: "null" description: | Open tool batch: when the batch started and which calls have not yet reported completion. usage: $ref: "#/components/schemas/Usage" description: >- The stage's usage: the session tree's tokens and cost, live and once the stage ends. Every answer is priced once by lithos-llm (the provider's reported cost, else the catalog's price for the route) and summed; the cost is absent only when an answer had neither. model: oneOf: - $ref: "#/components/schemas/UsageModelRef" - type: "null" permission_level: oneOf: - $ref: "#/components/schemas/PermissionLevel" - type: "null" description: Agent tool permission level applied to this stage session. agent_tools: type: array description: > Effective model-callable tools exposed to this agent stage session. Tool parameter schemas are intentionally omitted from this projection. items: $ref: "#/components/schemas/ToolSummary" inference: oneOf: - $ref: "#/components/schemas/StageInferenceProjection" - type: "null" description: > Open inference bracket, if the event log contains one. Present means a model request was dispatched and no closing event has been seen — not that the model is computing right now. acp_started_at: type: ["string", "null"] format: date-time description: > Start of an external ACP agent process, if one is running. ACP agents do not expose Fabro's internal LLM brackets, so the process lifetime supplies their live inference estimate. usage_by_model: type: array items: $ref: "#/components/schemas/ModelUsage" default: [] description: >- The completed stage's `usage` split by model, as `stage.completed` reported it: the root session's route and each subagent's own model, a subagent whose model the catalog does not know priced at the root's. Sums to `usage`. Empty while the stage runs and for stages without a coding agent; the usage rollup then puts `usage` under `model`. agent: oneOf: - $ref: "#/components/schemas/AgentSessionProjection" - type: "null" description: >- The coding agent's own fold of this stage's `agent.*` and `todo.*` events, present for agent stages once their first agent event is stored and absent for every other stage kind. Each stage owns one fold over its own events, so the lifetime fields are the stage's totals across every prompt it ran. `activity` reads `running` on stages recorded before `agent.processing.end` was kept; `state` is the authority on whether the stage is done. state: $ref: "#/components/schemas/StageState" description: Lifecycle state of the stage projection. StageToolBatchProjection: description: > One open tool batch: tool calls dispatched together that have not all reported completion. `open_call_ids` is a set rather than a count so a duplicated completion in a replayed log cannot drain the batch early. type: object required: - session_id - started_at - open_call_ids properties: session_id: type: string description: > Root agent session that dispatched the batch. Transitions are gated on it so delayed events from a replaced session cannot mutate the current batch. started_at: type: string format: date-time description: > When the batch opened — the first dispatched call observed while no other calls were outstanding. open_call_ids: type: array minItems: 1 uniqueItems: true items: type: string description: Calls dispatched but not yet completed, by tool call id. StageInferenceProjection: description: > One open inference bracket: a dispatched LLM request that has not yet produced a message, error, or interrupt. Carries no usage or cost — none exists until the turn completes. type: object required: - session_id - started_at - requested_model - retries properties: session_id: type: string description: > Agent session that opened the bracket, copied from the event envelope. Transitions are gated on it so sub-agent rounds cannot overwrite the root session's bracket. started_at: type: string format: date-time description: When the request was dispatched. requested_model: type: string description: > The model the request was sent to, as the agent names it. Failover can re-target, so `StageProjection.model` stays authoritative for what answered. example: claude-fable-5 first_output_at: type: ["string", "null"] format: date-time description: When the provider produced its first output, if it has. first_output_kind: oneOf: - $ref: "#/components/schemas/LlmOutputKind" - type: "null" description: Kind of the first output observed for the current attempt. retries: type: integer format: uint32 minimum: 0 description: Attempts that failed and restarted within this bracket. LlmOutputKind: description: > Kind of output a provider produced first for an inference attempt. Observed, never inferred. type: string enum: - reasoning - text - tool_call SkillSummary: description: Summary of an available agent skill. type: object required: - name - description properties: name: type: string description: type: string SkillActivationSource: description: Source that activated an agent skill. type: string enum: [slash, tool] ToolSummary: description: Summary of one effective model-callable tool exposed to an agent stage. type: object required: - name - description - source - category - invoked properties: name: type: string description: Exposed model-facing tool name, for example `apply_patch` or `mcp__filesystem__read_file`. description: type: string description: Model-facing tool description. source: $ref: "#/components/schemas/ToolSource" category: $ref: "#/components/schemas/ToolCategory" invoked: type: boolean default: false description: True once this tool has been invoked during the stage. ToolSource: description: Origin of an effective agent tool. oneOf: - $ref: "#/components/schemas/ToolSourceNative" - $ref: "#/components/schemas/ToolSourceApplication" - $ref: "#/components/schemas/ToolSourceMcp" - $ref: "#/components/schemas/ToolSourceSkill" discriminator: propertyName: kind mapping: native: "#/components/schemas/ToolSourceNative" application: "#/components/schemas/ToolSourceApplication" mcp: "#/components/schemas/ToolSourceMcp" skill: "#/components/schemas/ToolSourceSkill" ToolSourceNative: description: A tool the coding agent itself implements. type: object required: - kind properties: kind: type: string enum: [native] ToolSourceApplication: description: A tool Fabro registers with the coding agent, such as the `fabro_run_*` tools. type: object required: - kind properties: kind: type: string enum: [application] ToolSourceMcp: type: object required: - kind - server_name - original_name properties: kind: type: string enum: [mcp] server_name: type: string description: MCP server name that provided the tool. original_name: type: string description: Tool name before MCP qualification. ToolSourceSkill: type: object required: - kind properties: kind: type: string enum: [skill] ToolCategory: description: Coarse tool category for display and grouping. type: string enum: [read, write, shell, subagent, other] AgentSessionProjection: description: >- The coding agent's fold of one stage's event stream: token counts and provider-reported cost for the root session and each descendant, the route and where it moved, the context window, tools, MCP servers, skills, todo lists, subagents, compactions, files touched, and the prompt in progress. Its costs are the provider's own; pricing from the catalog is fabro's, and lives in `StageProjection.usage`. type: object required: - root_session_id - route - activity - usage - messages - descendants - context_window - tools - mcp_servers - skills - subagent_counts - todos - subagents - compactions - files_touched - last_file_touched - prompts - prompt properties: root_session_id: type: ["string", "null"] description: The root session, once an event named it. route: $ref: "#/components/schemas/AgentSessionRoute" activity: $ref: "#/components/schemas/AgentSessionActivity" usage: $ref: "#/components/schemas/Usage" description: >- The root session's usage over the stage, with the provider's reported cost when every answer carried one. messages: type: integer format: uint64 minimum: 0 description: Committed assistant messages from the root session. descendants: type: object additionalProperties: $ref: "#/components/schemas/AgentSessionDescendantAccount" description: Every descendant session's account, by session id. context_window: oneOf: - $ref: "#/components/schemas/ContextWindowSnapshot" - type: "null" description: >- The root session's latest context window. `event_seq` is the agent's own sequence when it carried one, not the run event seq. tools: type: object additionalProperties: $ref: "#/components/schemas/AgentSessionToolActivity" description: Every tool called anywhere in the tree, by the name the model used. retries: type: integer format: uint64 minimum: 0 default: 0 description: Model calls retried after a failed attempt, across the tree. mcp_servers: type: object additionalProperties: $ref: "#/components/schemas/AgentSessionMcpServer" description: Every MCP server the root configured, by name. skills: $ref: "#/components/schemas/AgentSessionSkills" subagent_counts: $ref: "#/components/schemas/AgentSessionSubagentCounts" todos: type: object additionalProperties: $ref: "#/components/schemas/TodoListProjection" description: >- Every todo list in the tree, by list id. The root agent's own list is the one whose id ends with `root_session_id`. subagents: type: array items: $ref: "#/components/schemas/AgentSessionSubagent" compactions: type: array items: $ref: "#/components/schemas/AgentSessionCompaction" description: The root session's compactions, in order. failovers: type: array items: $ref: "#/components/schemas/AgentSessionRouteFailover" default: [] description: Every move the root made to a fallback route, in order. failover_stopped: oneOf: - $ref: "#/components/schemas/AgentSessionFailoverStop" - type: "null" description: >- Why the prompt in progress, or the last one, stayed on its route and ended there although fallback routes were named. Cleared when a prompt starts. files_touched: type: array items: type: string description: Files written or edited across the tree, sorted. last_file_touched: type: ["string", "null"] prompts: type: integer format: uint64 minimum: 0 description: How many prompts have started. prompt: $ref: "#/components/schemas/AgentSessionPromptDelta" pending_writes: type: object additionalProperties: type: array items: type: string description: >- In-flight bookkeeping, not a fact about the session: the paths a write or edit tool call named, by tool call id, between its start and its completion. Present only while such a call is open; a settled projection has no such member. AgentSessionActivity: description: Where a session stands, as its events tell it. type: string enum: [idle, running, waiting_for_steer, ended] AgentSessionRoute: description: The route a session runs on, as it reported it. type: object required: - provider - model properties: provider: type: ["string", "null"] model: type: ["string", "null"] AgentSessionDescendantAccount: description: What one descendant session spent, as its own events reported it. type: object required: - parent - usage - messages - compactions properties: parent: type: string description: The session that spawned it. provider: type: string description: The provider it runs on, as its `SessionStarted` reported it. model: type: string description: >- The model it runs on, from its `SessionStarted`; when the start was not seen, the model of its first answer. usage: $ref: "#/components/schemas/Usage" messages: type: integer format: uint64 minimum: 0 description: Committed assistant messages. compactions: type: integer format: uint64 minimum: 0 description: Compactions it completed. AgentSessionToolActivity: description: How one tool has been used across the tree. type: object required: - calls - errors - open properties: calls: type: integer format: uint64 minimum: 0 description: Calls started. errors: type: integer format: uint64 minimum: 0 description: Calls that completed as errors. open: type: integer format: uint64 minimum: 0 description: Calls started and not yet completed. AgentSessionSubagentCounts: description: How many child lifecycle events the tree recorded. type: object required: - spawned - turns_started - completed - failed - closed properties: spawned: type: integer format: uint64 minimum: 0 turns_started: type: integer format: uint64 minimum: 0 completed: type: integer format: uint64 minimum: 0 failed: type: integer format: uint64 minimum: 0 closed: type: integer format: uint64 minimum: 0 AgentSessionMcpServer: description: >- One MCP server the session configured, and whether it has been called. `disconnected` set means the server came up and its connection then closed; otherwise `error` set means it did not start; otherwise it is ready with `tools`. type: object required: - tools - error - invoked properties: tools: type: array items: $ref: "#/components/schemas/McpToolSummary" error: type: ["string", "null"] description: Why it did not start, when it did not. invoked: type: boolean description: Whether any of its tools has been called. disconnected: type: string description: What closed its connection during the session, when it closed. startup_ms: type: integer format: uint64 minimum: 0 description: >- Milliseconds from launch to its outcome: to its tools being listed, or to the failure. Absent until either has been seen. AgentSessionSkills: description: The skills the root session found and the ones activated anywhere in the tree. type: object required: - available - activated properties: available: type: array items: $ref: "#/components/schemas/SkillSummary" activated: type: array items: $ref: "#/components/schemas/AgentSessionActivatedSkill" AgentSessionActivatedSkill: description: A skill the session activated. type: object required: - name - source properties: name: type: string source: $ref: "#/components/schemas/SkillActivationSource" AgentSessionSubagent: description: One child the root spawned. A reused child stays one row; every event after the spawn moves its status. type: object required: - agent_id - depth - task - status properties: agent_id: type: string depth: type: integer minimum: 0 task: type: string status: $ref: "#/components/schemas/AgentSessionSubagentStatus" AgentSessionSubagentStatus: description: Where a child stands. oneOf: - $ref: "#/components/schemas/AgentSessionSubagentStatusRunning" - $ref: "#/components/schemas/AgentSessionSubagentStatusCompleted" - $ref: "#/components/schemas/AgentSessionSubagentStatusFailed" - $ref: "#/components/schemas/AgentSessionSubagentStatusClosed" discriminator: propertyName: status mapping: running: "#/components/schemas/AgentSessionSubagentStatusRunning" completed: "#/components/schemas/AgentSessionSubagentStatusCompleted" failed: "#/components/schemas/AgentSessionSubagentStatusFailed" closed: "#/components/schemas/AgentSessionSubagentStatusClosed" AgentSessionSubagentStatusRunning: type: object required: - status properties: status: type: string enum: [running] AgentSessionSubagentStatusCompleted: type: object required: - status - success - turns_used properties: status: type: string enum: [completed] success: type: boolean turns_used: type: integer minimum: 0 AgentSessionSubagentStatusFailed: type: object required: - status - error properties: status: type: string enum: [failed] error: $ref: "#/components/schemas/AgentErrorData" AgentSessionSubagentStatusClosed: type: object required: - status properties: status: type: string enum: [closed] AgentSessionCompaction: description: One compaction the root session completed. type: object required: - reason - original_turn_count - preserved_turn_count - summary_token_estimate - tracked_file_count properties: reason: $ref: "#/components/schemas/CompactionReason" original_turn_count: type: integer minimum: 0 preserved_turn_count: type: integer minimum: 0 summary_token_estimate: type: integer minimum: 0 tracked_file_count: type: integer minimum: 0 usage: $ref: "#/components/schemas/Usage" description: >- The summary call's usage: a breakdown of the session's and the prompt's usage, which already include it. Zero on compactions recorded before it was kept. AgentSessionRouteFailover: description: One move the root session made to a fallback route, as the stream reported it from the route it moved to. type: object required: - from - to - attempt - error - usage - inference_ms - tool_ms - continuation properties: from: type: string description: The `provider/model` that failed. to: type: string description: The `provider/model` the prompt continued on. attempt: type: integer format: uint32 minimum: 0 description: How many routes the prompt had moved through, this one included. error: $ref: "#/components/schemas/AgentErrorData" description: The failure that ended the previous route. usage: $ref: "#/components/schemas/Usage" description: >- What the prompt spent on the failed route. Already in the session's and the prompt's totals through that route's committed answers: a breakdown, not an addition. inference_ms: type: integer format: uint64 minimum: 0 description: Milliseconds the prompt spent waiting on the failed route's model. tool_ms: type: integer format: uint64 minimum: 0 description: Milliseconds the prompt spent running tools on the failed route. continuation: $ref: "#/components/schemas/FailoverContinuation" AgentSessionFailoverStop: description: Why a prompt stayed on its route and ended there although fallback routes were named. type: object required: - route - attempt - reason - error properties: route: type: string description: The `provider/model` the prompt ended on. attempt: type: integer format: uint32 minimum: 0 description: How many fallback routes the prompt had moved through; `0` on the route it started on. reason: $ref: "#/components/schemas/FailoverStop" error: $ref: "#/components/schemas/AgentErrorData" description: The failure that ended the prompt. AgentSessionPromptDelta: description: >- What the prompt in progress, or the last one, did: reset when a prompt starts, complete once `completed` is set. type: object required: - completed - usage - messages - context_window - tool_calls - descendants - subagent_counts - compactions - files_touched - last_file_touched properties: completed: type: boolean description: Whether the prompt reached its end. usage: $ref: "#/components/schemas/Usage" description: The root session's usage over the prompt. messages: type: integer format: uint64 minimum: 0 description: Committed assistant messages. context_window: oneOf: - $ref: "#/components/schemas/ContextWindowSnapshot" - type: "null" description: The latest context window the prompt reported. tool_calls: type: integer format: uint64 minimum: 0 description: Tool calls started, across the tree. retries: type: integer format: uint64 minimum: 0 default: 0 description: Model calls retried after a failed attempt, across the tree. failovers: type: integer format: uint32 minimum: 0 default: 0 description: Moves the root made to a fallback route during the prompt. descendants: type: object additionalProperties: $ref: "#/components/schemas/AgentSessionDescendantAccount" description: What each descendant spent during the prompt, by session id. subagent_counts: $ref: "#/components/schemas/AgentSessionSubagentCounts" description: Child lifecycle events during the prompt. compactions: type: array items: $ref: "#/components/schemas/AgentSessionCompaction" description: Compactions the root completed during the prompt. files_touched: type: array items: type: string description: Files written or edited during the prompt, across the tree, sorted. last_file_touched: type: ["string", "null"] McpToolSummary: description: One tool an MCP server advertised, as the coding agent's registry named it. type: object required: - name - original_name properties: name: type: string description: "The name the model calls: `mcp__{server}__{tool}`." original_name: type: string description: The server's own name for the tool. CompactionReason: description: Why a conversation compaction ran. type: string enum: [threshold, manual, overflow] FailoverContinuation: description: >- How a prompt carries on after a failover. `replay_prompt` when nothing the prompt committed is in the conversation, so the new route is asked the prompt again; `continue_turn` when the conversation holds output or tool results this prompt committed, so the new route continues the turn from where it stood. type: string enum: [replay_prompt, continue_turn] FailoverStop: description: >- Why a model failure ends a prompt on its route when fallback routes were named. `ineligible` when the failure follows the request, so another route would fail the same way; `exhausted` when every named route has been taken. type: string enum: [ineligible, exhausted] AgentErrorData: description: >- A failure as the coding agent's event stream carries it: category, safe message, retry advice, provider and model context, and the rendered source chain. Never a raw provider response body. type: object required: - kind - message properties: kind: $ref: "#/components/schemas/AgentErrorKind" message: type: string description: The whole failure rendered for a person, cause included. llm_kind: $ref: "#/components/schemas/LlmErrorKind" description: The model-layer category, when a model call failed. retry: $ref: "#/components/schemas/LlmRetryClassification" description: Whether repeating the same model call is safe, when a model call failed. provider: type: string description: The provider that produced the failure, when one was selected. model: type: string description: The model that produced the failure, when one was selected. status: type: integer format: uint16 minimum: 0 description: The HTTP status, when the failure came from an HTTP response. provider_code: type: string description: The provider's own error code, as reported on the wire. provider_retry_after_millis: type: integer format: uint64 minimum: 0 description: The provider's advised wait in milliseconds. source_chain: type: array items: type: string description: The text of each cause below `message`, outermost first. AgentErrorKind: description: The stable category of a coding agent failure. type: string enum: - llm - compaction - agent - invalid_input - session_closed - invalid_state - tool_execution - interrupted - tool_rounds_exhausted - task - event_stream LlmErrorKind: description: >- The model layer's stable failure category. Known values are `configuration`, `model_selection`, `authentication`, `access_denied`, `not_found`, `invalid_request`, `context_length`, `rate_limit`, `quota_exceeded`, `content_filter`, `server`, `provider`, `network`, `timeout`, `stream_decode`, `response_decode`, `resource_limit`, `middleware`, and `cancelled`. A category written by a newer model layer is carried as its own spelling. type: string example: rate_limit LlmRetryClassification: description: Whether repeating the same resolved model call is safe. oneOf: - $ref: "#/components/schemas/LlmRetryClassificationNever" - $ref: "#/components/schemas/LlmRetryClassificationSafe" - $ref: "#/components/schemas/LlmRetryClassificationAfter" discriminator: propertyName: type mapping: never: "#/components/schemas/LlmRetryClassificationNever" safe: "#/components/schemas/LlmRetryClassificationSafe" after: "#/components/schemas/LlmRetryClassificationAfter" LlmRetryClassificationNever: description: Repeating the call cannot succeed. type: object required: - type properties: type: type: string enum: [never] LlmRetryClassificationSafe: description: Repeating the call is safe on the caller's own schedule. type: object required: - type properties: type: type: string enum: [safe] LlmRetryClassificationAfter: description: Repeating the call is safe after the given delay. type: object required: - type - after_millis properties: type: type: string enum: [after] after_millis: type: integer format: uint64 minimum: 0 description: The delay in milliseconds. StageModelUsage: description: Provider, model, and request-control metadata recorded for a stage attempt. type: object required: - mode properties: mode: type: string description: Source of the stage's model usage metadata. example: agent provider: type: ["string", "null"] example: openai model: type: ["string", "null"] example: gpt-5.5 reasoning_effort: oneOf: - $ref: "#/components/schemas/ReasoningEffort" - type: "null" speed: oneOf: - $ref: "#/components/schemas/Speed" - type: "null" InterviewOption: description: Option stored with an interview question in the event log. type: object required: - key - label properties: key: type: string description: Machine-readable option key used when submitting an answer. label: type: string description: Human-readable label displayed to the user. description: type: ["string", "null"] description: Optional untrusted model-authored option description for display. preview: type: ["string", "null"] description: Optional untrusted model-authored option preview captured for clients. ReviewTargetKind: description: The type of resource presented for human review. type: string enum: - document ReviewTarget: description: A validated external resource presented as the primary subject of a human review question. type: object required: - label - url - kind properties: label: type: string minLength: 1 maxLength: 200 description: Human-readable link label. example: Quarry review exercise url: type: string format: uri minLength: 1 maxLength: 2048 description: Absolute HTTP or HTTPS URL opened by the reviewer. example: https://quarry.lithos.computer/tmp/0123456789abcdef0123456789abcdef kind: $ref: "#/components/schemas/ReviewTargetKind" InterviewQuestionRecord: description: Storage shape of an interview question recorded in the event log. type: object required: - id - text - stage - question_type - allow_freeform properties: id: type: string text: type: string stage: type: string question_type: $ref: "#/components/schemas/QuestionType" options: type: array items: $ref: "#/components/schemas/InterviewOption" allow_freeform: type: boolean timeout_seconds: type: ["number", "null"] format: double context_display: type: ["string", "null"] review_target: oneOf: - $ref: "#/components/schemas/ReviewTarget" - type: "null" PendingInterviewRecord: description: Pending interview question plus the time it entered the unresolved set. type: object required: - question - started_at properties: question: $ref: "#/components/schemas/InterviewQuestionRecord" started_at: type: string format: date-time DirtyStatus: type: string enum: - clean - dirty - unknown ForkSourceRef: description: Source checkpoint used to initialize a forked or rewound run. type: object required: - source_run_id - checkpoint_sha properties: source_run_id: type: string checkpoint_sha: type: string RunSpec: description: Durable workflow run specification reconstructed from run.created events. type: object required: - run_id - settings - graph - provenance - admission properties: run_id: type: string settings: $ref: "#/components/schemas/WorkflowSettings" graph: $ref: "#/components/schemas/RunGraph" description: | The display graph: the workflow Petri admitted, reduced to what the read side names. The DOT it was written in is `graph_source`. graph_source: type: ["string", "null"] description: The entrypoint workflow's DOT as written. workflow_slug: type: ["string", "null"] workflow_version_id: description: Exact immutable root workflow version from which the run was admitted, when applicable. oneOf: - $ref: "#/components/schemas/WorkflowVersionId" - type: "null" target: description: Canonical workspace target accepted for a version-backed run. Absent for legacy manifest runs. oneOf: - $ref: "#/components/schemas/RunTarget" - type: "null" automation: oneOf: - $ref: "#/components/schemas/AutomationRef" - type: "null" source_directory: type: ["string", "null"] labels: type: object additionalProperties: type: string provenance: $ref: "#/components/schemas/RunProvenance" definition_blob: type: ["string", "null"] spec_blob: type: ["string", "null"] git: oneOf: - $ref: "#/components/schemas/GitContext" - type: "null" fork_source_ref: oneOf: - $ref: "#/components/schemas/ForkSourceRef" - type: "null" admission: $ref: "#/components/schemas/PetriAdmission" description: | What Petri admitted for the run at create time: the graphs it executes and resumes from. RunGraph: description: | The display graph of a run: the admitted workflow's name, goal, stages and edges, read off the graph Petri admitted at create time. Lowering artifacts (the goal check, a synthetic fan-in) are left out; the stages are the nodes the workflow declares, imports and `[run.prepare]` steps included. type: object required: [name] properties: name: type: string description: The workflow's name, the DOT `digraph` name. goal: type: string description: The run's goal as the run displays it; empty when the workflow has none. nodes: type: object description: The stages by node id. additionalProperties: $ref: "#/components/schemas/RunGraphNode" edges: type: array description: The routing edges as written, one per arm. items: $ref: "#/components/schemas/RunGraphEdge" RunGraphNode: description: One stage of a run's display graph. type: object required: [label, kind] properties: label: type: string description: The node's display label, its `label` attribute or its id. kind: $ref: "#/components/schemas/StageHandler" RunGraphEdge: description: One routing edge of a run's display graph. type: object required: [from, to] properties: from: type: string to: type: string PetriAdmission: description: | What Petri admitted for a run at create time: the lowered root graph and the pre-lowered child graphs, every one persisted in the blob store before the run exists. type: object required: [graph] properties: graph: $ref: "#/components/schemas/PetriGraphRef" children: type: array items: $ref: "#/components/schemas/PetriGraphRef" PetriGraphRef: description: An admitted graph in the blob store, verified by digest on load. type: object required: [blob, digest] properties: blob: $ref: "#/components/schemas/BlobHash" digest: type: string UpdateRunParentRequest: type: object required: - parent_id properties: parent_id: type: string description: Existing orchestration parent run ID. StartRecord: description: Metadata captured when execution starts. type: object required: - start_time properties: start_time: type: string format: date-time run_branch: type: ["string", "null"] base_sha: type: ["string", "null"] StageSummary: description: Terminal summary for one stage in a run conclusion. type: object required: - stage_id - stage_label - timing - usage - retries properties: stage_id: type: string stage_label: type: string timing: $ref: "#/components/schemas/StageTiming" usage: $ref: "#/components/schemas/Usage" description: Per-node usage summed across every visit of the node. retries: type: integer format: uint32 minimum: 0 Conclusion: description: Terminal run conclusion derived from final workflow execution. type: object required: - timestamp - status - timing - stages - total_retries - diff properties: timestamp: type: string format: date-time status: $ref: "#/components/schemas/StageOutcome" timing: $ref: "#/components/schemas/RunTiming" failure: oneOf: - $ref: "#/components/schemas/RunFailure" - type: "null" final_git_commit_sha: type: ["string", "null"] stages: type: array items: $ref: "#/components/schemas/StageSummary" usage: oneOf: - $ref: "#/components/schemas/Usage" - type: "null" description: >- The run's usage summed across every stage visit; null for a run that made no model calls. total_retries: type: integer format: uint32 minimum: 0 diff: $ref: "#/components/schemas/RunDiff" CheckpointRecord: description: Sequence-tagged checkpoint history entry with the diff observed at that checkpoint. type: object required: - seq - checkpoint - diff properties: seq: type: integer format: uint32 checkpoint: $ref: "#/components/schemas/RunCheckpoint" diff: $ref: "#/components/schemas/RunDiff" RunProjection: description: Raw internal run projection derived from the event log. type: object required: - spec - status - status_updated_at - last_event_at - checkpoints - pending_interviews - stages properties: title: type: string description: Resolved run title from the event log. parent_id: type: ["string", "null"] description: Current orchestration parent run ID, if linked. spec: $ref: "#/components/schemas/RunSpec" web_url: type: ["string", "null"] description: Absolute web UI URL for this run when server web settings are configured. start: oneOf: - $ref: "#/components/schemas/StartRecord" - type: "null" status: $ref: "#/components/schemas/RunStatus" archived_at: type: ["string", "null"] format: date-time status_updated_at: type: string format: date-time last_event_at: type: string format: date-time pending_control: oneOf: - $ref: "#/components/schemas/RunControlAction" - type: "null" checkpoints: type: array description: Sequence-tagged checkpoint history entries. items: $ref: "#/components/schemas/CheckpointRecord" conclusion: oneOf: - $ref: "#/components/schemas/Conclusion" - type: "null" sandbox: oneOf: - $ref: "#/components/schemas/RunSandbox" - type: "null" pull_request: oneOf: - $ref: "#/components/schemas/PullRequestLink" - type: "null" pull_request_creation: oneOf: - $ref: "#/components/schemas/PullRequestCreation" - type: "null" superseded_by: type: ["string", "null"] retried_from: type: ["string", "null"] description: Source run ID when this run was created by manual retry. forked_from: oneOf: - $ref: "#/components/schemas/ForkOrigin" - type: "null" description: Where the run's records came from when it is a fork. git_identity: oneOf: - $ref: "#/components/schemas/GitIdentity" - type: "null" description: > The Git author/committer identity the run resolved for its commits. Absent until the run's first initialization resolves it. pending_interviews: type: object additionalProperties: $ref: "#/components/schemas/PendingInterviewRecord" stages: type: object description: Map from StageId (`node_id@visit`) to stage projection data. additionalProperties: $ref: "#/components/schemas/StageProjection" TodoStatus: type: string enum: [pending, in_progress, completed, deleted] description: |- Lifecycle for a todo / task. `deleted` is reachable for Anthropic tasks; once observed, the todo is removed from the projection. TodoListKind: type: string enum: [openai_plan, anthropic_tasks, kimi_todos] description: |- Tool surface a todo list belongs to. Determines the `list_id` prefix and scoping convention. TodoProjection: type: object description: One projected todo / task item. required: - id - status - order - subject properties: id: type: string status: $ref: "#/components/schemas/TodoStatus" order: type: integer format: uint32 minimum: 0 subject: type: string description: type: string default: "" active_form: type: ["string", "null"] owner: type: ["string", "null"] blocks: type: array items: type: string blocked_by: type: array items: type: string metadata: type: object additionalProperties: true TodoListProjection: type: object description: All currently-projected todos for one `list_id`. required: - kind - list_id properties: kind: $ref: "#/components/schemas/TodoListKind" list_id: type: string items: type: array items: $ref: "#/components/schemas/TodoProjection" Run: description: Canonical public run shape. type: object required: - id - title - goal - workflow - automation - repository - created_by - origin - labels - lifecycle - sandbox - models - source_directory - timestamps - timing - usage - size - ask_fabro - diff - pull_request - current_question - superseded_by - retried_from - links - children_count properties: id: type: string parent_id: type: ["string", "null"] description: Current orchestration parent run ID, if linked. children_count: type: integer format: uint64 minimum: 0 description: Number of runs currently linked to this run as their orchestration parent. title: type: string goal: type: string workflow: $ref: "#/components/schemas/WorkflowRef" automation: oneOf: - $ref: "#/components/schemas/AutomationRef" - type: "null" repository: oneOf: - $ref: "#/components/schemas/RepositoryRef" - type: "null" created_by: $ref: "#/components/schemas/Principal" origin: $ref: "#/components/schemas/RunOrigin" labels: type: object additionalProperties: type: string lifecycle: $ref: "#/components/schemas/RunLifecycle" sandbox: oneOf: - $ref: "#/components/schemas/RunSandbox" - type: "null" models: type: array items: $ref: "#/components/schemas/RunModel" source_directory: type: ["string", "null"] timestamps: $ref: "#/components/schemas/RunTimestamps" timing: oneOf: - $ref: "#/components/schemas/RunTiming" - type: "null" description: | Run-level timing rollup. Wall time is the run's clock duration; active timing sums work across stage visits. usage: $ref: "#/components/schemas/Usage" description: >- The run's usage summed across every stage visit so far: the conclusion's total once the run ended, else the sum of the stages'. size: $ref: "#/components/schemas/RunSize" ask_fabro: $ref: "#/components/schemas/AskFabro" diff: oneOf: - $ref: "#/components/schemas/DiffSummary" - type: "null" pull_request: oneOf: - $ref: "#/components/schemas/PullRequestLink" - type: "null" current_question: oneOf: - $ref: "#/components/schemas/RunQuestion" - type: "null" superseded_by: type: ["string", "null"] description: Run ID that superseded this run via rewind, if any. retried_from: type: ["string", "null"] description: Source run ID when this run was created by manual retry. links: $ref: "#/components/schemas/RunLinks" AskFabro: description: Readiness and defaults for starting an Ask Fabro session on this run. type: object required: - available - unavailable_reason - default_model properties: available: type: boolean unavailable_reason: type: ["string", "null"] enum: - no_sandbox - sandbox_not_ready - llm_unconfigured - null default_model: type: ["string", "null"] WorkflowRef: type: object required: [slug, name, graph_name, node_count, edge_count] properties: slug: type: ["string", "null"] name: type: ["string", "null"] graph_name: type: ["string", "null"] node_count: type: integer format: int64 description: Number of nodes in the workflow graph. edge_count: type: integer format: int64 description: Number of edges in the workflow graph. AutomationRef: type: object required: [id, name] properties: id: type: string name: type: ["string", "null"] trigger_id: type: ["string", "null"] workflow_source: description: Resolved workflow source for automation runs that declare one. oneOf: - $ref: "#/components/schemas/ResolvedAutomationGitWorkflowSource" - type: "null" RunOrigin: type: object required: [kind] properties: kind: type: string enum: [api] RunLifecycle: type: object required: [status, approval, pending_control, queue_position, error, archived, archived_at] properties: status: $ref: "#/components/schemas/RunStatus" approval: oneOf: - $ref: "#/components/schemas/RunApproval" - type: "null" pending_control: oneOf: - $ref: "#/components/schemas/RunControlAction" - type: "null" queue_position: type: ["integer", "null"] error: oneOf: - $ref: "#/components/schemas/RunError" - type: "null" archived: type: boolean archived_at: type: ["string", "null"] format: date-time RunApproval: description: Pre-execution approval state for runs that require one-time human approval. type: object required: [state, requested_at, decided_at, denial_reason] properties: state: $ref: "#/components/schemas/RunApprovalState" requested_at: type: string format: date-time decided_at: type: ["string", "null"] format: date-time denial_reason: type: ["string", "null"] RunApprovalState: description: State of a run's pre-execution approval request. type: string enum: - pending - approved - denied RunModel: type: object required: [provider, name] properties: provider: type: ["string", "null"] name: type: string RunTimestamps: type: object required: [created_at, started_at, last_event_at, completed_at] properties: created_at: type: string format: date-time started_at: type: ["string", "null"] format: date-time last_event_at: type: ["string", "null"] format: date-time completed_at: type: ["string", "null"] format: date-time RunSize: type: string enum: [XS, S, M, L, XL] description: Run size bucket derived from the run's current cost. RunLinks: type: object required: [web] properties: web: type: ["string", "null"] format: uri ForkOrigin: description: >- Where a forked run came from: the source run, the position (an execution and a firing of its root invocation) the source's records were kept up to, and whether that firing runs again in the fork. type: object required: - source_run_id - execution - firing - rerun_last properties: source_run_id: type: string execution: type: integer format: uint64 firing: type: integer format: uint64 rerun_last: type: boolean ForkRequest: description: Request body for creating a new run from a source run checkpoint. type: object properties: target: type: ["string", "null"] description: Optional checkpoint target such as `@2`, `build`, or `build@1`. Defaults to the latest checkpoint. ForkResponse: description: Response returned after creating and starting a forked run. type: object required: - source_run_id - new_run_id - target - checkpoint_sha - execution - firing - rerun_last properties: source_run_id: type: string new_run_id: type: string target: type: string description: The checkpoint the fork was resolved to, as `@ordinal`. checkpoint_sha: type: string description: The commit the new run's workspace starts on. execution: type: integer format: uint64 description: The Petri execution of the fork position. firing: type: integer format: uint64 description: The Petri firing of the fork position. rerun_last: type: boolean description: Whether the position's stage runs again in the new run. RewindRequest: description: Request body for creating a replacement run from a source run checkpoint. type: object properties: target: type: ["string", "null"] description: Optional checkpoint target such as `@2`, `build`, or `build@1`. Defaults to the latest checkpoint. RewindResponse: description: Response returned after rewind creates and starts a new run. type: object required: - source_run_id - new_run_id - target - checkpoint_sha - execution - firing - archived properties: source_run_id: type: string new_run_id: type: string target: type: string description: The checkpoint the rewind was resolved to, as `@ordinal`. checkpoint_sha: type: string execution: type: integer format: uint64 firing: type: integer format: uint64 archived: type: boolean archive_error: type: ["string", "null"] RunTimelineResponse: description: The run's checkpoints in order, and its fork origin when it is a fork. type: object required: - entries properties: entries: type: array items: $ref: "#/components/schemas/TimelineEntryResponse" forked_from: oneOf: - $ref: "#/components/schemas/ForkOrigin" - type: "null" TimelineEntryResponse: description: One checkpoint of a run. type: object required: - ordinal - checkpoint_seq - execution - firing - attempt - node_name - visit properties: ordinal: type: integer format: uint64 description: 1-based, in the order the checkpoints were recorded; the `@ordinal` a fork target names. checkpoint_seq: type: integer format: uint64 description: The checkpoint record's position among the run's platform records. execution: type: integer format: uint64 description: The Petri execution the checkpoint belongs to. firing: type: integer format: uint64 description: The Petri firing the checkpoint belongs to. attempt: type: integer format: uint32 description: The attempt of the firing whose files the commit holds, from 1. stage: type: ["string", "null"] description: The stage id (`node@visit`) when the projection shows the stage. node_name: type: string visit: type: integer format: uint32 workspace: type: ["string", "null"] description: The Petri workspace id the commit was made in. run_commit_sha: type: ["string", "null"] diff_summary: oneOf: - $ref: "#/components/schemas/DiffSummary" - type: "null" BoardColumn: description: | Status bucket for a run, shared by list and kanban renderings and by the `status` query parameter on `GET /api/v1/runs`. The `archived` bucket is orthogonal to the `include_archived` flag — passing `status=archived` is equivalent to opting archived runs in. type: string enum: - pending - runnable - initializing - running - blocked - succeeded - failed - archived - removing CheckRunStatus: description: Status of a CI check run. type: string enum: - success - failure - skipped - pending - queued CheckRun: description: A CI check run result associated with a run's pull request. type: object required: - name - status properties: name: type: string description: Name of the CI check. example: unit-tests status: $ref: "#/components/schemas/CheckRunStatus" wall_time_ms: type: integer format: uint64 minimum: 0 description: Wall-clock duration of the check run in milliseconds. example: 154000 # ── Reusable Sub-Schemas ─────────────────────────────────────────── ModelReference: description: Reference to a model by its identifier. type: object required: - id properties: id: type: string description: Model identifier. example: claude-opus-4-6 WorkflowReference: description: Reference to a workflow by its slug. type: object required: - slug properties: slug: type: string description: URL-safe workflow slug. example: implement RunReference: description: Reference to a run with its title. type: object required: - id - title properties: id: type: string description: Unique run identifier. example: run-047 title: type: string description: Human-readable run title. example: "PR #312 — Add OAuth2 PKCE flow" RepositoryRef: description: Durable repository metadata for a run. type: object required: - name - origin_url - provider properties: name: type: string example: fabro-sh/fabro origin_url: type: ["string", "null"] example: https://github.com/fabro-sh/fabro.git provider: type: string enum: [github, git, unknown] UsageModelRef: description: >- Provider-qualified model identity a usage is grouped under. Carries the requested speed tier because providers price tiers differently. type: object required: - provider - model_id properties: provider: $ref: "#/components/schemas/ProviderId" model_id: type: string speed: oneOf: - $ref: "#/components/schemas/Speed" - type: "null" Speed: description: "lithos `Speed`: the requested latency or cost tier." type: string enum: - fast - balanced - economical CodeLocation: description: A file and line location in the codebase. type: object required: - file properties: file: type: string description: File path. example: src/middleware/rate-limit.ts line: type: integer description: Line number in the file. example: 42 RunError: description: Error information for a failed run. type: object required: - message properties: message: type: string description: Error message. example: "Stage 'apply-changes' exceeded maximum retries." PullRequestLink: description: Minimal GitHub pull request link associated with a run. type: object required: - owner - repo - number - html_url properties: owner: type: string example: fabro-sh repo: type: string example: fabro number: type: integer example: 123 html_url: type: string format: uri description: Computed GitHub web URL for the pull request. example: https://github.com/fabro-sh/fabro/pull/123 PullRequest: description: Stored pull request link plus optional live GitHub details. type: object required: - link properties: link: $ref: "#/components/schemas/PullRequestLink" details: oneOf: - $ref: "#/components/schemas/PullRequestDetails" - type: "null" PullRequestMeta: description: Metadata for live GitHub detail retrieval. type: object required: - details_status properties: details_status: $ref: "#/components/schemas/PullRequestDetailsStatus" details_unavailable_reason: oneOf: - $ref: "#/components/schemas/PullRequestDetailsUnavailableReason" - type: "null" PullRequestResponse: description: Pull request link and optional live GitHub details for a run. type: object required: - data - meta properties: data: $ref: "#/components/schemas/PullRequest" meta: $ref: "#/components/schemas/PullRequestMeta" PullRequestDetailsStatus: description: Whether live GitHub pull request details are present. type: string enum: - available - unavailable PullRequestDetailsUnavailableReason: description: Why live GitHub pull request details are unavailable. type: string enum: - integration_unavailable - not_found - fetch_failed PullRequestUser: description: GitHub user summary for a pull request. type: object required: - login properties: login: type: string example: octocat PullRequestRef: description: Git reference summary for a pull request. type: object required: - ref properties: ref: type: string example: fabro/run/demo PullRequestDetails: description: Live pull request fields retrieved successfully from GitHub. type: object required: - title - state - draft - merged - additions - deletions - changed_files - author - head_branch - base_branch - timestamps properties: title: type: string example: Move PR commands server-side body: type: ["string", "null"] example: Detailed description state: type: string example: open draft: type: boolean example: false merged: type: boolean example: false merged_at: type: ["string", "null"] format: date-time example: "2026-04-23T15:45:00Z" mergeable: type: ["boolean", "null"] example: true additions: type: integer example: 234 deletions: type: integer example: 67 changed_files: type: integer example: 5 author: $ref: "#/components/schemas/PullRequestUser" head_branch: type: string example: fabro/run/demo base_branch: type: string example: main timestamps: type: object required: [created_at, updated_at] properties: created_at: type: string format: date-time updated_at: type: string format: date-time CreateRunPullRequestRequest: description: Request body for creating a run pull request. type: object required: - force properties: force: type: boolean description: Create the pull request even if the run did not finish with succeeded or partially_succeeded. example: false model: type: ["string", "null"] description: Optional model override for generating the pull request description. example: claude-sonnet-4-6 PullRequestCreationId: description: Stable identifier for one explicit pull request creation request. type: string example: 01KYYK70WTZT2E551P3H5P0059 PullRequestCreationStatus: description: Durable state of a pull request creation request. type: string enum: - pending - succeeded - failed PullRequestCreation: description: Durable status for the latest explicit pull request creation requested for a run. type: object required: - id - status - model - force - requested_at - updated_at properties: id: $ref: "#/components/schemas/PullRequestCreationId" status: $ref: "#/components/schemas/PullRequestCreationStatus" model: type: string description: Resolved model identifier used to generate the pull request content. force: type: boolean description: Whether creation was allowed for a run without a successful conclusion. requested_at: type: string format: date-time updated_at: type: string format: date-time pull_request: oneOf: - $ref: "#/components/schemas/PullRequestLink" - type: "null" error: type: ["string", "null"] LinkRunPullRequestRequest: description: Request body for linking an existing GitHub pull request to a run. type: object required: - html_url properties: html_url: type: string format: uri description: GitHub pull request URL to associate with the run. Must use the form `https://github.com/{owner}/{repo}/pull/{number}`. example: https://github.com/fabro-sh/fabro/pull/123 MergeMethod: description: GitHub merge method for a pull request. type: string enum: - merge - squash - rebase MergeRunPullRequestRequest: description: Request body for merging a run pull request. type: object required: - method properties: method: $ref: "#/components/schemas/MergeMethod" MergeRunPullRequestResponse: description: Response body for merging a run pull request. type: object required: - number - html_url - method properties: number: type: integer example: 123 html_url: type: string format: uri example: https://github.com/fabro-sh/fabro/pull/123 method: $ref: "#/components/schemas/MergeMethod" CloseRunPullRequestResponse: description: Response body for closing a run pull request. type: object required: - number - html_url properties: number: type: integer example: 123 html_url: type: string format: uri example: https://github.com/fabro-sh/fabro/pull/123 StageTiming: description: | Timing breakdown for one stage visit. Fields are all milliseconds. `wall_time_ms` is elapsed clock time; `inference_time_ms` is Fabro- observed LLM request/stream elapsed time; `tool_time_ms` is tool or command execution elapsed time; `active_time_ms` equals `inference_time_ms + tool_time_ms`. For a terminal stage these come from the worker's own stopwatch and are authoritative. For a stage still in flight they are a live estimate reconstructed from the event log, and `active_time_ms` is clamped to `wall_time_ms`. The estimate is replaced by the authoritative breakdown when the stage reaches a terminal event. type: object required: - wall_time_ms - inference_time_ms - tool_time_ms - active_time_ms properties: wall_time_ms: type: integer format: uint64 minimum: 0 example: 1500 inference_time_ms: type: integer format: uint64 minimum: 0 default: 0 example: 900 tool_time_ms: type: integer format: uint64 minimum: 0 default: 0 example: 200 active_time_ms: type: integer format: uint64 minimum: 0 description: Equals `inference_time_ms + tool_time_ms`. example: 1100 RunTiming: description: | Timing rollup for an entire run. Active fields sum work across stage visits, so `active_time_ms` can exceed `wall_time_ms` when parallel branches run concurrently. For a running run, stages still in flight contribute a live estimate rather than nothing, so wall and active both advance continuously. Unlike `StageTiming`, active is not clamped to wall here — concurrent branches can legitimately sum past run wall time. type: object required: - wall_time_ms - inference_time_ms - tool_time_ms - active_time_ms properties: wall_time_ms: type: integer format: uint64 minimum: 0 example: 420000 inference_time_ms: type: integer format: uint64 minimum: 0 default: 0 example: 120000 tool_time_ms: type: integer format: uint64 minimum: 0 default: 0 example: 60000 active_time_ms: type: integer format: uint64 minimum: 0 description: Equals `inference_time_ms + tool_time_ms`. example: 180000 SandboxProviderKind: description: | Sandbox provider kind. `local`, `docker`, and `daytona` are bundled with the server; any other value names a sandbox-driver plugin configured under `server.sandbox.providers.`. type: string pattern: "^[a-z0-9]([a-z0-9-]{0,62}[a-z0-9])?$" example: docker RunSandboxKind: description: Lifecycle state for a run sandbox request. type: string enum: - planned - initializing - ready - failed RunSandboxPlan: description: Requested sandbox provider and base image/snapshot from run settings. type: object required: - provider properties: provider: $ref: "#/components/schemas/SandboxProviderKind" image: type: ["string", "null"] snapshot: type: ["string", "null"] RunSandbox: description: Sandbox lifecycle record for a run. A run can have a requested sandbox plan before it has an initialized sandbox instance. type: object required: - kind - plan properties: kind: $ref: "#/components/schemas/RunSandboxKind" plan: $ref: "#/components/schemas/RunSandboxPlan" instance: oneOf: - $ref: "#/components/schemas/RunSandboxInstance" - type: "null" description: Present only when `kind` is `ready`. failure: oneOf: - $ref: "#/components/schemas/RunSandboxFailure" - type: "null" description: Present only when `kind` is `failed`. RunSandboxInstance: description: Initialized sandbox provider and runtime metadata. type: object required: - provider - runtime properties: provider: $ref: "#/components/schemas/SandboxProviderKind" image: type: ["string", "null"] snapshot: type: ["string", "null"] runtime: $ref: "#/components/schemas/RunSandboxRuntime" ready_duration_ms: type: ["integer", "null"] format: uint64 minimum: 0 description: How long the sandbox took to become ready, when recorded. retained: type: ["boolean", "null"] description: | Whether the sandbox still exists after the run released it (kept, stopped or running) or was removed. Absent until the release. RunSandboxFailure: description: Sandbox initialization failure details. type: object required: - provider - error - causes - duration_ms properties: provider: type: string description: Provider reported by the sandbox initialization event. error: type: string causes: type: array items: type: string duration_ms: type: integer format: uint64 minimum: 0 RunSandboxRuntime: type: object required: - id - working_directory - repo_cloned - clone_origin_url - clone_branch properties: id: type: string working_directory: type: string repo_cloned: type: ["boolean", "null"] clone_origin_url: type: ["string", "null"] clone_branch: type: ["string", "null"] workspace_root: type: ["string", "null"] repos_root: type: ["string", "null"] primary_repo_path: type: ["string", "null"] primary_repo_link: type: ["string", "null"] RunQuestion: description: A pending human-in-the-loop question summary. type: object required: - text properties: text: type: string description: Question text. example: Accept or push for another round? AggregateUsageTotals: description: Aggregate usage totals across all runs. type: object required: - runs - usage - timing properties: runs: type: integer description: Total number of completed runs. example: 9 usage: $ref: "#/components/schemas/Usage" description: Tokens and cost summed across every completed run. timing: $ref: "#/components/schemas/RunTiming" description: | Aggregate timing rollup across every completed run. Active timing sums work across stage visits, so `active_time_ms` can exceed `wall_time_ms`. UsageStageRef: description: Reference to a workflow node in a usage stage row. type: object required: - id - name properties: id: type: string description: Stage identifier (slug). example: propose-changes name: type: string description: Human-readable stage name. example: Propose Changes RunCheckpoint: description: >- A checkpoint Fabro recorded for the run: when, at which node, and the commit the workspace was checkpointed at, when it was committed. type: object required: - timestamp - current_node properties: timestamp: type: string format: date-time description: When the checkpoint was recorded. current_node: type: string description: The node the checkpoint was recorded for. git_commit_sha: type: string description: SHA of the git commit created at this checkpoint. # ── Stage / Turn Schemas ───────────────────────────────────────────── StageId: description: Canonical stage execution identifier in `node_id@visit` form. type: string example: verify@2 ParallelBranchId: description: >- Durable identity of one branch within a parallel execution, in `{parallel_group_id}:{index}` form. type: string example: review_fork@3:1 StageState: description: Lifecycle projection state of a workflow stage. type: string enum: - pending - running - retrying - succeeded - partially_succeeded - failed - skipped - cancelled StageHandler: description: Canonical workflow stage handler kind. type: string enum: - start - exit - agent - prompt - command - human - conditional - parallel - parallel.fan_in - stack.manager_loop - wait RunStage: description: A single stage in a run's workflow graph. type: object required: - id - name - handler - status - node_id - visit - usage properties: id: $ref: "#/components/schemas/StageId" name: type: string description: Human-readable stage name. example: Propose Changes handler: $ref: "#/components/schemas/StageHandler" status: $ref: "#/components/schemas/StageState" wall_time_ms: type: integer format: uint64 minimum: 0 description: Wall-clock time the latest attempt spent in this stage, in milliseconds. example: 154000 node_id: type: string description: Node id in the workflow graph; multiple stages with different visits share the same node_id. example: verify visit: type: integer format: uint32 minimum: 1 description: >- 1-based stage execution ordinal, the numeric component of `id`. It increments each time the node produces a new observable execution: graph re-entry (loops) and replay of post-checkpoint work after resume. Automatic in-place retries do not increment it. example: 2 graph_visit: type: ["integer", "null"] format: uint32 minimum: 1 description: >- 1-based count of how many times workflow control entered this node (drives `max_visits`). Differs from `visit` when a post-checkpoint execution is replayed after resume. Absent for stages recorded before execution identity was tracked. example: 1 resumed_from_stage_id: oneOf: - $ref: "#/components/schemas/StageId" - type: "null" description: >- StageId of the prior post-checkpoint execution superseded by this replay after the run was resumed. example: verify@1 parallel_group_id: allOf: - $ref: "#/components/schemas/StageId" description: >- Exact StageId of the parent parallel execution. Clients can compare this directly with the `id` of a parallel stage. Omitted for stages that are not parallel branches. example: review_fork@1 parallel_branch_index: type: integer format: uint32 minimum: 0 description: >- Zero-based outgoing-edge index within the parent parallel execution. Omitted for stages that are not parallel branches. example: 1 provider_used: oneOf: - $ref: "#/components/schemas/StageModelUsage" - type: "null" description: Provider, model, and request controls recorded for the latest stage attempt. started_at: type: ["string", "null"] format: date-time description: Wall-clock time the latest attempt of this stage started, if known. example: "2026-04-29T12:34:56Z" usage: $ref: "#/components/schemas/Usage" description: >- Usage for this stage execution alone. `cost` sums what lithos-llm attached to each answer: the provider's reported cost when there is one, otherwise the catalog's price for the route — the same figures the `/runs/{id}/usage` rows sum. All-zero counts mean the stage made no model calls. Unlike the usage rows, which sum every visit of a node, this covers only this visit. # ── File Diff Schemas ────────────────────────────────────────────── FileCheckpoint: description: A named checkpoint within a run, used to filter file diffs. type: object required: - id - label properties: id: type: string description: Checkpoint identifier. example: cp-3 label: type: string description: Human-readable label for the checkpoint. example: "Checkpoint 3 — Review Changes" DiffFile: description: A file's contents at one side of a diff. type: object required: - name - contents properties: name: type: string description: File path relative to the repository root. example: src/commands/run.ts contents: type: ["string", "null"] description: "Full contents at this side. Live path: empty string for added/deleted/binary/sensitive/symlink/submodule/truncated entries (the placeholder flags drive rendering). Degraded path: null for every entry (including placeholder-flagged ones), because the server only holds a checkpoint patch and cannot reconstruct full file bytes — distinguish degraded from live by `meta.degraded`." example: 'import { parseArgs } from "node:util";' FileDiff: description: | A before/after pair showing changes to a single file. Contents conventions for non-modify cases: - Added: `old_file.contents` is empty string; `new_file` holds the added contents. - Deleted: `new_file.contents` is empty string; `old_file` holds the removed contents. - Renamed (no content change): both sides hold identical contents; `old_file.name != new_file.name`. - Symlink / submodule / binary / sensitive / truncated: contents are empty strings; consumers must render a placeholder based on the flag set. - Degraded responses: contents are null on every entry; regular text diffs include `unified_patch`. type: object required: - old_file - new_file properties: old_file: $ref: "#/components/schemas/DiffFile" new_file: $ref: "#/components/schemas/DiffFile" change_kind: type: string description: Optional classification of the change. Clients that don't recognize a value should fall back to inspecting the old/new contents. enum: - added - modified - deleted - renamed - symlink - submodule example: modified truncated: type: boolean description: When `true`, `new_file.contents` and `old_file.contents` are empty strings because the file exceeded a cap (see `truncation_reason`). example: false truncation_reason: type: string description: Reason this file's contents were omitted. Absent when `truncated` is `false` or omitted. enum: - file_too_large - budget_exhausted binary: type: boolean description: When `true`, the file is non-textual; `contents` on both sides are empty strings. example: false sensitive: type: boolean description: When `true`, the file path matched the server's sensitive-path denylist; `contents` on both sides are empty strings regardless of truncation or binary flags. example: false unified_patch: type: ["string", "null"] description: Per-file unified-patch text (the `diff --git` section verbatim). Populated only for regular non-flagged text-diff entries in degraded mode. Absent for sensitive, binary, symlink, submodule, truncated, and live-path entries. DiffStats: description: | Aggregate `+/-` line counts across all files in a diff. Binary, sensitive, symlink, and submodule files contribute 0/0 since they have no line-level diff. Both fields are 0 for empty / pre-start envelopes. type: object required: - additions - deletions properties: additions: type: integer description: Total lines added. example: 567 deletions: type: integer description: Total lines deleted. example: 234 DiffSummary: description: Cheap aggregate file and line counts for a run diff. type: object required: - files_changed - additions - deletions properties: files_changed: type: integer description: Total number of changed files, including binary files. example: 42 additions: type: integer description: Total lines added across text files. example: 567 deletions: type: integer description: Total lines deleted across text files. example: 234 RunDiff: description: Patch text and aggregate counts captured for a run-level diff. type: object properties: patch: type: ["string", "null"] summary: oneOf: - $ref: "#/components/schemas/DiffSummary" - type: "null" RunFilesMeta: description: | Metadata for a `PaginatedRunFileList` response. Replaces `PaginationMeta` on the files endpoint — the naturally-bounded list does not use cursor pagination but exposes caps and a degraded-response path instead. type: object required: - source - scope - truncated - total_changed - stats properties: source: type: string description: Source used to materialize this response. `sandbox` honors the requested scope from the run-owned sandbox; `final_patch` is fallback committed/final diff data from stored run state. enum: - sandbox - final_patch scope: type: string description: Diff scope materialized for this response. enum: - committed - uncommitted - all - range stats: $ref: "#/components/schemas/DiffStats" truncated: type: boolean description: True when any cap (file count, per-file size, or aggregate size) was hit for this response. example: false files_omitted_by_budget: type: integer description: Number of files dropped because the aggregate 5 MiB budget was exhausted. Zero or absent when no files were dropped for budget reasons. example: 0 total_changed: type: integer description: Total files changed in the run (before caps were applied). May exceed `data.length` when truncation occurred. example: 3 to_sha: type: string description: Head SHA the diff (or patch) was resolved against. pattern: "^[0-9a-f]{7,40}$" example: "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0" to_sha_committed_at: type: string format: date-time description: Commit time of `to_sha`, used by the UI for the "Checkpoint Xm ago" freshness label on Running runs. degraded: type: boolean description: When `true`, every entry in `data` has null `contents` on both sides; non-sensitive non-flagged entries also include `unified_patch`. Entries flagged `sensitive` / `binary` / `symlink` / `submodule` / `truncated` render via the same placeholders used in the live path (the flags drive rendering; contents are null in degraded mode regardless). The data shape is otherwise identical to the live path. example: false degraded_reason: type: string description: Why the response degraded. Absent when `degraded` is `false` or omitted. enum: - sandbox_unreachable - sandbox_gone - provider_unsupported PaginatedRunFileList: description: | List of file diffs produced by a run, with metadata describing truncation and degraded-response state. Naturally bounded: at most 200 files per response. Consumers should inspect `meta.truncated` rather than assuming `data.length` equals the run's total change count. type: object required: - data - meta properties: data: type: array items: $ref: "#/components/schemas/FileDiff" meta: $ref: "#/components/schemas/RunFilesMeta" RunCommitParent: description: Parent commit pointer. type: object required: - sha - short_sha properties: sha: type: string pattern: "^[0-9a-f]{7,40}$" short_sha: type: string pattern: "^[0-9a-f]{7,12}$" RunCommitPerson: description: Git author or committer identity. type: object required: - name - email - date properties: name: type: string email: type: string date: type: ["string", "null"] format: date-time RunCommit: description: A Git commit on a run branch. type: object required: - sha - short_sha - parents - author - committer - subject - message - trailers - tree_sha properties: sha: type: string pattern: "^[0-9a-f]{7,40}$" short_sha: type: string pattern: "^[0-9a-f]{7,12}$" parents: type: array items: $ref: "#/components/schemas/RunCommitParent" author: $ref: "#/components/schemas/RunCommitPerson" committer: $ref: "#/components/schemas/RunCommitPerson" subject: type: string body: type: ["string", "null"] message: type: string trailers: type: object additionalProperties: type: string tree_sha: type: ["string", "null"] pattern: "^[0-9a-f]{7,40}$" RunCommitsMeta: description: Metadata for a `PaginatedRunCommitList` response. type: object required: - source - base_sha - head_sha - limit - total_returned - truncated properties: source: type: string enum: - sandbox base_sha: type: string pattern: "^[0-9a-f]{7,40}$" head_sha: type: string pattern: "^[0-9a-f]{7,40}$" limit: type: integer minimum: 1 maximum: 100 total_returned: type: integer minimum: 0 truncated: type: boolean PaginatedRunCommitList: description: Git commits on a run branch since the run base. type: object required: - data - meta properties: data: type: array items: $ref: "#/components/schemas/RunCommit" meta: $ref: "#/components/schemas/RunCommitsMeta" # ── Usage Schemas ──────────────────────────────────────────────────── RunUsageStage: description: Token counts and cost for one workflow node within a run. Rows are grouped by node; usage and timing sum every visit of that node. type: object required: - stage - model - usage - timing properties: stage: $ref: "#/components/schemas/UsageStageRef" model: description: Latest usage-bearing visit model for this node; null when no visit used an LLM model. oneOf: - $ref: "#/components/schemas/UsageModelRef" - type: "null" usage: $ref: "#/components/schemas/Usage" timing: $ref: "#/components/schemas/StageTiming" description: | Per-node timing summed across every visit. `wall_time_ms` is the sum of visit wall times; the active breakdown sums work timing. started_at: type: ["string", "null"] format: date-time description: Wall-clock time the latest attempt of this stage started, if known. example: "2026-04-29T12:34:56Z" state: oneOf: - $ref: "#/components/schemas/StageState" - type: "null" description: Lifecycle state of the stage. Use to detect in-flight rows for client-side runtime ticking. RunUsageTotals: description: Aggregate usage totals across all stages of a run. type: object required: - timing - usage properties: timing: $ref: "#/components/schemas/RunTiming" description: | Run-level timing rollup. `wall_time_ms` is summed across stage visits; active timing sums work across visits. usage: $ref: "#/components/schemas/Usage" description: >- Tokens and cost summed across every stage visit. The cost is known only when every visit that used tokens was priced. UsageByModel: description: Usage grouped by model. type: object required: - model - stages - usage properties: model: $ref: "#/components/schemas/UsageModelRef" stages: type: integer description: Number of usage-bearing stage visits that used this model. example: 2 usage: $ref: "#/components/schemas/Usage" RunUsage: description: Complete usage breakdown for a single run. type: object required: - stages - totals - by_model properties: stages: type: array description: Per-node usage breakdown. Each row sums usage and runtime across all visits of that node. items: $ref: "#/components/schemas/RunUsageStage" totals: $ref: "#/components/schemas/RunUsageTotals" by_model: type: array description: Usage grouped by model. items: $ref: "#/components/schemas/UsageByModel" AggregateUsage: description: Aggregate token counts and costs across all runs since server start. type: object required: - totals - by_model properties: totals: $ref: "#/components/schemas/AggregateUsageTotals" by_model: type: array description: Usage grouped by model. items: $ref: "#/components/schemas/UsageByModel" PreviewUrlRequest: description: Request body for generating a preview URL from a sandbox port. type: object required: - port - expires_in_secs properties: port: type: integer description: Port number exposed by the sandbox. example: 3000 expires_in_secs: type: integer description: Time-to-live for the preview URL in seconds. minimum: 1 maximum: 86400 example: 3600 signed: type: boolean description: When true, return a signed URL that does not require a preview token header. default: false PreviewUrlResponse: description: Response containing the generated preview URL. type: object required: - url properties: url: type: string description: Preview URL. example: "https://preview.example.com/sb-a1b2c3d4/3000" token: type: string description: Preview token header value for unsigned preview URLs. example: "preview-token-123" SshAccessRequest: description: Request body for creating sandbox access for a sandbox-backed run. type: object required: - ttl_minutes properties: ttl_minutes: type: number description: Time-to-live for time-limited access commands in minutes. Ignored by providers whose commands are not time-limited. minimum: 1 maximum: 1440 example: 60 SshAccessResponse: description: Response containing a command for connecting to the sandbox. type: object required: - command properties: command: type: string description: Command to connect to the sandbox. example: docker exec -it fabro-run-01HY0000000000000000000000 sh -lc 'cd /workspace/fabro && exec sh -l' SandboxState: description: The sandbox driver's lifecycle state for a sandbox. The provider's own state string is preserved in `SandboxStatus.provider_state`. A reader must treat a value it does not know as `unknown`. type: string enum: - creating - starting - running - stopping - stopped - pausing - paused - resuming - archiving - archived - restoring - resizing - forking - snapshotting - deleting - deleted - error - unknown SandboxKind: description: The kind of isolation a sandbox was provisioned with, as observed by the driver. Not an isolation guarantee. type: string enum: - container - virtual_machine - unknown SandboxWorkspaceOwnership: description: Who owns a local sandbox's workspace directory. `designated` is a caller-owned directory that deleting the sandbox never touches; `managed` is a directory the driver created and removes. type: string enum: - designated - managed SandboxResources: description: Compute resources of a sandbox, in the units the field names give. A field is null when the provider does not report a value or applies its default. type: object properties: cpu_cores: type: ["integer", "null"] format: int64 minimum: 0 memory_mb: type: ["integer", "null"] format: int64 minimum: 0 disk_mb: type: ["integer", "null"] format: int64 minimum: 0 gpus: type: ["integer", "null"] format: int64 minimum: 0 SandboxNetworkPolicy: description: The network policy in force for a sandbox. A policy without parameters is its name; an allow list carries its entries. oneOf: - type: string enum: - provider_default - allow_all - block - type: object required: [cidr_allow_list] properties: cidr_allow_list: type: object required: [cidrs] properties: cidrs: type: array items: type: string - type: object required: [domain_allow_list] properties: domain_allow_list: type: object required: [domains] properties: domains: type: array items: type: string SandboxStatus: description: What the sandbox driver reports about a sandbox. Only `id` and `state` are always present; every other field is null or empty when the provider does not report it. type: object required: - id - state properties: id: type: string description: The provider's stable identifier for the sandbox. name: type: ["string", "null"] description: The provider's display name, which is not the stable identifier. state: $ref: "#/components/schemas/SandboxState" provider_state: type: string default: "" description: The provider's own state string, for display and debugging. error_reason: type: ["string", "null"] resources: oneOf: - $ref: "#/components/schemas/SandboxResources" - type: "null" sandbox_kind: oneOf: - $ref: "#/components/schemas/SandboxKind" - type: "null" region: type: ["string", "null"] description: The provider region or target the sandbox runs in. labels: type: object additionalProperties: type: string description: Provider-stored labels, including fabro's ownership labels. image: type: ["string", "null"] description: The image the sandbox runs, when the provider knows it (a Docker container's image reference). snapshot: type: ["string", "null"] description: The snapshot the sandbox was created from, when the provider knows it (a Daytona snapshot name). network: oneOf: - $ref: "#/components/schemas/SandboxNetworkPolicy" - type: "null" description: The network policy in force, when the provider can read it back. workspace_ownership: oneOf: - $ref: "#/components/schemas/SandboxWorkspaceOwnership" - type: "null" description: Local sandboxes only. web_url: type: ["string", "null"] description: The provider's console page for the sandbox, when it has one. created_at: type: ["string", "null"] format: date-time updated_at: type: ["string", "null"] format: date-time description: The provider's most recent activity or update timestamp for the sandbox. SandboxDetails: description: The sandbox owned by a run, as fabro's record of it and the sandbox driver's status. type: object required: - sandbox - status properties: sandbox: $ref: "#/components/schemas/RunSandboxInstance" status: $ref: "#/components/schemas/SandboxStatus" SandboxInfo: description: One sandbox of fabro's provider-backed inventory, as the provider fabro connected it through and the sandbox driver's status. type: object required: - provider - status properties: provider: $ref: "#/components/schemas/SandboxProviderKind" status: $ref: "#/components/schemas/SandboxStatus" SandboxProviderLookupError: description: Provider error captured during fail-soft sandbox inventory lookup. type: object required: - provider - message properties: provider: $ref: "#/components/schemas/SandboxProviderKind" message: type: string SandboxListMeta: description: Metadata for provider-backed sandbox inventory. type: object required: - provider_errors properties: provider_errors: type: array items: $ref: "#/components/schemas/SandboxProviderLookupError" SandboxListResponse: description: Non-paginated provider-backed sandbox inventory response. type: object required: - data - meta properties: data: type: array items: $ref: "#/components/schemas/SandboxInfo" meta: $ref: "#/components/schemas/SandboxListMeta" SandboxFileEntry: description: A directory entry in a run sandbox. type: object required: - name - is_dir properties: name: type: string description: Basename of the entry. is_dir: type: boolean description: Whether the entry is a directory. size: type: integer format: int64 description: File size in bytes when known. SandboxFileListResponse: description: Non-paginated list of sandbox directory entries. type: object required: - data properties: data: type: array items: $ref: "#/components/schemas/SandboxFileEntry" SandboxService: description: A TCP port a process inside a run sandbox listens on, as the sandbox driver reports it. type: object required: - port - addresses - processes - preview_supported properties: port: type: integer minimum: 1 maximum: 65535 description: Listening TCP port. example: 3000 addresses: type: array description: Local bind addresses the sandbox reports for the port. items: type: string example: ["127.0.0.1:3000", "[::]:3000"] processes: type: array description: The listening processes, when the sandbox can name them (`node`, or `pid=1234`). Empty when it cannot. items: type: string example: ["node"] preview_supported: type: boolean description: Whether the provider supports an external preview URL for this port. example: true SandboxServiceListResponse: description: Non-paginated list of listening TCP services in a run sandbox. type: object required: - data properties: data: type: array items: $ref: "#/components/schemas/SandboxService" VncPreviewResponse: description: Response containing a signed noVNC preview URL for a Daytona sandbox. type: object required: - url - provider - port - expires_in_secs properties: url: type: string description: Signed noVNC preview URL. example: "https://preview.example.com/sb-a1b2c3d4/6080?token=..." provider: type: string description: Sandbox provider that produced the VNC preview. example: daytona port: type: integer minimum: 1 maximum: 65535 description: noVNC port exposed by the sandbox. example: 6080 expires_in_secs: type: integer minimum: 1 description: Signed URL time-to-live in seconds. example: 3600 # ── Insights Schemas ───────────────────────────────────────────────── SavedQuery: description: A saved SQL query for the insights editor. type: object required: - id - name - sql - created_at - updated_at properties: id: type: string description: Unique query identifier. example: "1" name: type: string description: Human-readable query name. example: Run duration by workflow sql: type: string description: SQL query text. example: "SELECT workflow_name, AVG(duration_seconds) FROM runs GROUP BY 1" created_at: type: string format: date-time description: Timestamp when the query was saved. example: "2026-03-01T10:00:00Z" updated_at: type: string format: date-time description: Timestamp when the query was last modified. example: "2026-03-05T14:30:00Z" SaveQueryRequest: description: Request body for creating or updating a saved query. type: object required: - name - sql properties: name: type: string description: Human-readable query name. example: Run duration by workflow sql: type: string description: SQL query text. example: "SELECT workflow_name, AVG(duration_seconds) FROM runs GROUP BY 1" ExecuteQueryRequest: description: Request body for executing an ad-hoc SQL query. type: object required: - sql properties: sql: type: string description: SQL query to execute. example: "SELECT workflow_name, COUNT(*) FROM runs GROUP BY 1" ExecuteQueryResponse: description: Columnar result set from an executed query. type: object required: - columns - rows - elapsed - row_count properties: columns: type: array description: Column names in the result set. items: type: string example: ["workflow_name", "count"] rows: type: array description: Result rows, each an array of values matching the column order. items: type: array items: oneOf: - type: string - type: number - type: boolean - type: "null" elapsed: type: number description: Query execution time in seconds. example: 0.342 row_count: type: integer description: Number of rows returned. example: 3 HistoryEntry: description: A previously executed query in the history log. type: object required: - id - sql - timestamp - elapsed - row_count properties: id: type: string description: Unique history entry identifier. example: h1 sql: type: string description: SQL query that was executed. example: "SELECT workflow_name, COUNT(*) FROM runs GROUP BY 1" timestamp: type: string format: date-time description: ISO 8601 timestamp of execution. example: "2025-09-15T14:00:00Z" elapsed: type: number description: Query execution time in seconds. example: 0.342 row_count: type: integer description: Number of rows returned. example: 6 # ── Settings Schemas ───────────────────────────────────────────────── ServerSettings: description: Current in-memory server settings view. type: object required: [server] properties: server: $ref: "#/components/schemas/ServerNamespace" ServerNamespace: type: object required: - listen - api - web - auth - sandbox - storage - artifacts - scheduler - logging - integrations properties: listen: $ref: "#/components/schemas/ServerListenSettings" api: $ref: "#/components/schemas/ServerApiSettings" web: $ref: "#/components/schemas/ServerWebSettings" auth: $ref: "#/components/schemas/ServerAuthSettings" sandbox: $ref: "#/components/schemas/ServerSandboxSettings" storage: $ref: "#/components/schemas/ServerStorageSettings" artifacts: $ref: "#/components/schemas/ServerArtifactsSettings" scheduler: $ref: "#/components/schemas/ServerSchedulerSettings" logging: $ref: "#/components/schemas/ServerLoggingSettings" integrations: $ref: "#/components/schemas/ServerIntegrationsSettings" ServerListenSettings: oneOf: - $ref: "#/components/schemas/ServerListenTcpSettings" - $ref: "#/components/schemas/ServerListenUnixSettings" ServerListenTcpSettings: type: object required: [type, address] properties: type: type: string enum: [tcp] address: type: string ServerListenUnixSettings: type: object required: [type, path] properties: type: type: string enum: [unix] path: type: string ServerApiSettings: type: object required: [url] properties: url: type: ["string", "null"] ServerWebSettings: type: object required: [enabled, url] properties: enabled: type: boolean url: type: string ServerAuthSettings: type: object required: [methods, github] properties: methods: type: array items: $ref: "#/components/schemas/ServerAuthMethod" github: $ref: "#/components/schemas/ServerAuthGithubSettings" ServerAuthMethod: type: string enum: [dev-token, github] ServerAuthGithubSettings: type: object required: [allowed_usernames] properties: allowed_usernames: type: array items: type: string ServerSandboxSettings: type: object required: [providers] properties: providers: $ref: "#/components/schemas/ServerSandboxProvidersSettings" ServerSandboxProvidersSettings: description: | Sandbox provider policy keyed by provider kind. The bundled kinds (`local`, `docker`, `daytona`) are always present; any other key names a sandbox-driver plugin and carries its launch settings. type: object additionalProperties: $ref: "#/components/schemas/ServerSandboxProviderSettings" ServerSandboxProviderSettings: type: object required: [enabled] properties: enabled: type: boolean plugin: $ref: "#/components/schemas/SandboxPluginSettings" SandboxPluginSettings: description: How the server launches a sandbox-driver plugin executable. type: object properties: path: type: string description: Executable path. Absent means `sandbox-driver-` on `PATH`. sha256: type: string description: Pinned SHA-256 of the executable, hex. dev: type: boolean description: Allow launching without a checksum. args: type: array items: type: string env: $ref: "#/components/schemas/StringMap" inherit_env: type: array items: type: string ServerStorageSettings: type: object required: [root] properties: root: type: string ServerArtifactsSettings: type: object required: [prefix, store] properties: prefix: type: string store: $ref: "#/components/schemas/ObjectStoreSettings" ObjectStoreSettings: oneOf: - $ref: "#/components/schemas/ObjectStoreLocalSettings" - $ref: "#/components/schemas/ObjectStoreS3Settings" ObjectStoreLocalSettings: type: object required: [type, root] properties: type: type: string enum: [local] root: type: string ObjectStoreS3Settings: type: object required: [type, bucket, region, endpoint, path_style] properties: type: type: string enum: [s3] bucket: type: string region: type: string endpoint: type: ["string", "null"] path_style: type: boolean ServerSchedulerSettings: type: object required: [max_concurrent_runs] properties: max_concurrent_runs: type: integer ServerLoggingSettings: type: object required: [level, destination] properties: level: type: ["string", "null"] destination: $ref: "#/components/schemas/LogDestination" LogDestination: type: string enum: [file, stdout] ServerIntegrationsSettings: type: object required: [github, slack] properties: github: $ref: "#/components/schemas/GithubIntegrationSettings" slack: $ref: "#/components/schemas/SlackIntegrationSettings" GithubIntegrationSettings: type: object required: - enabled - strategy - app_id - client_id - slug - webhooks properties: enabled: type: boolean strategy: $ref: "#/components/schemas/GithubIntegrationStrategy" app_id: type: ["string", "null"] client_id: type: ["string", "null"] slug: type: ["string", "null"] webhooks: oneOf: - $ref: "#/components/schemas/IntegrationWebhooksSettings" - type: "null" GithubIntegrationStrategy: type: string enum: [token, app] SlackIntegrationSettings: type: object required: [enabled, default_channel] properties: enabled: type: boolean default_channel: type: ["string", "null"] IntegrationWebhooksSettings: type: object required: [strategy] properties: strategy: oneOf: - $ref: "#/components/schemas/WebhookStrategy" - type: "null" WebhookStrategy: type: string enum: [tailscale_funnel, server_url] WorkflowSettings: description: | The persisted dense `WorkflowSettings` snapshot used for a specific run. This matches the resolved run settings recorded at launch time. type: object required: - project - workflow - environments - run properties: project: $ref: "#/components/schemas/ProjectNamespace" workflow: $ref: "#/components/schemas/WorkflowNamespace" environments: type: object additionalProperties: $ref: "#/components/schemas/EnvironmentSettings" run: $ref: "#/components/schemas/RunNamespace" InterpString: description: Config string that can contain typed interpolation tokens. type: string StringMap: type: object additionalProperties: type: string TomlValue: description: Arbitrary TOML-compatible value. ProjectNamespace: type: object required: [name, description, metadata] properties: name: type: ["string", "null"] description: type: ["string", "null"] metadata: $ref: "#/components/schemas/StringMap" WorkflowNamespace: type: object required: [name, description, graph, metadata] properties: name: type: ["string", "null"] description: type: ["string", "null"] graph: type: string metadata: $ref: "#/components/schemas/StringMap" RunNamespace: type: object required: - goal - working_dir - metadata - inputs - model - git - prepare - execution - checkpoint - clone - run_branch - environment - notifications - interviews - agent - hooks - scm - pull_request - artifacts - integrations properties: goal: oneOf: - $ref: "#/components/schemas/RunGoal" - type: "null" working_dir: oneOf: - $ref: "#/components/schemas/InterpString" - type: "null" metadata: $ref: "#/components/schemas/StringMap" inputs: type: object additionalProperties: $ref: "#/components/schemas/TomlValue" model: $ref: "#/components/schemas/RunModelSettings" git: $ref: "#/components/schemas/RunGitSettings" prepare: $ref: "#/components/schemas/RunPrepareSettings" execution: $ref: "#/components/schemas/RunExecutionSettings" checkpoint: $ref: "#/components/schemas/RunCheckpointSettings" clone: $ref: "#/components/schemas/RunCloneSettings" run_branch: $ref: "#/components/schemas/RunBranchSettings" environment: $ref: "#/components/schemas/RunEnvironmentSettings" notifications: type: object additionalProperties: $ref: "#/components/schemas/NotificationRouteSettings" interviews: $ref: "#/components/schemas/RunInterviewsSettings" agent: $ref: "#/components/schemas/RunAgentSettings" hooks: type: array items: $ref: "#/components/schemas/HookDefinition" scm: $ref: "#/components/schemas/RunScmSettings" pull_request: oneOf: - $ref: "#/components/schemas/PullRequestSettings" - type: "null" artifacts: $ref: "#/components/schemas/ArtifactsSettings" integrations: $ref: "#/components/schemas/RunIntegrationsSettings" RunIntegrationsSettings: type: object required: [github] properties: github: $ref: "#/components/schemas/RunIntegrationsGithubSettings" RunIntegrationsGithubSettings: type: object required: [permissions] properties: permissions: type: object additionalProperties: type: string additional_repositories: type: array description: | Additional GitHub repositories, beyond the implicit run origin, that the minted GITHUB_TOKEN must cover. Each entry is a full `owner/repository` slug; every repository must share one owner with the run origin. Omitted when empty; settings persisted before this field existed deserialize to an empty set. items: type: string uniqueItems: true RunGoal: oneOf: - $ref: "#/components/schemas/RunGoalInline" - $ref: "#/components/schemas/RunGoalFile" RunGoalInline: type: object required: [type, value] properties: type: type: string enum: [inline] value: $ref: "#/components/schemas/InterpString" RunGoalFile: type: object required: [type, value] properties: type: type: string enum: [file] value: $ref: "#/components/schemas/InterpString" ModelRef: type: string description: | A fallback model reference. Bare values name a provider, canonical model ID, or alias. Provider-qualified values use `provider:selector`; the selector may be a canonical model ID, alias, or provider API ID and may contain `/` or additional colons. A value is treated as qualified only when the text before the first `:` names a known provider, so model IDs that contain a colon — ollama `name:tag` values, Bedrock inference-profile IDs — stay whole. Legacy `provider/model` references remain accepted. example: openrouter:moonshotai/kimi-k3 RunModelSettings: type: object required: [provider, name, fallbacks] properties: provider: type: ["string", "null"] name: type: ["string", "null"] fallbacks: type: object description: > Ordered fallback targets keyed by the originally requested model. Each chain is independent; selecting a fallback target does not activate that target model's own chain. additionalProperties: type: array items: $ref: "#/components/schemas/ModelRef" controls: $ref: "#/components/schemas/RunModelControls" RunModelControls: type: object description: > Run-level default values for typed model controls. Node and style attributes still win over these defaults. required: [reasoning_effort, speed] properties: reasoning_effort: type: ["string", "null"] speed: type: ["string", "null"] RunGitSettings: type: object required: [author] properties: author: oneOf: - $ref: "#/components/schemas/GitAuthorSettings" - type: "null" GitAuthorSettings: type: object required: [name, email] properties: name: type: ["string", "null"] email: type: ["string", "null"] RunPrepareSettings: type: object required: [steps, timeout_ms] properties: steps: type: array items: $ref: "#/components/schemas/PreparedStep" timeout_ms: type: integer format: int64 PreparedStep: description: | A single resolved prepare step. The runnable part preserves the script-vs-argv distinction via the `type` discriminator: a `script` is a raw shell snippet kept verbatim, while a `command` is an argv whose elements are shell-quoted and joined at the run boundary (after `{{ secrets.* }}` resolution) so an interpolated value cannot inject shell syntax. Optional per-step `env` is shared by both shapes. type: object required: [type] oneOf: - $ref: "#/components/schemas/PreparedScriptStep" - $ref: "#/components/schemas/PreparedCommandStep" discriminator: propertyName: type mapping: script: "#/components/schemas/PreparedScriptStep" command: "#/components/schemas/PreparedCommandStep" PreparedScriptStep: type: object required: [type, script] properties: type: type: string enum: [script] script: type: string env: $ref: "#/components/schemas/StringMap" PreparedCommandStep: type: object required: [type, command] properties: type: type: string enum: [command] command: type: array items: type: string env: $ref: "#/components/schemas/StringMap" RunExecutionSettings: type: object required: [mode, approval] properties: mode: $ref: "#/components/schemas/RunMode" approval: $ref: "#/components/schemas/ApprovalMode" RunMode: type: string enum: [normal, dry_run] ApprovalMode: type: string enum: [prompt, auto] RunCheckpointSettings: type: object required: [exclude_globs, skip_git_hooks] properties: exclude_globs: type: array items: type: string skip_git_hooks: type: boolean default: false description: | Accepted for compatibility. Fabro-managed run-branch checkpoint commits never run local Git commit hooks: the sandbox driver disables repository hooks on every git command it runs. Does not affect Fabro `[[run.hooks]]`. Defaults to false. RunCloneSettings: type: object required: [enabled] properties: enabled: type: boolean depth: type: integer format: int32 minimum: 0 default: 100 description: Git history depth. Set to 0 to clone full history. RunBranchSettings: type: object required: [enabled, push] properties: enabled: type: boolean push: type: boolean RunEnvironmentSettings: type: object required: [id, provider, image, resources, network, lifecycle, labels, env] properties: id: type: string provider: $ref: "#/components/schemas/SandboxProviderKind" cwd: type: ["string", "null"] description: Local-provider command working directory for this environment. Docker and Daytona ignore this value. example: /srv/fabro/workspaces/team-a image: $ref: "#/components/schemas/EnvironmentImageSettings" resources: $ref: "#/components/schemas/EnvironmentResourcesSettings" network: $ref: "#/components/schemas/EnvironmentNetworkSettings" lifecycle: $ref: "#/components/schemas/EnvironmentLifecycleSettings" labels: $ref: "#/components/schemas/StringMap" env: type: object additionalProperties: $ref: "#/components/schemas/InterpString" EnvironmentSettings: type: object required: [provider, image, resources, network, lifecycle, labels, env] properties: provider: $ref: "#/components/schemas/SandboxProviderKind" cwd: type: ["string", "null"] description: Local-provider command working directory for this environment. Docker and Daytona ignore this value. example: /srv/fabro/workspaces/team-a image: $ref: "#/components/schemas/EnvironmentImageSettings" resources: $ref: "#/components/schemas/EnvironmentResourcesSettings" network: $ref: "#/components/schemas/EnvironmentNetworkSettings" lifecycle: $ref: "#/components/schemas/EnvironmentLifecycleSettings" labels: $ref: "#/components/schemas/StringMap" env: type: object additionalProperties: $ref: "#/components/schemas/InterpString" EnvironmentImageSettings: type: object required: [docker, dockerfile] properties: docker: type: ["string", "null"] dockerfile: oneOf: - $ref: "#/components/schemas/DockerfileSource" - type: "null" EnvironmentResourcesSettings: type: object required: [cpu, memory, disk] properties: cpu: type: ["integer", "null"] format: int32 memory: type: ["string", "null"] disk: type: ["string", "null"] EnvironmentNetworkSettings: type: object required: [mode, allow] properties: mode: $ref: "#/components/schemas/EnvironmentNetworkMode" allow: type: array items: type: string EnvironmentNetworkMode: type: string enum: [allow_all, block, cidr_allow_list] EnvironmentLifecycleSettings: type: object required: [preserve, stop_on_terminal, auto_stop] properties: preserve: type: boolean stop_on_terminal: type: boolean auto_stop: type: ["string", "null"] DockerfileSource: oneOf: - $ref: "#/components/schemas/DockerfileSourceInline" - $ref: "#/components/schemas/DockerfileSourcePath" DockerfileSourceInline: type: object required: [type, value] properties: type: type: string enum: [inline] value: type: string DockerfileSourcePath: type: object required: [type, path] properties: type: type: string enum: [path] path: type: string NotificationRouteSettings: type: object required: [enabled, provider, events, slack] properties: enabled: type: boolean provider: type: ["string", "null"] events: type: array items: type: string slack: oneOf: - $ref: "#/components/schemas/NotificationProviderSettings" - type: "null" NotificationProviderSettings: type: object required: [channel] properties: channel: type: ["string", "null"] RunInterviewsSettings: type: object required: [provider, slack] properties: provider: type: ["string", "null"] slack: oneOf: - $ref: "#/components/schemas/InterviewProviderSettings" - type: "null" InterviewProviderSettings: type: object required: [channel] properties: channel: type: ["string", "null"] RunAgentSettings: type: object required: [fabro_tools, mcps] properties: fabro_tools: type: boolean mcps: type: object additionalProperties: $ref: "#/components/schemas/McpServerSettings" McpServerSettings: type: object required: [name, transport, startup_timeout_secs, tool_timeout_secs] properties: name: type: string transport: $ref: "#/components/schemas/McpTransport" startup_timeout_secs: type: integer format: int64 tool_timeout_secs: type: integer format: int64 McpTransport: description: | MCP server transport configuration. The `type` field selects stdio, HTTP, or sandbox transport. Unknown `type` discriminator values are reported as domain validation errors with HTTP 422. oneOf: - $ref: "#/components/schemas/McpTransportStdio" - $ref: "#/components/schemas/McpTransportHttp" - $ref: "#/components/schemas/McpTransportSandbox" discriminator: propertyName: type mapping: stdio: "#/components/schemas/McpTransportStdio" http: "#/components/schemas/McpTransportHttp" sandbox: "#/components/schemas/McpTransportSandbox" McpTransportStdio: description: Stdio transport that launches a local MCP server subprocess. type: object additionalProperties: false required: [type, command, env] properties: type: type: string enum: [stdio] command: type: array minItems: 1 description: Command and arguments used to launch the MCP server. items: type: string env: $ref: "#/components/schemas/StringMap" McpTransportHttp: description: HTTP transport that connects to a remote MCP server URL. type: object additionalProperties: false required: [type, url, headers] properties: type: type: string enum: [http] protocol: $ref: "#/components/schemas/McpHttpProtocol" url: type: string format: uri headers: $ref: "#/components/schemas/StringMap" McpTransportSandbox: description: Sandbox transport that launches the MCP server inside the run sandbox and connects over HTTP. type: object additionalProperties: false required: [type, command, port, env] properties: type: type: string enum: [sandbox] protocol: $ref: "#/components/schemas/McpHttpProtocol" command: type: array minItems: 1 description: Command and arguments used to launch the in-sandbox MCP server. items: type: string port: type: integer format: int32 minimum: 1 maximum: 65535 env: $ref: "#/components/schemas/StringMap" McpHttpProtocol: description: Wire protocol used by HTTP and sandbox MCP transports. type: string enum: [streamable_http, sse] default: streamable_http HookDefinition: type: object required: [name, event, command, matcher, blocking, timeout_ms, sandbox] properties: name: type: ["string", "null"] event: $ref: "#/components/schemas/HookEvent" command: type: ["string", "null"] type: type: ["string", "null"] enum: [command, http, prompt, agent, null] url: type: ["string", "null"] headers: oneOf: - $ref: "#/components/schemas/StringMap" - type: "null" description: >- Optional HTTP headers for an http hook. Values support `{{ vars.NAME }}` interpolation, substituted when the run is created; a token left unresolved at fire time blocks the hook (fail-closed). tls: $ref: "#/components/schemas/TlsMode" prompt: type: ["string", "null"] model: type: ["string", "null"] max_tool_rounds: type: ["integer", "null"] format: int32 matcher: type: ["string", "null"] blocking: type: ["boolean", "null"] timeout_ms: type: ["integer", "null"] format: int64 sandbox: type: ["boolean", "null"] HookEvent: type: string enum: - run_start - run_complete - run_failed - stage_start - stage_complete - stage_failed - stage_retrying - edge_selected - parallel_start - parallel_complete - sandbox_ready - sandbox_cleanup - checkpoint_saved - pre_tool_use - post_tool_use - post_tool_use_failure TlsMode: type: string enum: [verify, no_verify, off] RunScmSettings: type: object required: [provider, owner, repository, github] properties: provider: type: ["string", "null"] owner: type: ["string", "null"] repository: type: ["string", "null"] github: oneOf: - $ref: "#/components/schemas/ScmGitHubSettings" - type: "null" ScmGitHubSettings: type: object PullRequestSettings: type: object required: [enabled, draft, auto_merge, merge_strategy] properties: enabled: type: boolean draft: type: boolean auto_merge: type: boolean merge_strategy: $ref: "#/components/schemas/MergeMethod" ArtifactsSettings: type: object required: [include] properties: include: type: array items: type: string SystemInfoResponse: description: Runtime information for the active Fabro server process. type: object properties: version: type: string description: Server version string. server_url: type: string description: Configured public server URL for browser and CLI authentication flows. git_sha: type: ["string", "null"] description: Build git SHA when available. build_date: type: ["string", "null"] description: Build date when available. profile: type: ["string", "null"] description: Cargo build profile (e.g. `release`, `debug`) when available. os: type: string description: Target operating system. arch: type: string description: Target CPU architecture. storage_engine: type: string description: Backing run storage engine. storage_dir: type: string description: Configured storage directory. uptime_secs: type: integer format: int64 description: Seconds since this server process started. runs: $ref: "#/components/schemas/SystemRunCounts" sandbox_provider: type: string description: Effective sandbox provider for launched runs. SystemRunCounts: description: Counts of known runs in the active server process. type: object properties: total: type: integer format: int64 description: Total runs tracked by the server process. active: type: integer format: int64 description: Runs currently pending, runnable, or executing. scheduler_slots_used: type: integer format: int64 description: Runs currently occupying scheduler concurrency slots. SystemIntegrationsResponse: description: Runtime status for server integrations. type: object required: [data] properties: data: type: array items: $ref: "#/components/schemas/SystemIntegrationStatus" SystemIntegrationStatus: description: Runtime status for one server integration. type: object required: - provider - enabled - configured - status - missing_credentials - connection - metadata properties: provider: $ref: "#/components/schemas/IntegrationProvider" enabled: type: boolean description: Whether configuration allows this integration to run. configured: type: boolean description: Whether the integration has required non-secret settings and vault credentials. status: $ref: "#/components/schemas/IntegrationStatus" missing_credentials: type: array description: Missing setting or vault key names required before the integration can run. items: type: string connection: oneOf: - $ref: "#/components/schemas/IntegrationConnectionStatus" - type: "null" metadata: type: object description: Non-secret display hints for the integration. additionalProperties: type: string IntegrationProvider: description: Server integration provider. type: string enum: [github, slack] IntegrationStatus: description: Computed runtime integration status. type: string enum: - disabled - missing_credentials - configured - connecting - connected - error IntegrationConnectionStatus: description: Live connection status for integrations with persistent connections. type: object required: [kind, status, last_connected_at, last_error] properties: kind: $ref: "#/components/schemas/IntegrationConnectionKind" status: $ref: "#/components/schemas/IntegrationConnectionState" last_connected_at: type: ["string", "null"] format: date-time description: Last time this integration established its live connection. last_error: type: ["string", "null"] description: Sanitized last connection error, if any. IntegrationConnectionKind: description: Live connection mechanism. type: string enum: [socket_mode] IntegrationConnectionState: description: Live connection state. type: string enum: [connecting, connected, error] SystemResourcesResponse: description: Server-visible runtime resource usage for the active Fabro process environment. type: object required: [sampled_at, cpu, memory, disk, notes] properties: sampled_at: type: string format: date-time description: Timestamp when the sample was collected. cpu: $ref: "#/components/schemas/SystemCpuResources" memory: $ref: "#/components/schemas/SystemMemoryResources" disk: $ref: "#/components/schemas/SystemDiskResources" notes: type: array description: Human-readable caveats about unavailable or scoped metrics. items: type: string SystemCpuResources: description: CPU resources visible to the Fabro server process. type: object required: - supported - scope - unavailable_reason - logical_cpus - usage_percent - sample_window_ms properties: supported: type: boolean description: Whether CPU metrics are available on this platform. scope: $ref: "#/components/schemas/SystemCpuResourceScope" unavailable_reason: type: ["string", "null"] description: Reason metrics are unavailable when unsupported. logical_cpus: type: ["integer", "null"] format: int64 description: Logical CPUs visible to the server process. usage_percent: type: ["number", "null"] format: double description: CPU usage percentage, null until a delta sample is available. sample_window_ms: type: ["integer", "null"] format: int64 description: Elapsed milliseconds since the previous CPU sample, null until a delta sample is available. SystemCpuResourceScope: description: Scope for CPU resource metrics. type: string enum: [server_environment] SystemMemoryResources: description: Memory resources visible to the Fabro server process. type: object required: - supported - scope - unavailable_reason - total_bytes - used_bytes - available_bytes - used_percent - host_total_bytes properties: supported: type: boolean description: Whether memory metrics are available on this platform. scope: $ref: "#/components/schemas/SystemMemoryResourceScope" unavailable_reason: type: ["string", "null"] description: Reason metrics are unavailable when unsupported. total_bytes: type: ["integer", "null"] format: int64 description: Total memory for the reported scope. used_bytes: type: ["integer", "null"] format: int64 description: Used memory for the reported scope. available_bytes: type: ["integer", "null"] format: int64 description: Available memory for the reported scope. used_percent: type: ["number", "null"] format: double description: Used memory percentage for the reported scope. host_total_bytes: type: ["integer", "null"] format: int64 description: Host total memory, included even when reporting a cgroup scope. SystemMemoryResourceScope: description: "`cgroup` when Linux cgroup limits are available, otherwise `host`." type: string enum: [host, cgroup] SystemDiskResources: description: Filesystem resources for the configured Fabro storage root. type: object required: - supported - scope - unavailable_reason - storage_path - mount_point - filesystem - total_bytes - used_bytes - available_bytes - used_percent - fabro_managed_bytes - fabro_reclaimable_bytes properties: supported: type: boolean description: Whether storage filesystem metrics are available. scope: $ref: "#/components/schemas/SystemDiskResourceScope" unavailable_reason: type: ["string", "null"] description: Reason metrics are unavailable when unsupported. storage_path: type: string description: Configured Fabro storage directory. mount_point: type: ["string", "null"] description: Mount point for the filesystem containing the storage directory. filesystem: type: ["string", "null"] description: Filesystem name reported by the operating system. total_bytes: type: ["integer", "null"] format: int64 description: Total bytes on the storage filesystem. used_bytes: type: ["integer", "null"] format: int64 description: Used bytes on the storage filesystem. available_bytes: type: ["integer", "null"] format: int64 description: Available bytes on the storage filesystem. used_percent: type: ["number", "null"] format: double description: Used percentage on the storage filesystem. fabro_managed_bytes: type: integer format: int64 description: Bytes managed by Fabro under the storage root. fabro_reclaimable_bytes: type: integer format: int64 description: Bytes reclaimable through Fabro pruning. SystemDiskResourceScope: description: Scope for disk resource metrics. type: string enum: [storage_filesystem] SystemRepairRunsResponse: description: Runs that need manual repair or deletion because they cannot be loaded. type: object required: [runs, total_count] properties: runs: type: array items: $ref: "#/components/schemas/SystemRepairRunIssue" total_count: type: integer format: int64 description: Count of run repair issues. SystemRepairRunIssue: description: One cataloged run that cannot be loaded from durable storage. type: object required: [run_id, created_at, error] properties: run_id: type: string description: Run identifier. created_at: type: string format: date-time description: Timestamp encoded in the run identifier. error: type: string description: Error produced while loading the run projection. DiskUsageResponse: description: Disk usage summary for server-managed data. type: object properties: summary: type: array items: $ref: "#/components/schemas/DiskUsageSummaryRow" total_size_bytes: type: integer format: int64 description: Total size of all tracked system data. total_reclaimable_bytes: type: integer format: int64 description: Total bytes reclaimable by deleting inactive runs and logs. runs: type: ["array", "null"] description: Per-run usage rows when verbose output is requested. items: $ref: "#/components/schemas/DiskUsageRunRow" DiskUsageSummaryRow: description: One top-level disk usage category. type: object properties: type: type: string description: Category name, such as runs or logs. count: type: integer format: int64 description: Number of items in the category. active: type: ["integer", "null"] format: int64 description: Number of active items when applicable. size_bytes: type: integer format: int64 description: Total bytes used by the category. reclaimable_bytes: type: ["integer", "null"] format: int64 description: Bytes reclaimable by pruning the category. DiskUsageRunRow: description: Per-run disk usage information. type: object properties: run_id: type: string description: Run identifier. workflow_name: type: string description: Workflow display name. status: type: string description: Current run status. start_time: type: string description: Human-readable start timestamp. size_bytes: type: integer format: int64 description: Size used by the run scratch directory. reclaimable: type: boolean description: Whether the run is inactive and reclaimable. PruneRunsRequest: description: Filters for system run pruning. type: object properties: dry_run: type: boolean description: Preview matching runs without deleting them. default: true before: type: string description: Include runs started before this YYYY-MM-DD prefix. workflow: type: string description: Filter by workflow name substring. labels: type: object additionalProperties: type: string description: Label filters applied with AND semantics. orphans: type: boolean description: Include orphan run directories without run metadata. default: false older_than: type: string description: Include only runs older than this duration, such as 24h or 7d. PruneRunsResponse: description: Result of a prune preview or deletion. type: object properties: dry_run: type: boolean description: Whether this response is a dry-run preview. runs: type: ["array", "null"] description: Matched runs when dry-run is enabled. items: $ref: "#/components/schemas/PruneRunEntry" total_count: type: integer format: int64 description: Count of runs matching the prune filters. total_size_bytes: type: integer format: int64 description: Total bytes of the matching runs. deleted_count: type: integer format: int64 description: Number of runs deleted when dry-run is false. freed_bytes: type: integer format: int64 description: Estimated freed bytes when deletion occurs. PruneRunEntry: description: One run matched by a prune preview. type: object properties: run_id: type: string description: Run identifier. dir_name: type: string description: Scratch directory name for the run. workflow_name: type: string description: Workflow display name. size_bytes: type: integer format: int64 description: Bytes used by the run scratch directory. # ── Discovery Schemas ──────────────────────────────────────────────── RootResponseUrls: description: Collection of API discovery URLs. type: object required: - openapi_url - current_user_url - health_url properties: openapi_url: type: string description: URL of the OpenAPI JSON specification. example: /api/v1/openapi.json current_user_url: type: string description: URL of the current user endpoint. example: /api/v1/user health_url: type: string description: URL of the health check endpoint. example: /health RootResponse: description: API discovery response with navigation URLs. type: object required: - urls properties: urls: $ref: "#/components/schemas/RootResponseUrls" HealthResponse: description: Service health check response. type: object required: - status properties: status: type: string description: Health status indicator. example: ok SecretType: description: Schema of a stored secret. type: string enum: - token - oauth - file CreateSecretRequest: description: Request to store or update a secret. type: object required: - name - value - type properties: name: type: string description: Secret name or destination path for file secrets. value: type: string description: The secret value to store. type: $ref: "#/components/schemas/SecretType" description: type: string description: Optional operator-facing description of the secret. DeleteSecretRequest: description: Request to delete a secret by name. type: object required: - name properties: name: type: string description: Secret name or destination path for file secrets. SecretMetadata: description: Metadata for a stored secret (value is never exposed). type: object required: - name - type - created_at - updated_at properties: name: type: string description: Secret key name or destination path. example: ANTHROPIC_API_KEY type: $ref: "#/components/schemas/SecretType" description: type: string description: Optional operator-facing description of the secret. created_at: type: string format: date-time description: When the secret was first stored. updated_at: type: string format: date-time description: When the secret was last updated. SecretListResponse: description: List of stored secret metadata. type: object required: - data properties: data: type: array items: $ref: "#/components/schemas/SecretMetadata" Variable: description: Non-sensitive variable available for run config interpolation. type: object required: - name - value - created_at - updated_at properties: name: type: string pattern: "^[A-Za-z_][A-Za-z0-9_]*$" description: Env-style variable name. example: DEPLOY_ENV value: type: string description: Variable value. example: production description: type: string description: Optional operator-facing description of the variable. created_at: type: string format: date-time description: When the variable was first stored. updated_at: type: string format: date-time description: When the variable was last updated. VariableListResponse: description: List of stored variables. type: object required: - data properties: data: type: array items: $ref: "#/components/schemas/Variable" CreateVariableRequest: description: Request to store or update a variable. type: object required: - name - value properties: name: type: string pattern: "^[A-Za-z_][A-Za-z0-9_]*$" description: Env-style variable name. value: type: string description: Variable value. Empty values are allowed. description: type: string description: Optional operator-facing description of the variable. UpdateVariableRequest: description: Request to update a variable. type: object required: - value properties: value: type: string description: Replacement value. Empty values are allowed. description: type: string description: Optional operator-facing description. Omitted descriptions preserve the existing value. RepoCheckResponse: description: Repository access check result. type: object required: - owner - name - accessible properties: owner: type: string description: GitHub repository owner. example: acme-corp name: type: string description: GitHub repository name. example: my-app accessible: type: boolean description: Whether the server has read-write access to this repository. default_branch: type: ["string", "null"] description: Default branch name, if accessible. example: main private: type: ["boolean", "null"] description: Whether the repository is private, if accessible. permissions: type: ["object", "null"] description: Detected permission levels. properties: pull: type: boolean push: type: boolean admin: type: boolean install_url: type: ["string", "null"] description: GitHub App installation URL when the repo is not yet accessible. DiagnosticsReport: description: Server health diagnostics report. type: object required: - version - sections properties: version: type: string description: Server version. sections: type: array items: $ref: "#/components/schemas/DiagnosticsSection" DiagnosticsSection: type: object required: - title - checks properties: title: type: string checks: type: array items: $ref: "#/components/schemas/DiagnosticsCheck" DiagnosticsCheck: type: object required: - name - status - summary properties: name: type: string status: type: string enum: - pass - warning - error summary: type: string details: type: array items: $ref: "#/components/schemas/DiagnosticsDetail" remediation: type: ["string", "null"] DiagnosticsDetail: type: object required: - text - warn properties: text: type: string warn: type: boolean UserResponse: description: Information about the authenticated user. type: object required: - login properties: login: type: string description: User's login identifier (e.g. GitHub username). example: octocat