`get_run` reads a run in the authenticated workspace. It never starts or retries provider execution, changes approvals, reserves funds or creates a charge.

## Signature

```text
get_run({ run_id, wait_seconds? })
```

| Field | Type | Required | Meaning |
| --- | --- | --- | --- |
| `run_id` | UUID | yes | The ID returned by `run_tool`. |
| `wait_seconds` | integer, 0–120 | no | Wait for completion; defaults to 50 seconds. Zero returns the current state immediately. |

```json
{
  "name": "get_run",
  "arguments": { "run_id": "<existing run id>", "wait_seconds": 0 }
}
```

No idempotency key, tool ID or execution input is accepted. An expired wait returns the current state as a non-error response; call `get_run` again for the same ID.

## Return shape

Every state retains `run_id`. Success includes the result, signed artifact URLs when available, and estimated and final costs. Failure retains the teaching error and reports that the hold was released. An awaiting-approval response includes the human approval URL and estimate; reading it does not approve it.

Re-read a completed run to refresh its signed artifact URLs. This retrieves the existing output without generating or paying for it again.

## Errors and recovery

- Missing or malformed `run_id`: use the exact ID returned by `run_tool`.
- Unknown or another workspace's run: the same `run_not_found` response protects private run data.
- Invalid wait or extra fields: follow the returned hint; `get_run` accepts only `run_id` and optional `wait_seconds`.
- Failed execution: inspect the recorded failure and any external effect before authorizing a new paid intent.

The CLI equivalent is `scrollport get_run <run-id> [--wait-seconds 0..120]`; direct HTTP uses `GET /v1/runs/:id` for one immediate read.