docs blog library
github

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:

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

CapDefaultCounts
maxIterations100Reason-and-act cycles in a top-level run
maxCostUSDunsetModel spend in dollars, own run plus everything it delegated
maxTokensunsetPrompt plus completion tokens, own run only, not children
maxDurationMsunsetWall-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:

// ~/.jazz/config.json: every run on this machine
{ "maxIterations": 60, "maxCostUSD": 2.0 }
# a workflow's frontmatter: this workflow, every time it runs
maxIterations: 40
maxCostUSD: 1.00
maxDurationMs: 900000
# one run
jazz run --agent analyst --max-cost-usd 0.50 --max-duration-ms 300000 "Summarize report.md"

Watching from the terminal

/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

{
  "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:

{ "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.

{
  "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 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.

machine-readable: /docs/concepts/budgets.md · /llms.txt · /llms-full.txt