# client.runs

> client.runs — the runs operations.

`client.runs` — the `runs` operations.

On `AsyncKindgi` every method is the same, awaited.

## `client.runs.list()`

```python signature
list(
    *,
    limit: int | None = None,
    cursor: str | None = None,
    scope_kind: Literal['tenant', 'org', 'project'] | None = None,
    scope_id: str | UUID | None = None,
    parent_run_id: str | UUID | None = None,
    top_level: bool | None = None,
    agent_id: str | UUID | None = None,
    replays: Literal['exclude', 'include', 'only'] | None = None,
    eval_run_id: str | UUID | None = None,
    trigger_id: str | UUID | None = None,
    include: Literal['output'] | None = None,
    status: Literal['pending', 'running', 'suspended', 'completed', 'failed', 'cancelled'] | list[Literal['pending', 'running', 'suspended', 'completed', 'failed', 'cancelled']] | None = None,
    created_after: str | None = None,
    created_before: str | None = None,
    agent_version: str | None = None,
    flow_id: str | UUID | None = None,
    flow_version: str | None = None,
    timeout: float | None = None,
) -> RunCollectionPage
```

List runs. `GET /v1/runs`

Cursor-paginated. Fixed sort order: `createdAt desc, id desc`.

## `client.runs.start()`

```python signature
start(
    body: StartRunBody | Mapping[str, Any] | None = None,
    /,
    *,
    idempotency_key: str | None = None,
    timeout: float | None = None,
    **fields: Any,
) -> Run
```

Start a run. `POST /v1/runs`

One primitive, discriminated subject (`agent` XOR `flow`). When the deployment issues public run tokens, the response carries `publicAccessToken`: a read-only token for this run (15 minutes by default) to hand to a browser, which follows the run with it on `GET /v1/runs/{runId}/progress` and its stream.

## `client.runs.failures()`

```python signature
failures(
    *,
    project_id: str | UUID,
    from_: str,
    to: str,
    agent_id: str | UUID | None = None,
    flow_id: str | UUID | None = None,
    group_by: str | None = None,
    limit: int | None = None,
    timeout: float | None = None,
) -> RunFailureGroups
```

A project's failed runs, grouped by cause and version. `GET /v1/runs/failures`

Counts from the server, never from a page: per group, how many runs failed, when the first and the latest failed in the window, and the latest run. People's decisions (`hitl-*`: an approval rejected, cancelled or timed out) come apart as `outcomes`, never as failures. Runs that failed before their cause was recorded come apart as `unrecorded`, by subject and version only. Replays, eval runs' runs and dry runs aren't counted; a child run counts under its own agent or flow. Failed runs go with their retention, so a window can hold fewer than happened. Needs `read` on the project.

## `client.runs.get()`

```python signature
get(run_id: str | UUID, /, *, timeout: float | None = None) -> Run
```

Fetch a run. `GET /v1/runs/{runId}`

## `client.runs.cancel()`

```python signature
cancel(
    run_id: str | UUID,
    /,
    *,
    idempotency_key: str | None = None,
    timeout: float | None = None,
) -> Run
```

Cancel a run. `POST /v1/runs/{runId}/cancel`

Cancelling a run that already reached a terminal state returns `409 run-already-terminal`.

## `client.runs.resume()`

```python signature
resume(
    run_id: str | UUID,
    body: ResumeRunBody | Mapping[str, Any] | None = None,
    /,
    *,
    idempotency_key: str | None = None,
    timeout: float | None = None,
    **fields: Any,
) -> None
```

Resume a suspended run at a waitpoint (not available in this release). `POST /v1/runs/{runId}/resume`

Not available in this release: always `422 run-resume-not-supported`, and no waitpoint is completed. Every waitpoint a run can wait at belongs to an approval or to the runtime itself. A run waiting for an approval continues when a reviewer decides it: `POST /v1/approvals/{approvalId}/complete`.

## `client.runs.journal()`

```python signature
journal(
    run_id: str | UUID,
    /,
    *,
    since: int | None = None,
    limit: int | None = None,
    cursor: str | None = None,
    timeout: float | None = None,
) -> RunJournalPage
```

Read the durable journal for a run. `GET /v1/runs/{runId}/journal`

Returns raw `JournalEntry` values from the run journal (`@kindgi/runtime`), in sequence order. Distinct from the SSE wire enum — see `docs/API-ROUTE-CONVENTIONS.md` §6. Paging is opt-in: with `limit`, at most that many entries and a `nextCursor` while more remain; without it, the whole journal in one answer.

## `client.runs.stream()`

```python signature
stream(
    run_id: str | UUID,
    /,
    *,
    last_event_id: str | UUID | None = None,
    timeout: float | None = None,
) -> Iterator[RunEvent]
```

Server-Sent Events stream of RunEvent frames. `GET /v1/runs/{runId}/stream`

Each SSE frame is one `RunEvent` per `@kindgi/specs/run-event.schema.json`. Reconnect via `Last-Event-Id: <runId>:<sequence>`. The server ends the stream after the run's terminal event, or after 5 minutes: reconnect with `Last-Event-Id` to continue.

## `client.runs.progress()`

```python signature
progress(run_id: str | UUID, /, *, timeout: float | None = None) -> RunProgress
```

A run's progress (status and timing, no data). `GET /v1/runs/{runId}/progress`

The run's status and timing, without its input, output or failure message: safe to show in a browser. Accepts an API token, or a public run token (`kgi_pt_…`) that names the run or one of its ancestors.

## `client.runs.progress_stream()`

```python signature
progress_stream(
    run_id: str | UUID,
    /,
    *,
    last_event_id: str | UUID | None = None,
    timeout: float | None = None,
) -> Iterator[RunProgressEvent]
```

Server-Sent Events stream of a run's progress. `GET /v1/runs/{runId}/progress/stream`

Each SSE frame is one `RunProgressEvent`: what happened, on which node, when — no payloads. Accepts an API token, or a public run token that names the run or one of its ancestors. Reconnect via `Last-Event-Id`; the server ends the stream after the run's terminal event, or after 5 minutes.

## `client.runs.follow()`

```python signature
follow(
    run_id: str | UUID,
    /,
    *,
    last_event_id: str | UUID | None = None,
    timeout: float | None = None,
) -> Iterator[RunEvent]
```

Follow a run's events to its end. `GET /v1/runs/{runId}/stream`

`runs.stream`, through to the run's terminal event (`run.completed`, `run.failed` or `run.cancelled`), each event once. The server ends a run's stream after 5 minutes while the run goes on; this reconnects with `Last-Event-Id` and goes on. A dropped connection, a 429 or a 502-504 is retried with backoff; any other error is raised. Ends after the terminal event.

## `client.runs.follow_progress()`

```python signature
follow_progress(
    run_id: str | UUID,
    /,
    *,
    last_event_id: str | UUID | None = None,
    timeout: float | None = None,
) -> Iterator[RunProgressEvent]
```

Follow a run's progress to its end. `GET /v1/runs/{runId}/progress/stream`

`runs.progress_stream`, through to the run's terminal event (`run.completed`, `run.failed` or `run.cancelled`), each event once. The server ends a run's stream after 5 minutes while the run goes on; this reconnects with `Last-Event-Id` and goes on. A dropped connection, a 429 or a 502-504 is retried with backoff; any other error is raised. Ends after the terminal event.
