Budgets
Missions and tasks can declare spending limits in a budget block. When a limit is reached, the current task fails and the whole mission fails — in-flight commanders and agents unwind immediately.
Both a token cap and a dollar cap are supported. Either one alone is valid; the first limit reached wins.
mission "expensive_research" {
budget {
tokens = 5000000 # cumulative across every task
dollars = 25.00
}
task "crawl" {
budget { tokens = 500000 } # per-task cap
objective = "Crawl the target domain"
}
}Why both tokens and dollars?
Models without declared pricing — local models served via Ollama, self-hosted endpoints, anything Squadron doesn’t have rates for — always report $0 cost. That means a dollar-only budget cannot constrain them, no matter how many tokens they consume. If you run mixed fleets, always include a token cap as a safety net.
Conversely, a dollar-only budget is useful when you want one number that naturally scales across model choices: switching from a cheap model to an expensive one just means fewer tokens fit under the same cap.
Scope
Mission budget
Sums tokens and cost across every task in the mission — commanders, agents they spawn, every iteration of every iterated task. The first limit reached fails the mission.
Task budget
Sums across that task’s commander and every agent it spawns. Iteration suffixes are stripped — crawl[0], crawl[1], crawl[2] all contribute to the same crawl counter. That means a task-level budget caps the whole iterated task, not each iteration.
Validation
At least one of tokens or dollars must be set. Empty budget { } blocks are rejected at config load.
What happens when a budget trips
- The breach latches — subsequent usage checks return the same breach without double-counting.
- The mission-scoped context is canceled, so in-flight LLM calls and tool calls return promptly.
- A
mission_issueevent is emitted withseverity=fatal,category=budget_exceeded, and structured details (scope,kind,used,limit). - The task transitions to
failed(notstopped) with the breach message as its error. - The mission transitions to
failed.
Issues are purely advisory — authoritative failure still comes from the returned error — so the event and the mission status can never disagree.
Examples
Cap the whole mission in dollars, no per-task limits
mission "sweep" {
budget {
dollars = 2.00
}
# ... tasks ...
}Cap an expensive iteration but let the rest run free
mission "research" {
task "crawl_pages" {
iterator {
dataset = datasets.urls
parallel = true
}
budget {
tokens = 1000000 # the parallel fan-out is the risky part
}
objective = "Fetch and summarize ${item.url}"
}
task "summarize" {
depends_on = [tasks.crawl_pages]
objective = "Produce an executive summary"
}
}Belt-and-suspenders: cap dollars overall, tokens per expensive task
mission "thorough" {
budget {
dollars = 10.00 # hard spend ceiling regardless of model
}
task "deep_analysis" {
budget { tokens = 2000000 }
objective = "Analyze the full corpus"
}
}Zero overhead when unused
If neither the mission nor any task declares a budget, no tracker is created and no per-turn accounting happens.