# Commands

`POST /v1/runs/:id/commands`

Key `runs:write`, or session: member. On a personal worker, `send`, `steer`, `queue`, and `answer` are refused with 403 for anyone but the worker's owner; any member may `cancel`.

Every command has a `kind`, a `payload`, and an `idempotency_key` (1 to 200 characters). A repeated key returns the original command.

| `kind`   | `payload`                                  | Effect                                                     |
| -------- | ------------------------------------------ | ---------------------------------------------------------- |
| `send`   | `{ "text": "..." }`                        | Start a new turn when the runner is idle.                  |
| `queue`  | `{ "text": "..." }`                        | Run the text as the next turn, immediately when idle.      |
| `steer`  | `{ "text": "..." }`                        | Add the text to the turn in progress.                      |
| `answer` | `{ "request_id": "...", "response": ... }` | Resolve a permission or question the runner is waiting on. |
| `cancel` | `{}`                                       | Stop the runner and end the run as cancelled.              |

`text` is 1 to 100,000 characters.

```sh
curl https://api.workbenches.dev/v1/runs/wb_.../commands \
  -H "Authorization: Bearer $WORKBENCHES_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "kind": "send", "payload": { "text": "Also check the rollback." }, "idempotency_key": "followup-1" }'
```

Response `202`:

```json
{
    "command": {
        "id": "wbc_...",
        "run_id": "wb_...",
        "kind": "send",
        "payload": { "text": "Also check the rollback." },
        "idempotency_key": "followup-1",
        "status": "pending",
        "reason": null,
        "created_at": "...",
        "delivered_at": null
    },
    "after_sequence": 42
}
```

Read events after `after_sequence` to see the effect.

## Answers

`request_id` is the ID of the pending request, from the `input.requested` or `question.requested` event. `response` is:

- for a permission: `allow`, `deny`, or an offered option,
- for a question: a string for a single question, or an array of string arrays, one per question, such as `[["Yes"], ["Staging", "Production"]]`.

Strings are 1 to 100,000 characters; an array holds up to 100 arrays of up to 100 strings of up to 10,000 characters.

A runner can withdraw a request it no longer needs. The run then records `input.rejected` (for a permission) or `question.rejected` with `code: "request_withdrawn"`, goes back to `running`, and a later answer to it is rejected because the request is no longer pending.

## Command lifecycle

A command is stored first and delivered by the run's coordinator:

| `status`    | Meaning                                                                                         |
| ----------- | ----------------------------------------------------------------------------------------------- |
| `pending`   | Stored, not yet picked up. A command that arrives before the runner is up waits.                |
| `claimed`   | Picked up for delivery.                                                                         |
| `delivered` | Given to the runner. `delivered_at` is set.                                                     |
| `rejected`  | Refused, with a `reason`, for example when the runner is still responding or the run has ended. |

A command to a run that has ended answers 409.

## Errors

| Status | When                                                                                       |
| ------ | ------------------------------------------------------------------------------------------ |
| 400    | The body does not match a command shape.                                                   |
| 403    | Outside the run's organization, missing `runs:write`, or a non-owner on a personal worker. |
| 404    | No such run.                                                                               |
| 409    | The run has ended.                                                                         |
