/api/* and one Server-Sent Events stream for Turn execution. The canonical schema lives in openapi.yaml; this page is a high-level map.
Fleet uses one deterministic local User and Workspace scope. It accepts no Authorization header or caller-supplied identity headers. There is no /api/v1 prefix, no WebSocket execution surface, no optimization/evaluation API, no runtime-admin API, no caller-selected BYOK profile API, and no public Artifact creation endpoint.
Backend launchers default to binding 127.0.0.1 and reject non-loopback hosts unless --allow-non-loopback-bind is passed. The /api/settings endpoint is a separate local administration surface: it rejects non-loopback clients even when the API has been explicitly bound to another interface. See the security model for the full trust boundary.
Endpoint map
Turn creation
POST /api/sessions/{session_id}/turns executes exactly one Turn on the Session’s resident native dspy.RLM, creating or rotating the runtime as needed. Idempotency is mandatory.
Required headers:
Request body:
Explicit
skill_selections become authoritative for the Turn and are folded into its idempotency fingerprint. Omitting skill_selections supplies the full bounded catalog to the RLM and permits it to progressively load up to four advertised Skills. Providing selections preloads those exact versions and restricts loading to that set.
Structurally malformed selections fail pre-stream with 422 invalid_skill_selection. Catalog-rejected selections (missing, unauthorized, or version-mismatched) resolve during in-stream Turn opening and surface as a stream error chunk with the generic message Invalid Skill selection. Both paths avoid revealing hidden catalog entries.
Streaming contract
The response opens the AI SDK UI message stream immediately instead of holding headers until preparation finishes. Transport200 no longer implies a successful Turn; the Run id lives in the start chunk metadata.
While the Turn claim and preparation resolve, the server emits a transient data-status chunk:
runtime.heartbeat_seconds (configured in config/fleet.toml) until coordinator.open completes. Prelude chunks are client-facing keep-alives only; they never enter durable Turn history or the event log and may repeat.
After opening, exactly one of three closings applies:
- Success streams Runtime Events, ends with
finish, then[DONE]. - Claim or preparation failures close the stream with
error+finishchunks that map to the same messages the old prepare-before-headers boundary surfaced as HTTP statuses (Session not found,A Turn is already running,Idempotency key input mismatch,Invalid Skill selection,Turn preparation timed out,Turn is unavailable,Invalid request), then[DONE]. - Run cancellation ends the live stream with one terminal
abortchunk and nothing after it. Nofinish, nodata-usage, no checkpoint metadata.
GET /api/sessions/{session_id}/turns shows the attempt: the original user input plus one assistant message carrying only a cancelled data-status part, observed usage, and the closed text Turn cancelled. Cancelled tombstones never contain reasoning, code, output, or Tool evidence parts.
Example
Run cancellation
PUT /api/runs/{run_id}/cancellation requests durable cancellation of an owned Run. The active stream closes with a single abort chunk. Fleet writes a bounded tombstone after settlement so history remains consistent.
Files API
GET /api/files, GET /api/files/stat, GET /api/files/content, PUT /api/files/content, POST /api/files/append, PATCH /api/files/content, and DELETE /api/files/content operate on the process-local Workspace files/ root. Callers cannot select a Workspace or address Daytona Volume, mount, Sandbox, Attachment, Artifact, Session, or Run identifiers through this API.
The Files API has no rename operation and accepts an optional current SHA-256 on overwrite, append, delete, and patch. Stale preconditions return 409.
DELETE /api/files/contentremoves one file or one empty directory. Non-empty directories return409.PATCH /api/files/contentapplies one unique find/replace whoseoldtext must occur exactly once. Absent or ambiguous matches return409. The response returns the fresh content checksum for precondition chaining.
Attachments and Artifacts
POST /api/attachments uploads one durable Attachment and returns its id for future Turn requests.
GET /api/artifacts/{artifact_id} and GET /api/artifacts/{artifact_id}/content return committed metadata and verified bytes. There is no POST /api/artifacts. Artifacts become public only when the host-mediated create_artifact produces a private candidate that is then promoted through Turn Commit.
Volume tree
GET /api/volume/tree (Daytona only) returns a bounded, read-only view of relative paths within the mounted Workspace Volume. It is a process-local logical view, not a general-purpose Sandbox filesystem browser.
Skills
GET /api/skills returns bounded Skill Cards for the five bundled system Skills (data-analysis, dspy-rlm, long-context, report-builder, workspace-files). GET /api/skills/{skill_id} returns one Skill Card by id.
Selecting a Skill on a Turn preloads that exact expected_version and restricts progressive load_skill calls to the authorized set.
Health probes
GET /health and GET /health/ready are public probes for orchestrators, supervisors, and load balancers. Neither probe requires an identity header, a loopback client, or an existing Session.
GET /health answers liveness while the process serves HTTP, even before startup composition wires the runtime inventory. It performs no dependency checks and returns the application name and version:
GET /health/ready answers readiness. Before startup composition installs, it returns 503 with the closed service_not_ready error envelope:
SELECT 1 round-trip and returns 200:
database reports "not_configured" and the probe still returns 200. An unreachable configured database degrades readiness back to the same service_not_ready 503.
Point orchestrator liveness checks at /health to detect a dead process, and readiness checks at /health/ready to hold traffic until the database answers:
Local settings
GET /api/settings and PATCH /api/settings read and revision-update the non-secret config/fleet.toml policy. This endpoint rejects any non-loopback client — including when the main API is bound to another interface — and never reads or returns .env values, provider credentials, or database URLs. Saved policy applies only after Fleet is restarted.
Every PATCH carries the revision returned by the last read. If the file changed since that read, Fleet rejects the request with 409 settings_revision_conflict; reload and retry. The request body takes one of three shapes:
- Batch update — an
updatesarray of set or reset operations, with an optionaldefault_profile. Fleet validates the whole batch against every profile and writes it atomically; either every operation lands or none do. An operation withunset: trueremoves a profile override so the field inherits the[defaults]value again (defaults themselves cannot be reset). - Single field —
scope,path, andvalueupdate one policy field. - Profile selection —
profilewritesconfig.default_profilefor the next restart.
Source of truth
- Routes:
src/fleet_rlm/api/routes/ - Turn runtime:
src/fleet_rlm/chat/turn_runtime.py - SSE stream projection:
src/fleet_rlm/api/sse.pyandapi/ui_stream.py - Canonical schema:
openapi.yaml