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

# Runs

> Start a run on a machine, follow it, and read its messages, outputs, tree and usage

A run is one execution of a harness: a message goes in, the agent works on its
machine, and what comes out is a transcript, some outputs, a tree of whatever it
spawned, and a bill. This page starts one and follows it to the end.

## What a run needs

Two ids and an input.

**The harness** is the code the agent is — the tree that runs is the tip of its
`main` branch, and the run records the exact commit it got.

```bash theme={null}
curl -s "$SPLOX_BASE_URL/v2/harnesses" \
  -H "Authorization: Bearer $SPLOX_API_KEY"
```

```json theme={null}
{"data":[{"id":"h_5V125BR7R4AA189NRYAB3DQC6D","name":"My Agent"}],"page":{"has_more":false,"next_cursor":null}}
```

**The machine** is the computer it runs on. A run happens somewhere: the
filesystem it writes to, the shell it opens and the browser it drives all belong
to a machine, and that machine keeps them between runs. Machines are listed on
`/v1`, which speaks raw UUIDs:

```bash theme={null}
curl -s "$SPLOX_BASE_URL/v1/machines" \
  -H "Authorization: Bearer $SPLOX_API_KEY"
```

```json theme={null}
{
  "machines": [
    {
      "id": "01a060ee-ffb4-736c-9863-db1fee5c13df",
      "kind": "sandbox",
      "harness_id": "bb088abc-1f04-5282-84d7-1e52c6dbb0cd",
      "harness_ref": "main",
      "name": "My Agent",
      "last_active_at": "2026-09-02T07:25:39Z",
      "created_at": "2026-09-02T07:04:30Z",
      "live": {"state": "running", "cpu": 2, "memory_gb": 4, "disk_gb": 30, "auto_stop_minutes": 30}
    }
  ]
}
```

v2 wants that id in public form, which is a pure encoding of the same UUID:

```python theme={null}
from splox import encode_id
encode_id("m", "01a060ee-ffb4-736c-9863-db1fee5c13df")  # 'm_01M1GEXZXMEDP9GRYV3ZQ5R4YZ'
```

<Note>
  The machine must already run the harness you name. Point a run at a machine
  belonging to another harness and it is refused: `422 validation_failed`, "The
  machine runs a different agent.", with `/machine_id: the machine runs another
    harness`.
</Note>

## Create a run

```bash theme={null}
curl -s "$SPLOX_BASE_URL/v2/runs" \
  -H "Authorization: Bearer $SPLOX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "harness_id": "h_5V125BR7R4AA189NRYAB3DQC6D",
    "machine_id": "m_01M1GEXZXMEDP9GRYV3ZQ5R4YZ",
    "input": {"role": "user", "content": [{"type": "text", "text": "Run `uname -sm` in your sandbox and reply with exactly what it printed."}]},
    "metadata": {"source": "docs"}
  }'
```

```json theme={null}
{
  "id": "run_01M1GFRNR5F4N8S2JZV85T30A4",
  "harness_id": "h_5V125BR7R4AA189NRYAB3DQC6D",
  "harness_commit": "371758ecf28e8240192e4731080a7436fb492a09",
  "chat_id": "chat_01M1GFRNQHF6W9Q9RMP1QMZQR8",
  "parent_chat_id": null,
  "status": "queued",
  "created_at": "2026-09-02T07:19:05.214339044Z",
  "updated_at": "2026-09-02T07:19:05.214339044Z",
  "started_at": null,
  "completed_at": null,
  "failure": null,
  "metadata": {"source": "docs"}
}
```

`201`, with `Location: /v2/runs/run_01M1GFRNR5F4N8S2JZV85T30A4`. The run is
queued, not finished — the call returns as soon as the work is accepted.

<ParamField body="harness_id" type="string" required>
  The harness to execute. It runs the tip of `main`, and the answer tells you which commit that was.
</ParamField>

<ParamField body="machine_id" type="string" required>
  The machine to execute on. Required unless you continue a chat that is already on one.
</ParamField>

<ParamField body="input" type="object" required>
  `{"role": "user", "content": [...]}`. Content parts are `{"type":"text","text":...}`,
  `{"type":"json","value":...}` or `{"type":"file","url":...,"media_type":...,"name":...}`.
</ParamField>

<ParamField body="chat_id" type="string">
  Continue an existing chat instead of starting a new one. The run inherits that chat's machine and memory.
</ParamField>

<ParamField body="metadata" type="object">
  Yours to use — up to 50 keys of string, number, boolean or null. Keys starting with `splox.` are reserved.
</ParamField>

Send the same key and body again and nothing new happens: the original run comes
back with `Idempotency-Replayed: true`. Send the same key with a different body
and you get `409 idempotency_key_conflict`.

## Follow it

Two ways: subscribe to the event stream, which is what the app does, or poll the
run. Streaming is its own page — [Streaming](/api/streaming) — and polling is one
request:

```bash theme={null}
curl -s "$SPLOX_BASE_URL/v2/runs/run_01M1GFRNR5F4N8S2JZV85T30A4" \
  -H "Authorization: Bearer $SPLOX_API_KEY"
```

```json theme={null}
{
  "id": "run_01M1GFRNR5F4N8S2JZV85T30A4",
  "harness_id": "h_5V125BR7R4AA189NRYAB3DQC6D",
  "harness_commit": "371758ecf28e8240192e4731080a7436fb492a09",
  "chat_id": "chat_01M1GFRNQHF6W9Q9RMP1QMZQR8",
  "parent_chat_id": null,
  "status": "succeeded",
  "created_at": "2026-09-02T07:19:05.219385Z",
  "updated_at": "2026-09-02T07:19:16.72456Z",
  "started_at": "2026-09-02T07:19:05.214339Z",
  "completed_at": "2026-09-02T07:19:16.72456Z",
  "failure": null,
  "metadata": {"source": "docs"}
}
```

| Status                             | Means                                                                      |
| ---------------------------------- | -------------------------------------------------------------------------- |
| `queued`                           | accepted, not started                                                      |
| `running`                          | the agent is working                                                       |
| `waiting`                          | stopped on a question for a person — see [Interactions](/api/interactions) |
| `cancelling`                       | a cancel was asked for and has not landed yet                              |
| `succeeded`, `failed`, `cancelled` | terminal; nothing more will happen                                         |

A failed run carries a `failure` object with a stable `code`, a message written
for a person, and whether retrying could help:

```json theme={null}
"failure": {
  "code": "usage_window_exceeded",
  "message": "You have used your 5-hour limit. It frees up at 12:19 UTC on 2 Sep 2026.",
  "retryable": false
}
```

## Read the transcript

Messages are the conversation the model actually had, oldest first:

```bash theme={null}
curl -s "$SPLOX_BASE_URL/v2/runs/run_01M1GFRNR5F4N8S2JZV85T30A4/messages" \
  -H "Authorization: Bearer $SPLOX_API_KEY"
```

```json theme={null}
{
  "data": [
    {
      "id": "msg_01M1GFRW76F68T8K49222Z36KB",
      "run_id": "run_01M1GFRNR5F4N8S2JZV85T30A4",
      "role": "user",
      "content": [{"type": "text", "text": "Run `uname -sm` in your sandbox and reply with exactly what it printed."}],
      "created_at": "2026-09-02T07:19:11.842033Z"
    },
    {
      "id": "msg_01M1GFRYERFW2S0PQAW2E9H458",
      "role": "assistant",
      "content": [{"type": "json", "value": {"type": "tool_call", "tool_call": {
        "id": "call_996ef4f75bc744729e78f92f", "name": "compute_exec", "args": {"command": "uname -sm"}}}}],
      "created_at": "2026-09-02T07:19:14.128155Z"
    },
    {
      "id": "msg_01M1GFRYS0F6JRJH1DD8Q6WQ2F",
      "role": "tool",
      "content": [{"type": "json", "value": {"type": "tool_result", "tool_result": {
        "tool_call_id": "call_996ef4f75bc744729e78f92f",
        "output": "{\"cause\":\"ok\",\"command\":\"uname -sm\",\"exit_code\":0,\"stdout\":\"Linux x86_64\\n\",\"success\":true}",
        "metadata": {"source_url": "system:compute"}}}}],
      "created_at": "2026-09-02T07:19:14.458192Z"
    },
    {
      "id": "msg_01M1GFS0YJE3T9195YGXCTB4B0",
      "role": "assistant",
      "content": [
        {"type": "json", "value": {"type": "reasoning", "reasoning": {"text": "The command printed \"Linux x86_64\"...", "origin": {"provider": "openai", "api": "chat_completions", "model": "kimi-k3"}}}},
        {"type": "text", "text": "Linux x86_64"}
      ],
      "created_at": "2026-09-02T07:19:16.688525Z"
    }
  ],
  "page": {"has_more": false, "next_cursor": null}
}
```

Roles are `user`, `assistant`, `tool` and `system`. Everything that is not plain
prose arrives as a `json` part with its own `type` inside — `tool_call`,
`tool_result`, `reasoning` — so a client that only knows about text can render the
text parts and ignore the rest without losing them.

## Read the outputs

Outputs are what the run produced, as opposed to how it got there. The final
answer is one of them:

```bash theme={null}
curl -s "$SPLOX_BASE_URL/v2/runs/run_01M1GFRNR5F4N8S2JZV85T30A4/outputs" \
  -H "Authorization: Bearer $SPLOX_API_KEY"
```

```json theme={null}
{
  "data": [
    {
      "id": "out_01M1GFS0Z4FWNBXSY3WVBFSWE0",
      "run_id": "run_01M1GFRNR5F4N8S2JZV85T30A4",
      "type": "result",
      "name": "final_message",
      "value": "Linux x86_64",
      "created_at": "2026-09-02T07:19:16.707764Z"
    }
  ],
  "page": {"has_more": false, "next_cursor": null}
}
```

`type` is `result` or `artifact`; `value` is arbitrary JSON. If you want one thing
from a run, this is the endpoint to read.

## The tree

An agent hands work to sub-agents, and each of those is a run of its own. The
tree is a consistent snapshot of the whole family:

```bash theme={null}
curl -s "$SPLOX_BASE_URL/v2/runs/run_01M1GFRNR5F4N8S2JZV85T30A4/tree" \
  -H "Authorization: Bearer $SPLOX_API_KEY"
```

```json theme={null}
{
  "root_run_id": "run_01M1GFRNR5F4N8S2JZV85T30A4",
  "runs": [
    {"run": {"id": "run_01M1GFRNR5F4N8S2JZV85T30A4", "chat_id": "chat_01M1GFRNQHF6W9Q9RMP1QMZQR8", "status": "succeeded", "...": "..."}, "depth": 0, "child_run_ids": []},
    {"run": {"id": "run_01M1GFWT5ZEBP9V9M289WMNBEF", "chat_id": "chat_01M1GFRNQHF6W9Q9RMP1QMZQR8", "status": "succeeded", "...": "..."}, "depth": 0, "child_run_ids": []}
  ],
  "generated_at": "2026-09-02T07:19:18.303981382Z"
}
```

Depth is counted in chats, not runs: every run of this run's own chat is depth 0
— the two above are two turns of the same conversation — and a chat spawned by it
is depth 1. `child_run_ids` are the runs of the chats this one started.

## The bill

```bash theme={null}
curl -s "$SPLOX_BASE_URL/v2/runs/run_01M1GFRNR5F4N8S2JZV85T30A4/usage" \
  -H "Authorization: Bearer $SPLOX_API_KEY"
```

```json theme={null}
{
  "run_id": "run_01M1GFRNR5F4N8S2JZV85T30A4",
  "input_tokens": 3215,
  "output_tokens": 96,
  "cache_read_tokens": 22848,
  "cache_write_tokens": 0,
  "total_tokens": 26159,
  "tool_calls": 1,
  "duration_ms": 7783,
  "amount": "0.027065",
  "currency": "USD",
  "final": true,
  "updated_at": "2026-09-02T07:31:57.650167495Z"
}
```

`input_tokens` counts only the prompt tokens that were **not** served from cache,
which is why it looks small beside `cache_read_tokens`: an agent turn re-sends a
long prefix and the provider serves most of it from cache. `total_tokens` is the
honest figure.

Usage covers the same set of runs the tree does, so two turns of one chat report
the same numbers, and `final` is false while anything in that set is still
running.

## Cancel

```bash theme={null}
curl -s -X POST "$SPLOX_BASE_URL/v2/runs/run_01M1GFWNRZFQDR0EHKF2ZQYW9F/cancel" \
  -H "Authorization: Bearer $SPLOX_API_KEY"
```

```json theme={null}
{"id":"run_01M1GFWNRZFQDR0EHKF2ZQYW9F","status":"cancelled","started_at":"2026-09-02T07:21:16.317043Z","completed_at":"2026-09-02T07:21:16.463898Z","...":"..."}
```

Cancelling is idempotent and always answers `200` with the run as it now stands.
A run already in a terminal state comes back unchanged — cancelling a finished
run is not an error. A run that is mid-turn normally passes through `cancelling`
before it reaches `cancelled`.

## List runs

```bash theme={null}
curl -s "$SPLOX_BASE_URL/v2/runs?limit=2" \
  -H "Authorization: Bearer $SPLOX_API_KEY"
```

Newest first, by `(created_at, id)`. Filters: `status` (comma-separated, e.g.
`status=running,waiting`, or repeated `status=` parameters), `harness_id`,
`created_after`, `created_before`, plus `cursor` and `limit`. Follow
`page.next_cursor` while `page.has_more` is true.

## A second turn in the same chat

Pass `chat_id` and the run joins the conversation rather than starting one — same
machine, same memory, and the agent can refer back to what it already did:

```bash theme={null}
curl -s "$SPLOX_BASE_URL/v2/runs" \
  -H "Authorization: Bearer $SPLOX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "harness_id": "h_5V125BR7R4AA189NRYAB3DQC6D",
    "machine_id": "m_01M1GEXZXMEDP9GRYV3ZQ5R4YZ",
    "chat_id": "chat_01M1GFRNQHF6W9Q9RMP1QMZQR8",
    "input": {"role": "user", "content": [{"type": "text", "text": "What architecture did you just report? One word."}]}
  }'
```

The new run reports the same `chat_id`, and its single output is the answer to a
question that only makes sense in context:

```json theme={null}
{"data":[{"id":"out_01M1GFWZ5PEPE95WTX2Y9VZWYG","run_id":"run_01M1GFWT5ZEBP9V9M289WMNBEF","type":"result","name":"final_message","value":"x86_64","created_at":"2026-09-02T07:21:25.941363Z"}],"page":{"has_more":false,"next_cursor":null}}
```

## The same run in the SDKs

<CodeGroup>
  ```python Python theme={null}
  run = client.runs.create(
      {"role": "user", "content": [{"type": "text", "text": "Run `uname -sm` and reply with what it printed."}]},
      harness_id="h_5V125BR7R4AA189NRYAB3DQC6D",
  )
  run = run.wait()
  print(run.status)                                  # succeeded
  print([o.value for o in run.outputs().data])       # ['Linux x86_64']
  print(run.usage().total_tokens, run.usage().amount)
  ```

  ```ts Node theme={null}
  const run = await client.runs.create({
    harnessId: "h_5V125BR7R4AA189NRYAB3DQC6D",
    input: "Run `uname -sm` and reply with what it printed.",
  });
  await run.wait();
  const outputs = await run.outputs();
  console.log(outputs.data.map((o) => o.value));      // [ 'Linux x86_64' ]
  ```

  ```go Go theme={null}
  run, err := client.Runs.Create(ctx, splox.CreateRunParams{
      HarnessID: "h_5V125BR7R4AA189NRYAB3DQC6D",
      Input:     "Run `uname -sm` and reply with what it printed.",
  })
  run, err = run.Wait(ctx, splox.WaitOpts{Timeout: 5 * time.Minute})
  outs, err := client.Runs.OutputsPage(ctx, run.ID, splox.PageOpts{})
  ```
</CodeGroup>

<Warning>
  The published SDKs (Python and Node `0.5.4`, Go `v2.0.0`) do not send
  `machine_id`, so `runs.create` against the current API answers
  `422 validation_failed` with `/machine_id: machine_id is required`. Until they
  ship it, create runs over HTTP as above; every other call in all three SDKs works
  against the live API.
</Warning>
