|
| 1 | +--- |
| 2 | +title: "Budget" |
| 3 | +description: "Cap what a single run may spend in money, tokens, or wall-clock time." |
| 4 | +keywords: docker agent, ai agents, configuration, yaml, budget, cost, limits |
| 5 | +weight: 75 |
| 6 | +canonical: https://docs.docker.com/ai/docker-agent/configuration/budget/ |
| 7 | +--- |
| 8 | + |
| 9 | +_Cap what a single run may spend in money, tokens, or wall-clock time._ |
| 10 | + |
| 11 | +## Overview |
| 12 | + |
| 13 | +A budget sets ceilings on a run. When a ceiling is crossed the run stops with a message naming the exact limit that tripped, and the TUI tracks consumption live while the run is still going. |
| 14 | + |
| 15 | +Every limit is optional and an unset limit is unlimited, so you can cap money, tokens, time, or any combination. Declare no budget at all and runs are unbudgeted, which is the default. |
| 16 | + |
| 17 | +There are two ways to declare one, and they compose: |
| 18 | + |
| 19 | +| Block | Scope | |
| 20 | +| --- | --- | |
| 21 | +| `budget` | One run-wide ceiling, charged for every agent. | |
| 22 | +| `budgets` | Named budgets an agent opts into by name. | |
| 23 | + |
| 24 | +### A run-wide budget |
| 25 | + |
| 26 | +```yaml |
| 27 | +agents: |
| 28 | + root: |
| 29 | + model: openai/gpt-4o-mini |
| 30 | + description: An agent on a short leash. |
| 31 | + instruction: You are a helpful assistant. |
| 32 | + |
| 33 | +budget: |
| 34 | + max_cost: 0.50 |
| 35 | + max_tokens: 100000 |
| 36 | + max_time: 10m |
| 37 | +``` |
| 38 | +
|
| 39 | +| Field | Type | Description | |
| 40 | +| --- | --- | --- | |
| 41 | +| `max_cost` | number | Maximum spend, in USD. | |
| 42 | +| `max_tokens` | integer | Maximum cumulative input+output tokens. | |
| 43 | +| `max_time` | string | Maximum time the agents spend working, in Go duration format (`10m`, `30s`, `1h30m`). | |
| 44 | + |
| 45 | +### Named budgets |
| 46 | + |
| 47 | +Define budgets by name under the top-level `budgets` key, then have each agent opt in by listing names in its own `budgets` field. The fields are the same three. |
| 48 | + |
| 49 | +```yaml |
| 50 | +budgets: |
| 51 | + shell-work: |
| 52 | + max_cost: 0.03 |
| 53 | + max_tokens: 8000 |
| 54 | + research: |
| 55 | + max_time: 1m |
| 56 | +
|
| 57 | +agents: |
| 58 | + root: |
| 59 | + model: openai/gpt-4o-mini |
| 60 | + description: Does shell work. |
| 61 | + instruction: You are a helpful assistant. |
| 62 | + budgets: [shell-work] |
| 63 | + researcher: |
| 64 | + model: openai/gpt-4o-mini |
| 65 | + description: Answers questions. |
| 66 | + instruction: You answer questions concisely. |
| 67 | + budgets: [shell-work, research] |
| 68 | +``` |
| 69 | + |
| 70 | +An agent may list several budgets; all of them apply, and the first to be exhausted stops the run. A run-wide `budget` applies on top of any named budget, so the ceiling that binds is whichever runs out first. |
| 71 | + |
| 72 | +Referencing a budget name that isn't defined is a config error, caught at parse time rather than silently leaving the agent uncapped. |
| 73 | + |
| 74 | +## A name is one shared pot |
| 75 | + |
| 76 | +When several agents reference the same budget name they draw from the **same** ceiling — not a copy each. Above, `root` and `researcher` share `shell-work`: together they cannot spend more than `$0.03`. |
| 77 | + |
| 78 | +This is deliberate, and it is the whole reason budgets are worth having. If each agent received its own allowance, a run could spend `max_cost` × N simply by fanning out to N sub-agents, and the ceiling would mean nothing for exactly the workloads that most need one. |
| 79 | + |
| 80 | +Give agents **distinct budget names** when you want independent pots. |
| 81 | + |
| 82 | +The same applies to the run-wide `budget`: every sub-session inside a run (transferred tasks, sub-agents, skills) spends from that one wallet. |
| 83 | + |
| 84 | +## Scope: a budget spans the session |
| 85 | + |
| 86 | +Spend accumulates for the life of the **session**, across every message you send — it does not reset each time you hit enter. A `max_cost: 0.50` you could re-spend on every message would not be a ceiling at all. |
| 87 | + |
| 88 | +Starting a new session starts a fresh budget. It is a per-session ceiling, not a lifetime quota across sessions. |
| 89 | + |
| 90 | +> [!NOTE] |
| 91 | +> `max_time` measures the time the agents actually spend **working** — the sum of their turn durations — not wall-clock since the session opened. Because a budget spans a session, and a session sits idle while you read and type, wall-clock would let a budget expire during a coffee break: leave the TUI open for ten minutes and your next message would instantly trip a `max_time` of `2m` without the agent having done anything. |
| 92 | + |
| 93 | +## What stops a run |
| 94 | + |
| 95 | +Crossing any limit — run-wide or named — stops the run and produces: |
| 96 | + |
| 97 | +- an assistant message in the transcript naming the limit and the amounts, |
| 98 | +- a `budget_exceeded` event carrying `budget`, `limit`, `used`, `max` and `config_path`, |
| 99 | +- a `notification` hook at `warning` level, |
| 100 | +- a stream end reason of `budget_exceeded`, so a stopped run is distinguishable from a completed one in telemetry. |
| 101 | + |
| 102 | +The message names the exact YAML path to raise, so there is no ambiguity about which of several budgets tripped: |
| 103 | + |
| 104 | +```text |
| 105 | +Execution stopped after reaching the configured budgets.shell-work.max_cost |
| 106 | +limit (used $0.0312 of $0.0300). |
| 107 | +``` |
| 108 | + |
| 109 | +Unlike [`max_iterations`](../agents/index.md), a budget stop is **terminal** — there is no prompt offering to continue. A budget is a ceiling you set deliberately, so raising it means editing the config rather than answering a dialog. |
| 110 | + |
| 111 | +## Tracking spend in the TUI |
| 112 | + |
| 113 | +The sidebar's Token Usage panel lists every active budget by name, with consumption against each ceiling it declares. Where more than one agent draws on a budget, it breaks the total down per agent — biggest spender first — with that agent's cost, tokens, and active time: |
| 114 | + |
| 115 | +```text |
| 116 | +run $0.12/$0.50 · 12.3K/100.0K · 2m14s/10m |
| 117 | + developer $0.09 · 8.0K · 1m12s |
| 118 | + root $0.03 · 4.3K · 1m02s |
| 119 | +shell-work $0.09/$0.10 · 4.3K/20.0K |
| 120 | + developer $0.09 · 4.3K · 1m12s |
| 121 | +``` |
| 122 | + |
| 123 | +Only the ceilings you configured appear, and a budget drawn on by a single agent omits the breakdown. Each reading warns once it passes 80% of its limit, so a run about to be stopped is visible before it stops. |
| 124 | + |
| 125 | +## Limits and caveats |
| 126 | + |
| 127 | +### Unpriced models do not count towards `max_cost` |
| 128 | + |
| 129 | +Only responses the runtime can price count towards `max_cost`. A model with no pricing data — an unknown model ID, or a custom endpoint such as a local or private deployment — contributes nothing, because there is no honest number to add. |
| 130 | + |
| 131 | +Such a run emits a warning and the TUI marks the reading `(unpriced spend)`, rather than silently reading low because the spend is invisible. To make a custom endpoint count, price it explicitly with a model-level [`cost`](../models/index.md#custom-token-pricing) block: |
| 132 | + |
| 133 | +```yaml |
| 134 | +models: |
| 135 | + local: |
| 136 | + provider: openai |
| 137 | + model: my-model |
| 138 | + base_url: http://localhost:8000/v1 |
| 139 | + cost: |
| 140 | + input: 0.15 |
| 141 | + output: 0.60 |
| 142 | +
|
| 143 | +agents: |
| 144 | + root: |
| 145 | + model: local |
| 146 | + description: A locally-served agent with real cost accounting. |
| 147 | + instruction: You are a helpful assistant. |
| 148 | +
|
| 149 | +budget: |
| 150 | + max_cost: 0.50 |
| 151 | +``` |
| 152 | + |
| 153 | +### Limits are checked at turn boundaries |
| 154 | + |
| 155 | +A run is checked between turns, so it can overshoot by at most the turn already in flight. `max_time` in particular will not interrupt a model call or tool that has already started; the run stops at the first boundary after the limit is reached. |
| 156 | + |
| 157 | +This is the same granularity [`max_iterations`](../agents/index.md) has, and it keeps the ceiling out of the streaming hot path. Set limits with a little headroom rather than at the exact number you cannot exceed. |
| 158 | + |
| 159 | +### `max_tokens` here is not the model's `max_tokens` |
| 160 | + |
| 161 | +The `max_tokens` in a budget is a **cumulative** count of input+output tokens across the whole run. It is unrelated to the provider- or model-level [`max_tokens`](../models/index.md), which caps the output of a single response. |
| 162 | + |
| 163 | +It is also not the session's context length: compaction resets that, while the budget keeps counting. |
| 164 | + |
| 165 | +## Examples |
| 166 | + |
| 167 | +Cap money only, and let the run take as long as it needs: |
| 168 | + |
| 169 | +```yaml |
| 170 | +agents: |
| 171 | + root: |
| 172 | + model: openai/gpt-4o |
| 173 | + description: A cost-capped agent. |
| 174 | + instruction: You are a helpful assistant. |
| 175 | +
|
| 176 | +budget: |
| 177 | + max_cost: 5.00 |
| 178 | +``` |
| 179 | + |
| 180 | +Cap wall-clock time for an unattended job: |
| 181 | + |
| 182 | +```yaml |
| 183 | +agents: |
| 184 | + root: |
| 185 | + model: openai/gpt-4o-mini |
| 186 | + description: A time-boxed agent. |
| 187 | + instruction: You are a helpful assistant. |
| 188 | + toolsets: |
| 189 | + - type: shell |
| 190 | +
|
| 191 | +budget: |
| 192 | + max_time: 15m |
| 193 | +``` |
| 194 | + |
| 195 | +See [`examples/budget.yaml`](https://github.com/docker/docker-agent/blob/main/examples/budget.yaml) for a runnable configuration. |
0 commit comments