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

# Threads

> Read, update, delete, stream, and publish thread events

Threads are the canonical cloud conversation surface. Durable events are stored as JSONL in workspace storage and projected into `agent_threads` and `thread_rollouts` for fast listing; transient token/reasoning deltas are live-only WebSocket frames. Reach for threads when you want conversation history, multi-client live updates, compaction, or local-device runs that publish back into cloud history.

## Thread Management

| Method   | Path                              | Scope           | Description                                   |
| -------- | --------------------------------- | --------------- | --------------------------------------------- |
| `GET`    | `/v1/threads`                     | `agent:read`    | List visible threads                          |
| `GET`    | `/v1/threads/{threadId}`          | `agent:read`    | Get a thread snapshot                         |
| `GET`    | `/v1/threads/{threadId}/events`   | `agent:read`    | Read durable event history                    |
| `GET`    | `/v1/threads/{threadId}/rollouts` | `agent:read`    | List compaction rollouts                      |
| `GET`    | `/v1/threads/{threadId}/activity` | `activity:read` | Read customer-visible activity for the thread |
| `PATCH`  | `/v1/threads/{threadId}`          | `agent:run`     | Rename or archive a thread                    |
| `DELETE` | `/v1/threads/{threadId}`          | `agent:run`     | Delete a thread                               |
| `POST`   | `/v1/threads/{threadId}/compact`  | `agent:run`     | Request compaction                            |

<ParamField query="limit" type="number" default="50">
  List endpoints cap `limit` at 100 for thread lists and 500 for event reads.
</ParamField>

<ParamField query="cursor" type="string">
  Cursor returned in `meta.nextCursor`.
</ParamField>

<ParamField query="archived" type="boolean">
  Include archived threads when listing.
</ParamField>

<ParamField query="include" type="string">
  Use `include=all_rollouts` on snapshot or event reads when you need non-active rollout history.
</ParamField>

```bash cURL theme={null}
curl "https://api.runtools.ai/v1/threads?limit=25" \
  -H "X-API-Key: $RUNTOOLS_API_KEY"
```

```bash cURL theme={null}
curl "https://api.runtools.ai/v1/threads/thr_abc123/events?limit=200" \
  -H "X-API-Key: $RUNTOOLS_API_KEY"
```

## Live WebSocket

Subscribe to live thread frames:

```text theme={null}
wss://api.runtools.ai/v1/threads/{threadId}/events?api_key=<key>
wss://api.runtools.ai/v1/threads/{threadId}/events?token=<session-token>
```

Pass exactly one of `api_key` or `token`. The first frame is a `snapshot` for the owner, or a metadata-only snapshot for admin broader-view access.

Common live frames:

| Frame                                                             | Durable? | Description                                      |
| ----------------------------------------------------------------- | -------- | ------------------------------------------------ |
| `snapshot`                                                        | No       | Initial full snapshot with `protocol_version: 1` |
| `run_started` / `run_completed`                                   | Yes      | Run lifecycle                                    |
| `user_message` / `assistant_message`                              | Yes      | Final persisted messages                         |
| `tool_call` / `tool_result`                                       | Yes      | Persisted tool lifecycle and final output        |
| `assistant_message_delta`                                         | No       | Token deltas                                     |
| `assistant_thinking_delta`                                        | No       | Reasoning deltas                                 |
| `assistant_message_source`                                        | No       | Source/citation deltas                           |
| `tool_call_started` / `tool_output_delta` / `tool_call_completed` | No       | Live tool execution output                       |
| `compaction_started` / `compaction_completed`                     | Yes      | Rollout lifecycle                                |
| `thread_archived` / `thread_deleted` / `thread_renamed`           | No       | Metadata updates                                 |

## Publish Thread Events

Public clients that execute local runs, such as the desktop sidecar, publish through `POST /v1/thread-events`. This route requires user or API-key auth and rejects internal service headers.

Durable frame types:

```text theme={null}
run_started, run_completed, user_message, assistant_message, tool_call, tool_result
```

Transient frame types:

```text theme={null}
assistant_message_delta, assistant_thinking_delta, assistant_message_source,
tool_call_started, tool_output_delta, tool_call_completed
```

Transient frames require `threadId`, `runId`, `rolloutId`, and a positive `sequenceNumber`. They fan out to WebSocket subscribers but do not write JSONL or bump durable thread timestamps.

```bash cURL theme={null}
curl -X POST https://api.runtools.ai/v1/thread-events \
  -H "X-API-Key: $RUNTOOLS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "threadId": "thr_abc123",
    "frame": {
      "type": "assistant_message_delta",
      "runId": "run_abc123",
      "rolloutId": "001",
      "messageId": "msg_abc123",
      "sequenceNumber": 1,
      "delta": "Hello"
    }
  }'
```

## Thread Busy

Only one active run may write a thread at a time. Starting another run on a busy thread returns `409 THREAD_BUSY`.
