How-to guides / Budgets and limits
Start here
How-to guides
How-to guides
Budgets and limits
Budgets stop an agent from spending more than you meant it to. They are set in
x-agen/config.json (or per deployment with UpdateDeployment):
{
"budget": { "maxTokensPerRun": 50000, "maxUsdPerRun": 0.10, "maxUsdPerDay": 5 }
}
| Budget | Enforced by | What happens |
|---|---|---|
maxTokensPerRun |
the engine | Once the run’s input + output tokens reach the limit, it stops and reports (see below). |
maxUsdPerRun |
the engine | The same, by cost. Needs a provider that reports cost (OpenRouter does; direct OpenAI does not). |
maxUsdPerDay |
the Hub | Once today’s (UTC) spend of the deployment reaches it, no new work starts until the next UTC day: no task leases, no wake-ups, no scale-up (callers get 503 with the reset time). Runs already in flight finish. |
How close the limits are
- Before each model call, the output limit (
max_tokens) is lowered to what is left ofmaxTokensPerRun, so a single answer cannot jump far past it. This applies tomaxOutputTokens(8192 by default for bundles). An SDK agent defined in code withoutmaxOutputTokenssends the remaining budget only once it is below 8192 tokens, because some providers reject or pre-charge large limits. - The input of the next call still counts, so a run can end slightly over
maxTokensPerRun. KeepmaxOutputTokensmodest for tight budgets. maxUsdPerDayis checked when work starts, so the day’s spend can overshoot by the runs already in flight (at mostmaxUsdPerRun× concurrency).
Stopping at a limit
A run that reaches maxTurns, maxRunDuration, maxTokensPerRun or
maxUsdPerRun, or keeps repeating itself (stuckRepeats), is not cut off
empty-handed. It gets one more model call,
without tools and with at most limits.reportTokens (default 1024) output
tokens, asking it to report what it did, what it found and what is left. The
run then ends succeeded with the outcome partial and a reason
(max_turns, duration, budget or stuck), and the report is its output. That
last call can take a run slightly past a token or cost budget (by its input
plus reportTokens).
Set reportTokens to 0 to have runs fail at a limit instead, with outcome
failed and the same reason.
The Hub records a budget.threshold event when a deployment
has spent 50, 80 and 100% of maxUsdPerDay, each once per UTC day, so a
notification target can hear about it.
Budget pressure
Once a deployment has spent 80% of its maxUsdPerDay, the tasks it leases
carry budget_pressure. An agent on a routing model
then runs at its router.budgetTier (default low), or lower if the task
asked for less, so the rest of the day’s budget goes further. Other models are
not affected.
The console’s Overview warns when a daily budget is 80% spent and when it is used up, and a task’s details show its tier and whether it ran under budget pressure.
Seeing spend
Each run records its tokens and cost: agen logs <name> prints them per run,
ListRuns returns them, and the web UI shows them per deployment. agen ps
marks a deployment whose daily budget is used up. The console’s Costs page
also breaks calls down by the model that served them, with fallbacks,
latency, tokens and cost (GetMetrics models).
Limits
Limits stop a run that goes wrong (a loop, a hung tool, a runaway
delegation) even without a budget. Every limit has a default; set one to 0
to turn it off.
{
"limits": { "maxRunDuration": "2h", "maxIdenticalToolCalls": 10, "maxQueuedTasks": 5000 }
}
| Limit | Where | Default | What happens |
|---|---|---|---|
maxTurns |
x-agen/agent.md |
16 | Model calls per run; past it the run stops and reports. |
maxOutputTokens |
x-agen/harness.json |
8192 | The most one model answer may produce. |
maxRunDuration |
limits |
1h |
Working time of a run, not counting approval waits; past it the run stops and reports. |
reportTokens |
limits |
1024 | Output limit of the report call at a limit; 0: no report, the run fails. |
maxIdenticalToolCalls |
limits |
5 | The same tool with the same arguments in one run; further identical calls are refused and the model is told to change course. A call that failed 3 times in a row with the same error is refused the same way. |
stuckRepeats |
limits |
4 | Turns in a row with the same calls and the same results count as stuck: the run is told once to change approach, and if it goes on repeating it stops and reports with reason stuck. |
modelRequestTimeout |
limits |
10m |
One model request; it fails past it. |
toolTimeout |
limits |
10m |
One tool call (not call_agent, which the callee’s limits bound); the model gets a timeout error. |
maxQueuedTasks |
limits |
1000 | Queued tasks per deployment; more are refused (RESOURCE_EXHAUSTED, webhooks get 429). |
maxDelegationDepth, maxFanOut, maxTotalDelegations |
limits |
3, 20, 50 | See Connecting agents. |
approvalTimeout |
permissions |
1h |
How long an ask waits; at most 168h. |
A deployment’s page in the console shows where it stands against its spend and queue limits.