# Budgets

Budgets limit how much work an agent can do in one run. Use them for scripts, reviews,
and scheduled jobs to control time and model spend.

For example, give a review five minutes and a fifty-cent cost budget:

```bash
jazz run --agent reviewer --max-cost-usd 0.50 --max-duration-ms 300000 \
  "Review the current changes and report concrete issues. Do not modify files."
```

Cost caps are checked between model calls, so the final call can take the total past the cap.
The duration cap interrupts work at its deadline.

## Per-run limits

| Cap             | Default | Counts                                                           |
| --------------- | ------: | ---------------------------------------------------------------- |
| `maxIterations` |   `100` | Reason-and-act cycles in a top-level run                         |
| `maxCostUSD`    |   unset | Model spend in dollars, **own run plus everything it delegated** |
| `maxTokens`     |   unset | Prompt plus completion tokens, **own run only, not children**    |
| `maxDurationMs` |   unset | Wall-clock time                                                  |

Use a cost cap to bound delegation spend. Token caps work without pricing data.

Three more shape delegation itself: `maxSubagentIterations` (30), `maxLiveSubagents` (10), and
`maxSubagentDepth` (3), where `0` disables delegation outright.

## What the cost includes

`costUSD`, and the `maxCostUSD` cap, count every model call the run paid for:

- its own turns, with prompt-cache reads at the cache-read rate and cache writes at the
  cache-write rate;
- every sub-agent it spawned, including one that failed or was stopped (in chat, a sub-agent
  still working when the turn ends is recorded in the spend ledger under that turn once it
  finishes);
- the calls it makes for itself: compaction summaries, memory extraction before compaction,
  and the command-risk classifier.

A sub-agent runs under what its parent has left: the remaining time, the remaining
`maxCostUSD` (while the parent's spend is fully priced) and the remaining `maxTokens`. Once
any of them is used up, the parent is told to finish with what it has instead of delegating.
Sub-agents running at the same time share that remainder: each reports its spend after every
step, and both the parent's and every child's cost check count what the others have spent so far,
so together they stop at the parent's `maxCostUSD`. `maxTokens` is still counted per run: each
child gets the parent's remaining tokens. A parent can tighten a child's time (`maxMinutes`), cost
(`maxCostUSD`) and output (`maxOutputTokens`, the tokens the child writes, reasoning included)
when it spawns it. It can't set the child's `maxTokens`: that cap counts every request's whole
prompt, so a child's first step alone can use most of a small figure.

## Where to set them

Three places, narrowest wins:

```jsonc
// ~/.jazz/config.json: every run on this machine
{ "maxIterations": 60, "maxCostUSD": 2.0 }
```

```yaml
# a workflow's frontmatter: this workflow, every time it runs
maxIterations: 40
maxCostUSD: 1.00
maxDurationMs: 900000
```

```bash
# one run
jazz run --agent analyst --max-cost-usd 0.50 --max-duration-ms 300000 "Summarize report.md"
```

## Watching from the terminal

```text
/cost     tokens and USD for this conversation, sub-agents included
/limit    set a turn, cost, or token cap on this session, applied immediately
```

`/limit usd 5` caps the session at five dollars and tells you straight away if you are already
past it. `/limit clear` removes it. The cap gates the next turn rather than killing the current
one, so you get asked to confirm rather than losing work in flight.

## Watching from a script

```json
{
  "ok": true,
  "answer": "…",
  "costUSD": 0.0041,
  "costKnown": true,
  "tokenUsage": { "promptTokens": 1204, "completionTokens": 6, "totalTokens": 1210 }
}
```

A failed envelope still carries `costUSD`, `costKnown` and `tokenUsage`. A run
killed from outside leaves no envelope; `--watch spend` streams `run_spend` events with the
running total so the caller can use the last one. The chat bridges do exactly that: their daily
spend cap counts failed, timed-out and cancelled runs, not only answered ones.
`jazz workflow history <name>` shows the same figures per scheduled run, failed runs included.

## When a cap stops the run

`maxIterations`, `maxCostUSD` and `maxTokens` are checked between iterations, so one model call
or tool phase can cross them before the next iteration stops. Budget `--max-cost-usd` with that
in mind.

`maxDurationMs` is a deadline. Work stops at 85% of it: Jazz interrupts whatever is running (the
model call is aborted, a shell command is killed with every process it started, and a sub-agent
stops with it), and unfinished tool calls are closed with a note. The last 15% is for the answer.
The run returns with `durationCapped: true`. A sub-agent is given only the work time its parent
has left, so delegating work never extends the deadline.

`--timeout` is a harder wall around the whole run, including start-up. The run treats it like
`maxDurationMs`: work stops at 85% of it and the agent answers in the rest. If the run is still
going at the deadline, it ends as a failure, with the same cleanup. Time spent waiting for a
person to approve a tool pushes the deadline out.

Whatever stops the run (a budget, the iteration limit, or the agent repeating itself), Jazz makes
one more model call without tools. It asks the agent to answer from what it has gathered, mark
what it did not verify, and say what is left undone. A run that was mid-research hands back a
partial answer instead of nothing. A user interrupt (Esc) skips that call.

Jazz warns the agent at 50%, 80%, and 90% of its cost, token, and duration limits, and at
50%, 70% and 90% of its iteration limit. Warnings are not saved in conversation history.

## When the figure is unknown

A cost is known when the provider priced the call, or when the model genuinely costs nothing,
which means a self-hosted Ollama, llama.cpp, vLLM, or SGLang model. Anything else is unknown, and Jazz says so:

```json
{ "ok": true, "costUSD": 0, "costKnown": false }
```

When `costKnown` is false, `costUSD: 0` does not mean the run was free.

One unknown child makes the parent's total unknown too.

The same goes for cache writes: when the pricing data has no cache-write rate for the model,
they are priced at the plain input rate and the total is marked unknown, since providers such as
Anthropic charge more for them.

An Ollama model with a cloud tag uses remote billing and does not count as free.

A cost cap cannot be enforced against a model nobody has priced. That is the case `maxTokens`
exists for.

## Daily and monthly caps

The caps above bound one run. A goal that runs every ten minutes, or a workflow that fails and
retries, stays under every per-run cap while the bill grows. The `daemon` spend caps bound the
total: every run's final cost, failed and cancelled runs included, is recorded in one ledger
under `$JAZZ_HOME/spend`, and the caps count what **unattended** runs (nobody could be asked
while they ran) spent per local day and month. Your chat turns never count.

```jsonc
{
  "daemon": {
    "dailyCostUSD": 5,
    "dailyTokens": 2000000,
    "monthlyCostUSD": 60,
    "goals": { "dailyCostUSD": 2, "monthlyCostUSD": 20 },
    "agents": { "inbox": { "dailyCostUSD": 1 } },
  },
}
```

Every cap is unset, meaning unlimited, until you set one. `goals` covers goal cycles and loop
runs together; `agents.<agent>` covers one agent's unattended runs, keyed by its name (`inbox`
above) or its id, as `jazz agent list` shows them. `jazz config set` and `jazz spend` warn about
a key that names no agent. Set the goal caps and the machine-wide ones from `jazz` > `/settings` > **Spend limits**, or with `jazz config set daemon.goals.dailyCostUSD 2`.

When a cap is reached:

- **The daemon pauses** at a machine-wide daily cap (`dailyCostUSD`, `dailyTokens`) until local
  midnight, and tells your [notify targets](../configure/notifications.md) once.
  `jazz daemon resume` lifts the machine-wide daily caps for the rest of the day, whether or not
  a daemon was running; monthly, goal and agent caps stay in force.
- **Unattended runs it covers refuse to start**: `jazz run` (with or without `--events`),
  workflows, goal cycles, loop runs, wake triggers, job batches, webhooks, peers and daemon API
  runs. The refusal names the cap and the key to change, and your notify targets hear about it
  once per cap and window. Runs still going count at the average cost of this month's
  unattended runs until they finish, so several starting at once cannot all spend the same
  headroom.
- **Goals and loops wait** instead of failing: the check runs before each cycle, and the next
  one starts on its own when the day or month turns over or you raise the cap.
- **Chat is never stopped.** It warns once when a cap covering its agent is reached. A run
  answering a parked one (`jazz runs approve`) also proceeds.

An unpriced run adds nothing to a dollar cap's spend, so the priced spend a cap counts is a
floor, and a cap it reaches is reached. A daily dollar cap with an unpriced run in its scope
today cannot be verified, so it blocks as if reached until midnight (`jazz spend` marks it
BLOCKED); a monthly one counts priced spend and shows the unpriced runs beside it. Use a priced
model, or `dailyTokens` for a model nobody has priced.

`jazz spend` shows today, this month, unattended spend, the breakdown by agent and source, and
each cap. The chat bridges record their runs in the same ledger, and `JAZZ_DAILY_COST_CAP_USD`
caps one bridge's own runs.

## Related

- [Context management](./context-management.md): what happens as the context fills
- [Workflow frontmatter](../configure/workflows.md): the caps as workflow fields
- [Configuration](../configure/jazz.md#run-budgets): the defaults and the enforcement model
- [Headless](../surfaces/headless.md): the full JSON envelope
- [Notifications](../configure/notifications.md): hearing about a reached cap