> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qredence.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# fleet-rlm HTTP and SSE API reference

> Reference for the fleet-rlm FastAPI surface: Sessions, Turns, Attachments, Artifacts, Files, Volume, Skills, Runs, and the Turn SSE stream contract.

fleet-rlm exposes a small, deterministic HTTP surface under `/api/*` and one Server-Sent Events stream for Turn execution. The canonical schema lives in [`openapi.yaml`](https://github.com/qredence/fleet-rlm/blob/main/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.

## Endpoint map

| Method          | Path                                   | Purpose                                                                               |
| --------------- | -------------------------------------- | ------------------------------------------------------------------------------------- |
| `POST`          | `/api/sessions/{session_id}/turns`     | Execute one idempotent Turn and stream Runtime Events over SSE.                       |
| `POST`          | `/api/sessions`                        | Create a Session.                                                                     |
| `GET`           | `/api/sessions`                        | List owned Sessions.                                                                  |
| `GET` / `PATCH` | `/api/sessions/{session_id}`           | Read, rename, or archive an owned Session.                                            |
| `GET`           | `/api/sessions/{session_id}/turns`     | Read ordered committed Turn history.                                                  |
| `POST`          | `/api/attachments`                     | Upload one durable Attachment.                                                        |
| `GET`           | `/api/attachments/{attachment_id}`     | Read owned Attachment metadata.                                                       |
| `GET`           | `/api/artifacts/{artifact_id}`         | Read committed Artifact metadata.                                                     |
| `GET`           | `/api/artifacts/{artifact_id}/content` | Download verified committed Artifact bytes.                                           |
| `GET`           | `/api/files`                           | List the durable Workspace `files/` namespace.                                        |
| `GET`           | `/api/files/stat`                      | Read file metadata and SHA-256.                                                       |
| `GET`           | `/api/files/content`                   | Read one bounded UTF-8 page.                                                          |
| `PUT`           | `/api/files/content`                   | Create or explicitly overwrite a UTF-8 file.                                          |
| `POST`          | `/api/files/append`                    | Append UTF-8 text.                                                                    |
| `PATCH`         | `/api/files/content`                   | Replace one unique `old` fragment with `new`.                                         |
| `DELETE`        | `/api/files/content`                   | Delete one file or one empty directory.                                               |
| `GET`           | `/api/volume/tree`                     | List relative paths from the mounted Workspace Volume (Daytona only).                 |
| `GET`           | `/api/skills`                          | List bounded system Skill Cards.                                                      |
| `GET`           | `/api/skills/{skill_id}`               | Read one bounded system Skill Card.                                                   |
| `PUT`           | `/api/runs/{run_id}/cancellation`      | Request cancellation of an owned Run.                                                 |
| `GET` / `PATCH` | `/api/settings`                        | Read or revision-update non-secret `config/fleet.toml` policy from a loopback client. |

## Turn creation

`POST /api/sessions/{session_id}/turns` executes exactly one Turn against a fresh native `dspy.RLM`. Idempotency is mandatory.

**Required headers:**

| Header            | Description                                                       |
| ----------------- | ----------------------------------------------------------------- |
| `Idempotency-Key` | Client-supplied key that bounds retries to a single durable Turn. |
| `Content-Type`    | `application/json`.                                               |

**Request body:**

| Field              | Type      | Description                                                                |
| ------------------ | --------- | -------------------------------------------------------------------------- |
| `text`             | string    | User message text.                                                         |
| `attachment_ids`   | string\[] | Optional durable Attachment ids owned by the caller.                       |
| `skill_selections` | object\[] | Optional list of up to four unique `{id, expected_version}` Skill entries. |

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. Transport `200` 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:

```json theme={null}
{
  "type": "data-status",
  "data": { "phase": "preparation", "status": "running", "message": null },
  "transient": true
}
```

Fleet re-emits this chunk every `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` + `finish` chunks 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 `abort` chunk and nothing after it. No `finish`, no `data-usage`, no checkpoint metadata.

Once cancellation settlement completes, the cancelled attempt persists a bounded tombstone in committed history so `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

```bash theme={null}
SESSION=$(curl -s -X POST http://127.0.0.1:8000/api/sessions \
  -H "Content-Type: application/json" -d '{"title": "hello"}' | jq -r .id)

curl -N -X POST "http://127.0.0.1:8000/api/sessions/$SESSION/turns" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "text": "Summarize the workspace README.",
    "skill_selections": [
      { "id": "workspace-files", "expected_version": "1.0.0" }
    ]
  }'
```

## Run cancellation

`PUT /api/runs/{run_id}/cancellation` requests durable cancellation of an owned Run. The active stream closes with a single `abort` chunk. A bounded tombstone is written 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/content` removes one file or one empty directory. Non-empty directories return `409`.
* `PATCH /api/files/content` applies one unique find/replace whose `old` text must occur exactly once. Absent or ambiguous matches return `409`. 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.

## 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.

## Source of truth

* Routes: `src/fleet_rlm/api/routes/`
* Turn coordinator: `src/fleet_rlm/chat/turn_coordinator.py`
* SSE stream projection: `src/fleet_rlm/api/sse.py` and `api/ui_stream.py`
* Canonical schema: [`openapi.yaml`](https://github.com/qredence/fleet-rlm/blob/main/openapi.yaml)
