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

# Run Management Tools

> run_skill, get_run, subscribe_run, and cancel_run manage the durable run lifecycle — draft, queued, running, succeeded, failed, cancelled.

The run management tools family covers the durable run lifecycle. Skill-backed tools execute as **durable runs** — persistent state machines that survive server restarts, stream events as they progress, and produce artifacts on completion. The agent creates runs with `run_skill`, inspects them with `get_run`, polls for new events with `subscribe_run`, and cancels them with `cancel_run`.

## The run state machine

Every durable run moves through a fixed state machine:

```
draft → queued → running → succeeded
                          → failed
                          → cancelled
```

| State       | Description                                                                            |
| ----------- | -------------------------------------------------------------------------------------- |
| `draft`     | The run has been created but not yet queued. The agent can still modify inputs.        |
| `queued`    | The run is waiting for a worker. Inputs are frozen.                                    |
| `running`   | A worker has picked up the run and is executing the skill. Events stream in real time. |
| `succeeded` | The run completed successfully. Artifacts are available.                               |
| `failed`    | The run failed. The `error` field on the run record contains details.                  |
| `cancelled` | The run was cancelled by the agent or the human. The `reason` field records why.       |

<Callout type="info">
  `succeeded`, `failed`, and `cancelled` are terminal states. A run in a terminal state cannot be restarted — you must create a new run.
</Callout>

## `run_skill`

Create a durable run for a skill. Returns a `run_id` immediately; the skill executes asynchronously. Poll with `get_run` or stream with `subscribe_run` for progress and results.

### Arguments

| Argument   | Type   | Required | Description                                                                                                              |
| ---------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `skill_id` | string | Yes      | The skill identifier (from `search_skills`).                                                                             |
| `input`    | object | Yes      | The skill input dict (validated against the skill's `input_schema`).                                                     |
| `mode`     | string | No       | Execution mode: `sync` (wait for completion, default for short skills) or `async` (return immediately). Default `async`. |

### Return value

| Field        | Type              | Description                           |
| ------------ | ----------------- | ------------------------------------- |
| `run_id`     | string (UUID)     | The durable run identifier.           |
| `skill_id`   | string            | The skill being run.                  |
| `status`     | string            | Initial status (`draft` or `queued`). |
| `created_at` | string (ISO 8601) | When the run was created.             |

### Example call

```json theme={null}
{
  "skill_id": "congress_trades",
  "input": { "symbol": "NVDA", "since": "2024-01-01" },
  "mode": "async"
}
```

### Example response

```json theme={null}
{
  "run_id": "run_01HQKX2J3K4M5N6P7R8S9T0V3C",
  "skill_id": "congress_trades",
  "status": "queued",
  "created_at": "2025-01-15T14:35:00.123Z"
}
```

## `get_run`

Fetch the full run record — status, jobs, artifacts, and events. This is the polling endpoint. For long-running skills, call `get_run` periodically until `status` is terminal.

### Arguments

| Argument | Type   | Required | Description         |
| -------- | ------ | -------- | ------------------- |
| `run_id` | string | Yes      | The run identifier. |

### Return value

| Field        | Type           | Description                                                   |
| ------------ | -------------- | ------------------------------------------------------------- |
| `run_id`     | string         | The run identifier.                                           |
| `skill_id`   | string         | The skill being run.                                          |
| `status`     | string         | Current state of the run.                                     |
| `input`      | object         | The frozen input dict.                                        |
| `output`     | object \| null | The skill output, if the run succeeded.                       |
| `error`      | object \| null | Error details, if the run failed.                             |
| `jobs`       | array          | Sub-jobs (e.g. per-symbol fetches) with their own statuses.   |
| `artifacts`  | array          | Artifacts produced by the run (with `artifact_id` and `uri`). |
| `events`     | array          | Chronological event log (state transitions, progress, logs).  |
| `created_at` | string         | When the run was created.                                     |
| `updated_at` | string         | When the run was last updated.                                |

### Example call

```json theme={null}
{ "run_id": "run_01HQKX2J3K4M5N6P7R8S9T0V3C" }
```

### Example response

```json theme={null}
{
  "run_id": "run_01HQKX2J3K4M5N6P7R8S9T0V3C",
  "skill_id": "congress_trades",
  "status": "succeeded",
  "input": { "symbol": "NVDA", "since": "2024-01-01" },
  "output": {
    "trades": [
      { "member": "Pelosi, Nancy", "symbol": "NVDA", "transaction_date": "2024-06-24", "type": "buy", "amount_range": "$1,000,001 - $5,000,000", "filing_date": "2024-07-01" }
    ]
  },
  "error": null,
  "jobs": [
    { "job_id": "job_01", "step": "fetch_disclosures", "status": "succeeded", "duration_ms": 1240 }
  ],
  "artifacts": [
    { "artifact_id": "art_01HQKX2J3K4M5N6P7R8S9T0V3D", "uri": "s3://doomberg-artifacts/run_01.../trades.json", "content_hash": "sha256:..." }
  ],
  "events": [
    { "ts": "2025-01-15T14:35:00.123Z", "type": "run_created" },
    { "ts": "2025-01-15T14:35:00.500Z", "type": "run_queued" },
    { "ts": "2025-01-15T14:35:01.100Z", "type": "job_started", "job_id": "job_01" },
    { "ts": "2025-01-15T14:35:02.340Z", "type": "job_succeeded", "job_id": "job_01" },
    { "ts": "2025-01-15T14:35:02.500Z", "type": "run_succeeded" }
  ],
  "created_at": "2025-01-15T14:35:00.123Z",
  "updated_at": "2025-01-15T14:35:02.500Z"
}
```

## `subscribe_run`

Poll for new events since a cursor. This is the efficient alternative to re-fetching the full run record on every poll. Pass the `cursor` returned by the previous `subscribe_run` call to get only events that arrived after that point.

### Arguments

| Argument | Type   | Required | Description                                                                                               |
| -------- | ------ | -------- | --------------------------------------------------------------------------------------------------------- |
| `run_id` | string | Yes      | The run identifier.                                                                                       |
| `cursor` | string | No       | An opaque cursor from a previous `subscribe_run` response. If omitted, returns all events from the start. |

### Return value

| Field    | Type    | Description                                                              |
| -------- | ------- | ------------------------------------------------------------------------ |
| `run_id` | string  | The run identifier.                                                      |
| `status` | string  | Current run status.                                                      |
| `events` | array   | Events that arrived after the cursor.                                    |
| `cursor` | string  | The cursor to pass on the next call.                                     |
| `done`   | boolean | `true` if the run is in a terminal state and no more events will arrive. |

### Example call

```json theme={null}
{ "run_id": "run_01HQKX2J3K4M5N6P7R8S9T0V3C", "cursor": "evt_01HQKX2J3K4M5N6P7R8S9T0V3E" }
```

### Example response

```json theme={null}
{
  "run_id": "run_01HQKX2J3K4M5N6P7R8S9T0V3C",
  "status": "succeeded",
  "events": [
    { "ts": "2025-01-15T14:35:02.340Z", "type": "job_succeeded", "job_id": "job_01" },
    { "ts": "2025-01-15T14:35:02.500Z", "type": "run_succeeded" }
  ],
  "cursor": "evt_01HQKX2J3K4M5N6P7R8S9T0V3F",
  "done": true
}
```

<Tip>
  When `done` is `true`, stop polling. The run is terminal and no further events will arrive. Fetch the final output with `get_run` if you haven't already.
</Tip>

## `cancel_run`

Cancel a queued or running run. The run transitions to `cancelled` and the worker stops processing. Already-produced artifacts are retained.

### Arguments

| Argument | Type   | Required | Description                                                             |
| -------- | ------ | -------- | ----------------------------------------------------------------------- |
| `run_id` | string | Yes      | The run identifier.                                                     |
| `reason` | string | No       | A human-readable reason for the cancellation. Stored on the run record. |

### Return value

| Field          | Type              | Description                 |
| -------------- | ----------------- | --------------------------- |
| `run_id`       | string            | The run identifier.         |
| `status`       | string            | `cancelled`.                |
| `cancelled_at` | string (ISO 8601) | When the run was cancelled. |
| `reason`       | string            | The reason provided.        |

### Example call

```json theme={null}
{ "run_id": "run_01HQKX2J3K4M5N6P7R8S9T0V3C", "reason": "User changed research direction." }
```

### Example response

```json theme={null}
{
  "run_id": "run_01HQKX2J3K4M5N6P7R8S9T0V3C",
  "status": "cancelled",
  "cancelled_at": "2025-01-15T14:36:00.000Z",
  "reason": "User changed research direction."
}
```

<Callout type="warn">
  A run in a terminal state (`succeeded`, `failed`, `cancelled`) cannot be cancelled. Calling `cancel_run` on a terminal run returns a `run_already_terminal` error.
</Callout>

## Polling pattern

<Steps>
  <Step title="Create the run">
    Call `run_skill` with the `skill_id` and `input`. Get back a `run_id`.
  </Step>

  <Step title="Subscribe for events">
    Call `subscribe_run` with the `run_id` (no cursor). Process the initial events and save the `cursor`.
  </Step>

  <Step title="Poll until done">
    Call `subscribe_run` with the saved `cursor` on an interval (e.g. every 1–2 seconds). Stop when `done` is `true`.
  </Step>

  <Step title="Fetch the final output">
    Call `get_run` to read the `output`, `artifacts`, and full event log.
  </Step>
</Steps>

## Related

* [Data tools](/tools/data) — `search_skills` and `describe_skill` for discovery
* [Artifact tools](/tools/artifacts) — fetching artifacts produced by runs
* [Trace observability](/api/runs) — how runs appear in the web UI
