Files
test-woodpecker/api/openapi.yaml
pptx704 45f7f467c5 v0.3.0 (#15)
## What's New?

- Bugfixes
- Updated test suites

Reviewed-on: wrenn/python-sdk#15
Co-authored-by: pptx704 <rafeed@omukk.dev>
Co-committed-by: pptx704 <rafeed@omukk.dev>
2026-06-25 22:11:25 +00:00

1742 lines
47 KiB
YAML

openapi: 3.1.0
info:
title: Wrenn API
description: API for Wrenn — the runtime where AI coding agents live, work, and ship.
version: 0.2.2
servers:
- url: http://localhost:8080
description: Local development
security: []
paths:
/v1/capsules:
post:
summary: Create a capsule
operationId: createCapsule
tags:
- capsules
security:
- apiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateCapsuleRequest"
responses:
"202":
description: Capsule creation initiated (status will be "starting")
content:
application/json:
schema:
$ref: "#/components/schemas/Capsule"
"400":
$ref: "#/components/responses/BadRequest"
"403":
$ref: "#/components/responses/Forbidden"
"409":
$ref: "#/components/responses/FailedPrecondition"
"502":
description: Host agent error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
$ref: "#/components/responses/ServiceUnavailable"
get:
summary: List capsules for your team
operationId: listCapsules
tags:
- capsules
security:
- apiKeyAuth: []
responses:
"200":
description: List of capsules
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Capsule"
/v1/capsules/stats:
get:
summary: Get capsule usage stats for your team
operationId: getCapsuleStats
tags:
- capsules
security:
- apiKeyAuth: []
parameters:
- name: range
in: query
required: false
schema:
type: string
enum:
- 5m
- 1h
- 6h
- 24h
- 30d
default: 1h
description: Time window for the time-series data.
responses:
"200":
description: Capsule stats for the team
content:
application/json:
schema:
$ref: "#/components/schemas/CapsuleStats"
"400":
$ref: "#/components/responses/BadRequest"
/v1/capsules/usage:
get:
summary: Get daily CPU and RAM usage for your team
operationId: getCapsuleUsage
tags:
- capsules
security:
- apiKeyAuth: []
parameters:
- name: from
in: query
required: false
schema:
type: string
format: date
description: Start date (YYYY-MM-DD). Defaults to 30 days ago.
- name: to
in: query
required: false
schema:
type: string
format: date
description: End date (YYYY-MM-DD). Defaults to today.
responses:
"200":
description: Daily usage data for the team
content:
application/json:
schema:
$ref: "#/components/schemas/UsageResponse"
"400":
$ref: "#/components/responses/BadRequest"
/v1/capsules/{id}:
parameters:
- name: id
in: path
required: true
schema:
type: string
get:
summary: Get capsule details
operationId: getCapsule
tags:
- capsules
security:
- apiKeyAuth: []
responses:
"200":
description: Capsule details
content:
application/json:
schema:
$ref: "#/components/schemas/Capsule"
"400":
$ref: "#/components/responses/BadRequest"
"404":
description: Capsule not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
delete:
summary: Destroy a capsule
operationId: destroyCapsule
tags:
- capsules
security:
- apiKeyAuth: []
responses:
"202":
description: Capsule destruction initiated
"400":
$ref: "#/components/responses/BadRequest"
"404":
$ref: "#/components/responses/NotFound"
"409":
$ref: "#/components/responses/FailedPrecondition"
"503":
$ref: "#/components/responses/ServiceUnavailable"
/v1/capsules/{id}/exec:
parameters:
- name: id
in: path
required: true
schema:
type: string
post:
summary: Execute a command
operationId: execCommand
tags:
- capsules
security:
- apiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ExecRequest"
responses:
"200":
description: Command output (foreground exec)
content:
application/json:
schema:
$ref: "#/components/schemas/ExecResponse"
"202":
description: Background process started
content:
application/json:
schema:
$ref: "#/components/schemas/BackgroundExecResponse"
"400":
$ref: "#/components/responses/BadRequest"
"404":
description: Capsule not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"409":
description: Capsule not running
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
$ref: "#/components/responses/ServiceUnavailable"
/v1/capsules/{id}/processes:
parameters:
- name: id
in: path
required: true
schema:
type: string
get:
summary: List running processes
operationId: listProcesses
tags:
- capsules
security:
- apiKeyAuth: []
description:
"Returns all running processes inside the capsule, including background
processes and any processes started by templates or init scripts.
"
responses:
"200":
description: Process list
content:
application/json:
schema:
$ref: "#/components/schemas/ProcessListResponse"
"400":
$ref: "#/components/responses/BadRequest"
"404":
description: Capsule not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"409":
description: Capsule not running
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
$ref: "#/components/responses/ServiceUnavailable"
/v1/capsules/{id}/processes/{selector}:
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: selector
in: path
required: true
description: Process PID (numeric) or tag (string)
schema:
type: string
delete:
summary: Kill a process
operationId: killProcess
tags:
- capsules
security:
- apiKeyAuth: []
parameters:
- name: signal
in: query
required: false
description: Signal to send (SIGKILL or SIGTERM, default SIGKILL)
schema:
type: string
enum:
- SIGKILL
- SIGTERM
default: SIGKILL
responses:
"204":
description: Process killed
"400":
$ref: "#/components/responses/BadRequest"
"404":
description: Capsule or process not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"409":
description: Capsule not running
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
$ref: "#/components/responses/ServiceUnavailable"
/v1/capsules/{id}/processes/{selector}/stream:
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: selector
in: path
required: true
description: Process PID (numeric) or tag (string)
schema:
type: string
get:
summary: Stream process output via WebSocket
operationId: connectProcess
tags:
- capsules
security:
- apiKeyAuth: []
description:
'Opens a WebSocket connection to stream stdout/stderr from a running
background process. The selector can be a numeric PID or a string tag.
Server sends JSON messages:
- `{"type": "start", "pid": 42}` — connected to process
- `{"type": "stdout", "data": "..."}` — stdout output
- `{"type": "stderr", "data": "..."}` — stderr output
- `{"type": "exit", "exit_code": 0}` — process exited
- `{"type": "error", "data": "..."}` — error message
'
responses:
"101":
description: WebSocket upgrade
/v1/capsules/{id}/ping:
parameters:
- name: id
in: path
required: true
schema:
type: string
post:
summary: Reset capsule inactivity timer
operationId: pingCapsule
tags:
- capsules
security:
- apiKeyAuth: []
description:
"Resets the last_active_at timestamp for a running capsule, preventing
the auto-pause TTL from expiring. Use this as a keepalive for capsules
that are idle but should remain running.
"
responses:
"204":
description: Ping acknowledged, inactivity timer reset
"400":
$ref: "#/components/responses/BadRequest"
"404":
description: Capsule not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"409":
description: Capsule not running
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/v1/capsules/{id}/metrics:
parameters:
- name: id
in: path
required: true
schema:
type: string
get:
summary: Get per-capsule resource metrics
operationId: getCapsuleMetrics
tags:
- capsules
security:
- apiKeyAuth: []
description:
"Returns time-series CPU, memory, and disk metrics for a capsule.
Three tiers are available with different granularity and retention:
- `10m`: 500ms samples, last 10 minutes
- `2h`: 30-second averages, last 2 hours
- `24h`: 5-minute averages, last 24 hours
For running capsules, data comes from the host agent's in-memory
ring buffer. For paused capsules, data is read from persisted
snapshots in the database. Stopped/destroyed capsules return 404.
"
parameters:
- name: range
in: query
required: false
schema:
type: string
enum:
- 5m
- 10m
- 1h
- 2h
- 6h
- 12h
- 24h
default: 10m
description: Time range filter to query
responses:
"200":
description: Metrics retrieved
content:
application/json:
schema:
$ref: "#/components/schemas/CapsuleMetrics"
"400":
description: Invalid range parameter
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"404":
description: Capsule not found or metrics not available
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
$ref: "#/components/responses/ServiceUnavailable"
/v1/capsules/{id}/pause:
parameters:
- name: id
in: path
required: true
schema:
type: string
post:
summary: Pause a running capsule
operationId: pauseCapsule
tags:
- capsules
security:
- apiKeyAuth: []
description:
"Takes a snapshot of the capsule (VM state + memory + rootfs), then
destroys all running resources. The capsule exists only as files on
disk and can be resumed later.
"
responses:
"202":
description: Capsule pause initiated (status will be "pausing")
content:
application/json:
schema:
$ref: "#/components/schemas/Capsule"
"400":
$ref: "#/components/responses/BadRequest"
"404":
$ref: "#/components/responses/NotFound"
"409":
description: Capsule not running
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
$ref: "#/components/responses/ServiceUnavailable"
/v1/capsules/{id}/resume:
parameters:
- name: id
in: path
required: true
schema:
type: string
post:
summary: Resume a paused capsule
operationId: resumeCapsule
tags:
- capsules
security:
- apiKeyAuth: []
description:
"Restores a paused capsule from its snapshot. Cloud Hypervisor is
relaunched in --restore mode with memory_restore_mode=ondemand so
guest pages fault in lazily via userfaultfd. The original network
slot (and host-reachable IP) is preserved across pause/resume.
"
responses:
"202":
description: Capsule resume initiated (status will be "resuming")
content:
application/json:
schema:
$ref: "#/components/schemas/Capsule"
"400":
$ref: "#/components/responses/BadRequest"
"404":
$ref: "#/components/responses/NotFound"
"409":
description: Capsule not paused
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
$ref: "#/components/responses/ServiceUnavailable"
/v1/snapshots:
post:
summary: Create a snapshot template
operationId: createSnapshot
tags:
- snapshots
security:
- apiKeyAuth: []
description:
"Snapshot a capsule, processed asynchronously. The call returns
immediately with the capsule in the `snapshotting` state, then it
returns to its original state on completion. The capsule must be
`running` or `paused`.
A `running` capsule is snapshotted live: it briefly pauses while its VM
state + memory + flattened rootfs are written to a new template, then
resumes to `running`. A `paused` capsule is snapshotted directly from
its on-disk state without reviving the VM, and stays `paused`.
Because it is async, the response does NOT contain the template. Watch
for the `template.snapshot.create` SSE event (its `outcome` reports
success or failure) or poll `GET /v1/snapshots` to observe completion.
Snapshots are immutable: each call must use a fresh name. Re-using
an existing name returns 409 Conflict.
"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateSnapshotRequest"
responses:
"202":
description: Snapshot accepted; capsule is now snapshotting
content:
application/json:
schema:
$ref: "#/components/schemas/Capsule"
"400":
$ref: "#/components/responses/BadRequest"
"404":
$ref: "#/components/responses/NotFound"
"409":
description: Name already exists, or capsule is not running or paused
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
get:
summary: List templates for your team
operationId: listSnapshots
tags:
- snapshots
security:
- apiKeyAuth: []
parameters:
- name: type
in: query
required: false
schema:
type: string
enum:
- base
- snapshot
description: Filter by template type.
responses:
"200":
description: List of templates
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Template"
/v1/snapshots/{name}:
parameters:
- name: name
in: path
required: true
schema:
type: string
delete:
summary: Delete a snapshot template
operationId: deleteSnapshot
tags:
- snapshots
security:
- apiKeyAuth: []
description: Removes the snapshot files from disk and deletes the database record.
responses:
"204":
description: Snapshot deleted
"400":
$ref: "#/components/responses/BadRequest"
"403":
description: Cannot delete a platform-owned / system base template
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"404":
description: Template not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"409":
description: Delete failed (e.g. owning host offline)
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/v1/capsules/{id}/files/write:
parameters:
- name: id
in: path
required: true
schema:
type: string
post:
summary: Upload a file
operationId: uploadFile
tags:
- capsules
security:
- apiKeyAuth: []
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required:
- path
- file
properties:
path:
type: string
description: Absolute destination path inside the capsule
file:
type: string
format: binary
description: File content
responses:
"204":
description: File uploaded
"400":
$ref: "#/components/responses/BadRequest"
"404":
$ref: "#/components/responses/NotFound"
"409":
description: Capsule not running
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"413":
description: File too large
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
$ref: "#/components/responses/ServiceUnavailable"
/v1/capsules/{id}/files/read:
parameters:
- name: id
in: path
required: true
schema:
type: string
post:
summary: Download a file
operationId: downloadFile
tags:
- capsules
security:
- apiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ReadFileRequest"
responses:
"200":
description: File content
content:
application/octet-stream:
schema:
type: string
format: binary
"400":
$ref: "#/components/responses/BadRequest"
"404":
description: Capsule or file not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"409":
description: Capsule not running
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
$ref: "#/components/responses/ServiceUnavailable"
/v1/capsules/{id}/files/list:
parameters:
- name: id
in: path
required: true
schema:
type: string
post:
summary: List directory contents
operationId: listDir
tags:
- capsules
security:
- apiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ListDirRequest"
responses:
"200":
description: Directory listing
content:
application/json:
schema:
$ref: "#/components/schemas/ListDirResponse"
"400":
$ref: "#/components/responses/BadRequest"
"404":
description: Capsule not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"409":
description: Capsule not running
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
$ref: "#/components/responses/ServiceUnavailable"
/v1/capsules/{id}/files/mkdir:
parameters:
- name: id
in: path
required: true
schema:
type: string
post:
summary: Create a directory
operationId: makeDir
tags:
- capsules
security:
- apiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MakeDirRequest"
responses:
"200":
description: Directory created
content:
application/json:
schema:
$ref: "#/components/schemas/MakeDirResponse"
"400":
$ref: "#/components/responses/BadRequest"
"404":
description: Capsule not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"409":
description:
"Capsule not running, or a directory already exists at the target path (error code `already_exists`).
"
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
$ref: "#/components/responses/ServiceUnavailable"
/v1/capsules/{id}/files/remove:
parameters:
- name: id
in: path
required: true
schema:
type: string
post:
summary: Remove a file or directory
operationId: removePath
tags:
- capsules
security:
- apiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/RemoveRequest"
responses:
"204":
description: File or directory removed
"400":
$ref: "#/components/responses/BadRequest"
"404":
description: Capsule not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"409":
description: Capsule not running
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
$ref: "#/components/responses/ServiceUnavailable"
/v1/capsules/{id}/exec/stream:
parameters:
- name: id
in: path
required: true
schema:
type: string
get:
summary: Stream command execution via WebSocket
operationId: execStream
tags:
- capsules
security:
- apiKeyAuth: []
description:
'Opens a WebSocket connection for streaming command execution.
**Client sends** (first message to start the process):
```json
{"type": "start", "cmd": "tail", "args": ["-f", "/var/log/syslog"]}
```
**Client sends** (to stop the process):
```json
{"type": "stop"}
```
**Server sends** (process events as they arrive):
```json
{"type": "start", "pid": 1234}
{"type": "stdout", "data": "line of output\n"}
{"type": "stderr", "data": "warning message\n"}
{"type": "exit", "exit_code": 0}
{"type": "error", "data": "description of error"}
```
The connection closes automatically after the process exits.
Note: capsule-not-found and not-running conditions encountered after the
WebSocket upgrade are delivered as in-band `{"type": "error"}` frames
rather than HTTP status codes.
'
responses:
"101":
description: WebSocket upgrade
"400":
$ref: "#/components/responses/BadRequest"
"404":
description: Capsule not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"409":
description: Capsule not running
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/v1/capsules/{id}/pty:
parameters:
- name: id
in: path
required: true
schema:
type: string
get:
summary: Interactive PTY session via WebSocket
operationId: ptySession
tags:
- capsules
security:
- apiKeyAuth: []
description:
"Opens a WebSocket connection for an interactive PTY (terminal) session.\nSupports creating new sessions,\
\ sending input, resizing, killing, and\nreconnecting to existing sessions.\n\n**Client sends** (first message — start\
\ a new PTY):\n```json\n{\n \"type\": \"start\",\n \"cmd\": \"/bin/bash\",\n \"args\": [],\n \"cols\": 80,\n \
\ \"rows\": 24,\n \"envs\": {\"TERM\": \"xterm-256color\"},\n \"cwd\": \"/home/user\",\n \"user\": \"user\"\n}\n\
```\nAll fields except `type` are optional. Defaults: cmd=\"/bin/bash\", cols=80, rows=24.\n\n**Client sends** (first\
\ message — reconnect to existing PTY):\n```json\n{\"type\": \"connect\", \"tag\": \"pty-abc123de\"}\n```\n\n**Client\
\ sends** (control messages, after session is established — JSON text frames):\n```json\n{\"type\": \"resize\", \"\
cols\": 120, \"rows\": 40}\n{\"type\": \"kill\"}\n```\n\nKeystroke input is sent as **raw binary WebSocket frames**\
\ containing the\nterminal bytes verbatim — not JSON, not base64. Every binary frame from\nthe client is treated as\
\ PTY input.\n\n**Server sends** (control messages — JSON text frames):\n```json\n{\"type\": \"started\", \"tag\"\
: \"pty-abc123de\", \"pid\": 42}\n{\"type\": \"exit\", \"exit_code\": 0}\n{\"type\": \"error\", \"data\": \"description\"\
, \"fatal\": true}\n{\"type\": \"ping\"}\n```\n\nPTY output is sent as **raw binary WebSocket frames** containing\
\ the\nterminal bytes verbatim — not JSON, not base64. Sending input and output\nas binary avoids the ~33% inflation\
\ of base64 over the JSON path.\n\nThe connection negotiates permessage-deflate (RFC 7692) compression\nautomatically;\
\ rapid output (e.g. full-screen TUI repaints) is coalesced\ninto fewer, larger frames before compression.\n\nSessions\
\ persist across WebSocket disconnections — the process keeps\nrunning in the capsule. Use the `tag` from the \"started\"\
\ response to\nreconnect later.\n"
responses:
"101":
description: WebSocket upgrade
"400":
$ref: "#/components/responses/BadRequest"
"404":
description: Capsule not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"409":
description: Capsule not running
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/v1/capsules/{id}/files/stream/write:
parameters:
- name: id
in: path
required: true
schema:
type: string
post:
summary: Upload a file (streaming)
operationId: streamUploadFile
tags:
- capsules
security:
- apiKeyAuth: []
description:
"Streams file content to the capsule without buffering in memory.
Suitable for large files. Uses the same multipart/form-data format
as the non-streaming upload endpoint.
"
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required:
- path
- file
properties:
path:
type: string
description: Absolute destination path inside the capsule
file:
type: string
format: binary
description: File content
responses:
"204":
description: File uploaded
"400":
$ref: "#/components/responses/BadRequest"
"404":
description: Capsule not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"409":
description: Capsule not running
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"502":
description: Host agent error while streaming the upload
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
$ref: "#/components/responses/ServiceUnavailable"
/v1/capsules/{id}/files/stream/read:
parameters:
- name: id
in: path
required: true
schema:
type: string
post:
summary: Download a file (streaming)
operationId: streamDownloadFile
tags:
- capsules
security:
- apiKeyAuth: []
description:
"Streams file content from the capsule without buffering in memory.
Suitable for large files. Returns raw bytes with chunked transfer encoding.
"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ReadFileRequest"
responses:
"200":
description: File content streamed in chunks
content:
application/octet-stream:
schema:
type: string
format: binary
"400":
$ref: "#/components/responses/BadRequest"
"404":
description: Capsule or file not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"409":
description: Capsule not running
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
$ref: "#/components/responses/ServiceUnavailable"
/v1/events/stream:
get:
summary: Real-time lifecycle event stream
operationId: streamEvents
tags:
- events
description:
'Server-Sent Events stream of capsule, template, and host lifecycle
events scoped to the caller''s active team. Browsers send the
wrenn_sid cookie automatically on EventSource connections; SDKs
authenticate via X-API-Key.
Frame format follows the standard SSE protocol:
```
event: capsule.create
data: {"event":"capsule.create","outcome":"success","resource":{"id":"sb-..."},"sandbox":{...},"timestamp":"2026-05-19T02:00:00Z"}
: keepalive
```
A `: keepalive` comment is emitted every 30s.
'
security:
- apiKeyAuth: []
responses:
"200":
description: SSE stream opened
content:
text/event-stream:
schema:
$ref: "#/components/schemas/SSEEvent"
"401":
description: Missing or invalid auth
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
responses:
BadRequest:
description: Invalid request parameters
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
Forbidden:
description: Authenticated but not permitted (e.g. non-admin on /v1/admin/*)
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
FailedPrecondition:
description: Resource state does not allow this operation (e.g. exec on a paused capsule)
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
ServiceUnavailable:
description: The host serving this capsule is unreachable (host_unavailable)
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
securitySchemes:
apiKeyAuth:
type: apiKey
in: header
name: X-API-Key
description: API key for capsule lifecycle operations. Create via POST /v1/api-keys.
schemas:
CreateCapsuleRequest:
type: object
properties:
template:
type: string
default: minimal-ubuntu
vcpus:
type: integer
default: 1
memory_mb:
type: integer
default: 512
timeout_sec:
type: integer
minimum: 0
default: 0
description:
"Auto-pause TTL in seconds. The capsule is automatically paused after this duration of inactivity (no
exec or ping). 0 means no auto-pause. Positive values below 60 are silently clamped to 60 (the agent's startup
envelope).
"
metadata:
type: object
additionalProperties:
type: string
nullable: true
description:
"Optional user-supplied key/value labels attached to the capsule. Max 20 keys; keys match [a-zA-Z0-9][a-zA-Z0-9._-]{0,63};
values are at most 64 characters. Reserved system keys (kernel_version, vmm_version, agent_version, envd_version)
are rejected. Metadata is set at create-time only.
"
UsageResponse:
type: object
properties:
from:
type: string
format: date
to:
type: string
format: date
points:
type: array
items:
type: object
properties:
date:
type: string
format: date
cpu_minutes:
type: number
ram_mb_minutes:
type: number
CapsuleStats:
type: object
properties:
range:
type: string
enum:
- 5m
- 1h
- 6h
- 24h
- 30d
current:
type: object
properties:
running_count:
type: integer
vcpus_reserved:
type: integer
memory_mb_reserved:
type: integer
peaks:
type: object
description: Maximum values over the last 30 days.
properties:
running_count:
type: integer
vcpus:
type: integer
memory_mb:
type: integer
series:
type: object
description: Parallel arrays for chart rendering.
properties:
labels:
type: array
items:
type: string
format: date-time
running:
type: array
items:
type: integer
vcpus:
type: array
items:
type: integer
memory_mb:
type: array
items:
type: integer
Capsule:
type: object
properties:
id:
type: string
status:
type: string
enum:
- pending
- starting
- running
- pausing
- paused
- snapshotting
- resuming
- stopping
- hibernated
- stopped
- missing
- error
template:
type: string
vcpus:
type: integer
memory_mb:
type: integer
timeout_sec:
type: integer
created_at:
type: string
format: date-time
started_at:
type: string
format: date-time
nullable: true
last_active_at:
type: string
format: date-time
nullable: true
last_updated:
type: string
format: date-time
metadata:
type: object
additionalProperties:
type: string
nullable: true
description:
"User-supplied key/value labels attached at create-time. Once the
capsule is running this also carries agent-side system version info
(kernel_version, vmm_version, agent_version, envd_version); those
reserved keys are owned by the system and cannot be set by users.
"
disk_size_mb:
type: integer
description: Maximum disk capacity in MiB.
disk_used_mb:
type: integer
format: int64
description: Current disk usage in MiB. Only populated on individual capsule GET; omitted in list responses.
CreateSnapshotRequest:
type: object
required:
- sandbox_id
properties:
sandbox_id:
type: string
description: ID of the running capsule to snapshot.
name:
type: string
description: Name for the snapshot template. Auto-generated if omitted.
Template:
type: object
properties:
name:
type: string
type:
type: string
enum:
- base
- snapshot
vcpus:
type: integer
nullable: true
memory_mb:
type: integer
nullable: true
size_bytes:
type: integer
format: int64
created_at:
type: string
format: date-time
platform:
type: boolean
description:
"True when the template is platform-managed (visible to all teams,
e.g. the built-in `minimal-ubuntu` rootfs). False for team-owned
snapshot templates.
"
protected:
type: boolean
description: "True for built-in system base templates (minimal-ubuntu,
minimal-alpine, minimal-arch, minimal-fedora). Protected templates
cannot be deleted.
"
metadata:
type: object
additionalProperties:
type: string
nullable: true
ExecRequest:
type: object
required:
- cmd
properties:
cmd:
type: string
args:
type: array
items:
type: string
timeout_sec:
type: integer
default: 30
description: Timeout in seconds (foreground exec only, default 30)
background:
type: boolean
default: false
description: If true, starts the process in the background and returns immediately with a PID and tag (HTTP 202)
tag:
type: string
description:
Optional user-chosen tag for the background process. Auto-generated if omitted. Only used when background
is true.
envs:
type: object
additionalProperties:
type: string
description: Environment variables for the process (applies to both foreground and background exec)
cwd:
type: string
description: Working directory for the process (applies to both foreground and background exec)
BackgroundExecResponse:
type: object
properties:
sandbox_id:
type: string
cmd:
type: string
pid:
type: integer
tag:
type: string
ProcessEntry:
type: object
properties:
pid:
type: integer
tag:
type: string
cmd:
type: string
args:
type: array
items:
type: string
ProcessListResponse:
type: object
properties:
processes:
type: array
items:
$ref: "#/components/schemas/ProcessEntry"
ExecResponse:
type: object
properties:
sandbox_id:
type: string
cmd:
type: string
stdout:
type: string
stderr:
type: string
exit_code:
type: integer
duration_ms:
type: integer
encoding:
type: string
enum:
- utf-8
- base64
description: Output encoding. "base64" when stdout/stderr contain binary data.
ReadFileRequest:
type: object
required:
- path
properties:
path:
type: string
description: Absolute file path inside the capsule
ListDirRequest:
type: object
required:
- path
properties:
path:
type: string
description: Directory path inside the capsule
depth:
type: integer
default: 1
description: Recursion depth (0 = non-recursive, 1 = immediate children)
ListDirResponse:
type: object
properties:
entries:
type: array
items:
$ref: "#/components/schemas/FileEntry"
FileEntry:
type: object
properties:
name:
type: string
path:
type: string
type:
type: string
enum:
- file
- directory
- symlink
size:
type: integer
format: int64
mode:
type: integer
permissions:
type: string
description: Human-readable permissions (e.g. "-rwxr-xr-x")
owner:
type: string
group:
type: string
modified_at:
type: integer
format: int64
description: Unix timestamp (seconds)
symlink_target:
type: string
nullable: true
MakeDirRequest:
type: object
required:
- path
properties:
path:
type: string
description: Directory path to create inside the capsule
MakeDirResponse:
type: object
properties:
entry:
$ref: "#/components/schemas/FileEntry"
RemoveRequest:
type: object
required:
- path
properties:
path:
type: string
description: Path to remove inside the capsule
CapsuleMetrics:
type: object
properties:
sandbox_id:
type: string
range:
type: string
enum:
- 5m
- 10m
- 1h
- 2h
- 6h
- 12h
- 24h
points:
type: array
items:
$ref: "#/components/schemas/MetricPoint"
MetricPoint:
type: object
properties:
timestamp_unix:
type: integer
format: int64
cpu_pct:
type: number
format: double
description: CPU utilization percentage (0-100), normalized to vCPU count
mem_bytes:
type: integer
format: int64
description: Resident memory in bytes (VmRSS of Cloud Hypervisor process)
disk_bytes:
type: integer
format: int64
description: Allocated disk bytes for the CoW sparse file
Error:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
SSEEvent:
type: object
description:
"Wire format of one SSE message body. The event name (`event:` line) is
the `kind` and the JSON below is the `data:` line.
"
properties:
event:
type: string
enum:
- connected
- capsule.create
- capsule.pause
- capsule.resume
- capsule.destroy
- capsule.state.changed
- template.snapshot.create
- template.snapshot.delete
- host.up
- host.down
outcome:
type: string
enum:
- success
- error
description:
"Present for action events (capsule.* except state.changed,
template.snapshot.*). Absent for host.up/down, capsule.state.changed,
and the connected sentinel.
"
resource:
type: object
properties:
id:
type: string
type:
type: string
actor:
type: object
properties:
type:
type: string
enum:
- user
- api_key
- system
id:
type: string
name:
type: string
metadata:
type: object
additionalProperties:
type: string
description: "Event-specific context. Examples: `reason` (ttl_expired,
host_failure, cleanup_after_create_error, orphaned),
`host_ip`, `from`/`to` (for capsule.state.changed).
"
error:
type: string
description: Failure reason; only set when outcome=error.
sandbox:
allOf:
- $ref: "#/components/schemas/Capsule"
nullable: true
description: Populated for capsule.* events; null if DB lookup failed.
timestamp:
type: string
format: date-time