> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.cloudraker.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.cloudraker.com/_mcp/server.

# Agents

The [capability verbs](/capabilities/extract) do one thing per call. An **agent** does a *sequence* of things: read the intake pack, extract the fields, fill the form, wait for a human to countersign, file the result. It is a saved, reviewed automation — a list of steps, the [saved actions](/capabilities/actions) it is allowed to take, and the points where a person has to sign off.

`GET /v1/agents` lists the agents your organization can run; `POST /v1/agent-runs` starts one on a set of files. Everything after that is one object — the **agent run** (`agr_…`) — that you poll or subscribe to.

An **agent** in the API is a **playbook** in the CloudRaker app. Same object, same runs: what you build and review under [Playbooks](/playbooks/overview) is what `GET /v1/agents` returns, and a run started over the API shows up there like any other.

## An agent

```json
{
  "object": "agent",
  "id": "01JQ8ZKMRT4V6WXYZ0ABCDEFGH",
  "name": "Client intake",
  "description": "Reads an intake pack, files the data, and collects a signature.",
  "version": 7,
  "tasks": [
    { "id": "task-1", "title": "Extract the intake fields", "executor": "agent", "dependsOn": [] },
    { "id": "task-2", "title": "Countersign the engagement letter", "executor": "human", "dependsOn": ["task-1"] }
  ],
  "actions": [
    { "name": "Extract structured data", "approval": "output" },
    { "name": "Sign document", "approval": "before" }
  ],
  "updatedAt": "2026-07-28T14:02:11.884Z"
}
```

| Field       | What it tells you                                                                                                                                             |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tasks[]`   | The **step ledger** — the shape of the work. `executor: "human"` marks the steps that come back to you. `dependsOn` is what has to close before a step opens. |
| `actions[]` | What the agent may do, and the `approval` gate on each.                                                                                                       |
| `version`   | The revision a new run will snapshot. Editing the agent doesn't change runs already in flight.                                                                |

Only **active** agents are listed. Ids are opaque strings — don't parse them.

## Who does each step

Every step has an `executor`, and that is the whole division of labour:

* **`agent`** — it runs by itself. Nothing for you to do.
* **`human`** — it waits. Complete it with [`POST /v1/agent-runs/:id/tasks/:taskId/complete`](/developers/agent-runs#complete-a-human-step), optionally attaching a note and files.

On a run, each step also carries a `status`: `pending` (blocked on its `dependsOn`), `ready` (open), `in_progress`, `completed`, or `skipped` — a skipped step satisfies anything waiting on it, exactly like a completed one.

## Sign-off gates

An action's `approval` says where a human has to agree before the agent may proceed:

| `approval` | Gate                                                                                                      |
| ---------- | --------------------------------------------------------------------------------------------------------- |
| `auto`     | No sign-off. The agent runs the action.                                                                   |
| `before`   | Approve the **proposed inputs** before it runs. The approval carries the `params` the agent wants to use. |
| `output`   | Approve the **result** before it is used.                                                                 |
| `both`     | Both gates.                                                                                               |

Every outstanding sign-off appears in `approvals[]` on the run, with a `kind` of `before` or `output`, the action's name, the files it touches, and — for a `before` gate — the proposed `params`. Answer it with [`POST /v1/agent-runs/:id/approvals/:approvalId`](/developers/agent-runs#decide-an-approval); approving lets you replace those `params` or `files` first, and rejecting requires a `note`.

## Run statuses

| Status       | Meaning                                                                                                   |
| ------------ | --------------------------------------------------------------------------------------------------------- |
| `queued`     | Accepted; its files are still being prepared. **Reading the run is what picks it up** once they're ready. |
| `processing` | The agent is working.                                                                                     |
| `waiting`    | Blocked on a person — see `waiting`, `approvals[]`, and the `ready` human steps in `tasks[]`.             |
| `paused`     | Stopped short and resumable. **Not a failure.** `paused.reason` is `model_error` or `system_error`.       |
| `completed`  | Finished. `result` and `output` are populated.                                                            |
| `failed`     | Finished without producing a result. `error.code` and `error.message` say why.                            |
| `cancelled`  | Stopped on request.                                                                                       |
| `expired`    | Reached `expiresAt` without finishing.                                                                    |

`completed`, `failed`, `cancelled`, and `expired` are terminal.

A `completed` run that still had outstanding work also carries **`incomplete: true`** — it closed with steps unfinished, and `tasks[]` shows which. Treat it as "done, with gaps", not as a failure.

A `paused` run keeps everything it produced and can be started again. Whatever an agent run already filed — imported records, attached files, a sealed signature — is **never taken back**, at any status.

## Long-lived by design

An agent run that is blocked on a person waits **days**, and the API is built for that:

* **`expiresAt` is about seven days out.** That is the run's deadline, not a cleanup timer: an unfinished run parks itself for good when it passes, so a human step has to land before then.
* **Input files are never purged on a deadline.** Files you pass as `{ "url": … }` join your reusable [file corpus](/developers/files), so the run still has its inputs however long it waits. There is no `ttl` on `POST /v1/agent-runs`.
* **`output.files[]` links are short-lived** — each signed URL is good for about an hour. Re-read the run for a fresh one.

Agent runs are a **separate surface from [runs](/developers/runs)**. They don't appear in `GET /v1/runs`, they have no list endpoint, and there is no cancel or delete for one — keep the `agr_` id you got at create, or find the run again with your own `metadata`.

## Next steps

#### [Agent runs](/developers/agent-runs)

Start a run, poll it, answer an approval, and complete a human step — with curl.

#### [Webhooks](/developers/webhooks#agent-runs)

The five `agent_run.*` events, so you aren't polling for days.

#### [Saved actions](/capabilities/actions)

The catalog an agent's steps are built from.

#### [Playbooks in the app](/playbooks/overview)

Build and review the same automation from the CloudRaker interface.