# Session Endpoints

Endpoints for reading, updating and deleting sessions and their pending and finished tasks.

| Method | Path | Description |
|---|---|---|
| `GET` | `/v1/sessions` | List sessions and status |
| `GET` | `/v1/usage` | **local** — 24 h / 7 d / 28 d total token usage across sessions. Since v1.0.11 each per-model row also carries `elapsed_ms` (summed provider round-trip time) and `output_tps` (output tokens per second, computed only over the rows that recorded an elapsed time). Since v1.1.0 the `input` of `claude` and `claude-code` rows includes cache writes (`write`), which those providers report separately; since v1.0.26 each usage record also stores the IDs of the tool calls the response made (not returned here) |
| `POST` | `/v1/session` | **local** — create a session; `{prefix}` defaults to `cli-` |
| `GET` `POST` `DELETE` | `/v1/session/:id` | **local** — one session's full state in one call: `id`, `self_id`, `name`, `role`, `state`, `model`, `reasoning`, `levels`, `count`. `role` (the persona body) replaced `rule` in v1.1.0; `rule` is still returned with the same value and still accepted on `POST` for older clients. `levels` starts with `auto` since v1.1.0 — the model selector then picks the reasoning level per request from the kind of work — and `auto_reasoning` was removed with the global toggle. `POST` is a partial update — `self_id` / `name` / `role` / `model` / `reasoning` are all optional and a field left out (or `null`) is untouched; `model: ""` resets to `auto`, `reasoning` must be one of `levels`. A duplicate `self_id` returns 409. `DELETE` removes the session directory, history, state, and vectors. `GET` also takes `?chat=1` to append the action log under `chat` and `?usage=1` to append per-model token usage under `usage`; both are off by default because the log can be large. Since v1.0.12 the `chat` payload is trimmed: for a task that already reached `done` / `canceled` / `error`, its `tool_*` and `thinking` lines and every assistant line but the last are dropped, so a finished task contributes its outcome rather than its whole trace |
| `POST` | `/v1/session/:id/event` | **local** — publish an event into a session's stream |
| `POST` | `/v1/session/:id/memory` | **local** — one memory operation, picked by `action`: `summary` rebuilds the rolling summary and returns `count`; `compact` drops older messages and returns `removed`; `reset` clears the conversation and returns `removed`, and requires `mode` — `summary` keeps the rolling summary, `all` wipes it too |
| `POST` | `/v1/session/:id/cancel/:task_hash` | Cancel one running task. Returns `{ok, cancelled:true}` when that task hash is running in this process; otherwise (or for `current`) it records a canceled event on the session stream and returns `{ok, cancelled:false, stale:true}` |
| `POST` | `/v1/session/:id/confirm/:confirm_hash` | Resolve an outstanding tool confirmation: `{approve, remember?, allow_turn?, abort?, reason?, password?}`. 410 when the confirmation was already resolved or expired. Approving a confirmation that lists `restricted` paths must come from loopback (403 otherwise) and passes the OS password check with `password` (401 on failure); the check is skipped while the sudo ticket is still cached, which the confirm event reports as `password_cached` |

## Pending and completed tasks

| Method | Path | Description |
|---|---|---|
| `GET` | `/v1/session/:id/task` | List resumable pending (`ask_user` / confirm) tasks. Tasks whose run is still live are excluded — a run refreshes `action:<session_id>:<task_hash>` in ToriiDB every 55 s with a 60 s TTL (v0.35.3), so a task left behind by a closed window or a killed process reappears here within a minute |
| `GET` | `/v1/session/:id/task/:task_hash/questions` | Get a pending task's questions |
| `POST` | `/v1/session/:id/task/:task_hash/resume` | Answer a pending task and resume |
| `DELETE` | `/v1/session/:id/task/:task_hash` | Discard a pending task without answering |
| `GET` | `/v1/session/:id/task/history` | **local** — completed tasks of this session, newest first: `{task_hash, end_at, objective, model, reasoning}` per row. `?keyword=` filters on the objective and the recorded action text |
| `GET` | `/v1/session/:id/task/:task_hash/history` | **local** — the full action record of one completed task, returned as a JSON string under `content`. 404 when that hash has no record |
