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

# vetta session

> Create, send, stream, and manage sessions.

Manage [sessions](https://vetta.sh/docs/concepts/sessions.md) — directly-controlled runs of an agent.

## Commands

| Command | Description |
| - | - |
| `vetta session create` | Start a session from an agent (optionally with a first `--message`). |
| `vetta session send` | Send a user message (`--message`; add `--interrupt` to steer a running session). |
| `vetta session stream` | Stream events (resumable). |
| `vetta session run` | Create + send + stream + wait for idle; exits on the terminal `stop_reason`. |
| `vetta session get <id>` | Retrieve a session. |
| `vetta session list` | List sessions (paginated); `--stop-reason` narrows to one kind of stop. |
| `vetta session inbox` | Every session waiting on a person, and what each is waiting on. |
| `vetta session interrupt` | Interrupt the current turn (session goes `idle`, `stop_reason: interrupted`). |
| `vetta session confirm` | Approve or deny a tool awaiting approval. |
| `vetta session answer` | Answer a question the agent parked the turn on. |
| `vetta session usage <id>` | Show cumulative token usage and cost. |
| `vetta session budget` | Raise or remove the session cap. |
| `vetta session events` | List events for a session; `--include-accepted` adds the newer rows the list holds back by default (`message.accepted`, `outcome.evaluation.*`). |
| `vetta session cancel` | Cancel a running session. |
| `vetta session outcome set` | Hold an idle session to an [outcome](https://vetta.sh/docs/cli/outcomes.md): the next turn is graded. |

## create, send, stream

```bash theme={"system"}
SID=$(vetta session create --agent agt_01j8rf6tq2m4vz9xkp3n7c5hwd --window immediate --budget-usd 2.00 \
  --message "Refund order #4821" --output-schema ./refund.schema.json --json | jq -r .id)
vetta session send --session $SID --message "Actually, refund only 20.00 USD"
vetta session stream --session $SID --from-seq 0
```

`--from-seq` replays every event after a sequence number, so a reconnecting client never misses or duplicates events. Omit it to tail live from now. See [Events & streaming](https://vetta.sh/docs/concepts/events-and-streaming.md).

### A structured answer for one session

`--output-schema` takes a path to a JSON Schema file and overrides the agent's schema for this run;
`--require-output` refuses a clean ending that produced nothing matching it.

| Flag | Meaning |
| - | - |
| `--output-schema <path>` | JSON Schema the answer must match. Must be `"type": "object"` with at least one property — the schema *becomes* the tool the agent answers through, and a tool call's arguments are always an object, so anything else is refused with `400`. |
| `--require-output` | Without a conforming answer the session goes idle with `stop_reason: error` instead of `end_turn`. |

```bash theme={"system"}
vetta session run --agent agt_01j8rf6tq2m4vz9xkp3n7c5hwd --message "Refund order #4821" \
  --output-schema ./refund.schema.json --require-output --json | jq .structured_output
```

The document comes back on the session's `structured_output`, on the `session.idle` event and on the
`session.idle` webhook. See [Structured outputs](https://vetta.sh/docs/capabilities/structured-outputs.md).

### Graded against an outcome

`--outcome` (on `create` and `run`) attaches an [outcome](https://vetta.sh/docs/capabilities/outcomes.md) from the first turn, by `ocm_` id or by name; `vetta session outcome set` attaches one to an `idle` session. Either way the agent must run no team members (`handoffs: false`, no `multiagent` roster).

```bash theme={"system"}
vetta session create --agent agt_kt88353jaw132sjakt4sytz4a6 --outcome refund-quality --message "Refund order #4821"
vetta session outcome set --session $SID --outcome refund-quality
```

`--agent` takes the agent's `agt_` id; the outcome may be its id or its name. An ambiguous name — two outcomes share it — exits `2` and lists the ids to pick from. See [`vetta outcome`](https://vetta.sh/docs/cli/outcomes).

`vetta session run` with an outcome attached (and `vetta session stream` on a graded session) does not stop at the graded turn's own park (`awaiting_delegation` while the grader runs): it keeps streaming through the grade and any revision turn, and exits on the `session.idle` after a terminal result (`satisfied` ends `end_turn`, exit `0`). The SDK's `client.stream` does the same unless passed `throughGrades: false`.

Each grade is an `outcome.evaluation.*` event, which `vetta session events` lists only with `--include-accepted`:

```bash theme={"system"}
vetta session events $SID --include-accepted --json | jq '.data[] | select(.type | startswith("outcome."))'
```

> [!NOTE]
>
> **Money.** `--budget-usd` takes a decimal-dollar string and is converted client-side to integer micro-USD (the wire field is `cap_micro_usd`; `1 USD = 1_000_000` micro-USD). JSON amounts are integer `*_micro_usd`.

## interrupt, steer & queue

A running session ignores a plain `send` (it returns `session_running`). Steer it in one call with `--interrupt`, interrupt on its own, or hold the words for the next turn with `--queue`:

```bash theme={"system"}
vetta session send --session $SID --interrupt --message "Stop — escalate to a human instead."
vetta session interrupt --session $SID     # no new message; stops at the next commit boundary
vetta session send --session $SID --queue --message "When you're done, also check the refund log."
```

`--queue` is `queue: true` on the wire: the message waits in the session's inbox and becomes the input of the turn that follows the one running; on an idle session it is a plain send. `--interrupt` and `--queue` together are refused (`validation_failed`).

## The inbox: what is waiting on you

A session that has stopped and is waiting on a person is `idle`, exactly like one that finished its
work — `status` cannot tell them apart. `stop_reason` can, so it is a filter:

```bash theme={"system"}
vetta session list --stop-reason awaiting_approval --human
vetta session list --stop-reason awaiting_answer --json | jq -r '.data[].id'
```

`vetta session inbox` asks that question for every reason a person can clear —
`awaiting_answer`, `awaiting_approval` and `budget_paused` — and prints the id, the `tool_call` to
quote back, and one line saying what each session wants:

```bash theme={"system"}
vetta session inbox --human
```

```
id                            agent_id                      stop_reason       tool_call  waiting_on
ses_01j…                      agt_01j…                      awaiting_answer   ask_01j…   Which mailbox should the crew send from?
ses_01k…                      agt_01j…                      awaiting_approval tc_9f…     bash
```

`awaiting_delegation` is deliberately absent: a coordinator waiting on its own threads is blocked on
work, not on you. `inbox` pages one reason at a time: with `--stop-reason`, pass the reply's
`next_cursor` back as `--after` for the next page. Across all three reasons there is no single cursor:
`next_cursor` is `null`, and `--after` without `--stop-reason` is refused.

## confirm & tool-result

When the agent pauses on a guarded tool, the session goes `idle` with `stop_reason: awaiting_approval` and a `tool.confirm` event. Resolve it:

```bash theme={"system"}
vetta session confirm --session $SID --tool-call <id> --allow
vetta session confirm --session $SID --tool-call <id> --deny --reason "over policy limit"
```

Setting an agent up means approving the same tool several times with different arguments, one turn
apart each — the id being approved is derived from the call, so a second `identities_create` is a
second card. `--for-session` answers it once and grants that **tool** for the rest of the chat:

```bash theme={"system"}
vetta session confirm --session $SID --tool-call <id> --allow --for-session
```

It covers one tool name in one session and nothing else. It ends when the session does, is never
written onto the agent, and needs `--allow` — there is no session-wide deny. For a call through the
tool invoker (`tools_execute`) the tool granted is the one in its `tool` argument, not the invoker.

## answer a parked question

An agent that needs something from you parks the turn: the session goes `idle` with
`stop_reason: awaiting_answer` and carries the question in `pending_actions`. `confirm` cannot
resolve it — that route says only allow or deny, and "allow" is not an answer to "which mailbox?".

At a terminal, `vetta session answer` prints the question and asks for each field in turn:

```bash theme={"system"}
vetta session answer $SID
```

```
Which mailbox should the crew send from?
Mailbox
  e.g. hello@acme.com
> hello@acme.com
Tone
  1) formal
  2) warm
  or type anything else
> 2
```

A number picks an option; anything else is taken as typed, which is how you say the thing the agent
did not think of.

Under a script — or any redirected stdin — there is nobody to ask, so a prompt would hang forever.
Pass the whole answer instead, one flag per field; repeat a key to send several values:

```bash theme={"system"}
vetta session answer $SID --answer mailbox=hello@acme.com --answer tone=warm
vetta session answer $SID --tool-call ask_01j… --answer topics=pricing --answer topics=hiring
```

`--tool-call` is only needed when a session holds more than one parked question.

## run exit codes

`vetta session run` (and the top-level [`vetta run`](https://vetta.sh/docs/cli/overview#convenience-run)) block until the session goes idle/terminal, then set the process exit code from the terminal `stop_reason` so scripts and CI can branch. Idle is **not** inherently success — the exit code reflects `stop_reason`:

| `stop_reason` | Exit code |
| - | - |
| `end_turn` | `0` |
| `error` | `7` |
| `awaiting_input` | `3` |
| `awaiting_approval` | `4` |
| `budget_paused` | `5` |
| `interrupted` | `6` |
| `max_iterations` | `8` |
| `context_exhausted` | `9` |
| `awaiting_delegation` | `10` |
| `awaiting_answer` | `11` |

A session that never reported why it stopped exits `1`, and a bad command line exits `2`.

```bash theme={"system"}
vetta run --agent agt_01j8rf6tq2m4vz9xkp3n7c5hwd --message "Refund order #4821" || echo "stopped: exit $?"
```

## usage

```bash theme={"system"}
vetta session usage --session $SID --human
```

```json theme={"system"}
{
  "session_id": "ses_01H...",
  "consumed_micro_usd": 184200,
  "token_usage": { "input": 8120, "cache_write": 512, "cache_read": 4096, "output": 1340, "reasoning": 900 },
  "active_seconds": 37,
  "tool_calls": 4
}
```

## Changing tools mid-session

> [!WARNING]
>
> **Not available.** There is no `vetta session update` command — a session's tool set is fixed at creation from the agent's configuration. To change it, update the agent (which creates a new version) and start a new session.

## budget

```bash theme={"system"}
vetta session budget --session $SID --usd 5.00    # raise; must exceed what is already consumed
```

| Flag | Description |
| - | - |
| `--session` | Session id (required). |
| `--usd` | New cap as a decimal-dollar string (required). |

There is no `--remove`: a session always carries a cap. Raise it, or let the session stop at `budget_paused`.

## cancel

```bash theme={"system"}
vetta session cancel --session $SID
```

Stops a running session. It takes `--session` and no other flag.

> [!WARNING]
>
> There is no `vetta session archive` and no `vetta session delete`. Unknown commands are a hard error, so either one exits `2` without touching the session.

> [!NOTE]
>
> Files a session produced in its sandbox are not durable unless the agent promoted them with `publish_file`. List what a run published with [`vetta file list --session $SID`](https://vetta.sh/docs/cli/files#what-a-run-produced) — there is no `vetta session files`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.