My subagents were eating 48% of my tokens. So I gave them hard budget caps — enforced by hooks, not dashboards
A few weeks ago a measurement made the rounds: developer aidiveyt logged a
month of Claude Code usage — 455 sessions, 2,631 subagent runs — and found
subagents had consumed 48.1% of all tokens. The median subagent's first
request alone was 47,117 tokens. Nobody approved that spend. It just
happened, quietly, in the background, one Task call at a time.
Simon Willison's reaction was the whole community's reaction: "hard budget
caps, please, now."
I had the same problem and the same reaction. So I built
subagent-budget: per-agent-type token and dollar budgets that are
enforced by Claude Code hooks — an over-budget subagent is refused at
launch, with the reason shown to the agent. A dashboard that can't stop a
launch is a suggestion. This is a cap.
The core idea in 30 seconds
pip install subagent-budget subagent-budget init --default-tokens 1000000 --default-usd 50 subagent-budget set-budget --pattern "Explore*" --tokens 200000 --usd 10 subagent-budget sync # backfill from ~/.claude/projects transcripts subagent-budget report Then the enforcement part — one block in ~/.claude/settings.json:
{ "hooks": { "PreToolUse": [ { "matcher": "Task", "hooks": [{ "type": "command", "command": "subagent-budget hook --event pre" }] } ] } } Now every subagent launch goes through a budget check first. Under budget:
it launches, and the hook prints the remaining headroom. Over budget: exit
code 2 (Claude Code's blocking-hook signal), and Claude sees exactly why:
subagent-budget blocked launch of 'Explore auth code' (Explore): token budget exceeded: used 210,441 / 200,000 tokens That last part is the whole point. Prompt-level instructions ("please don't
spawn too many subagents") don't survive contact with an agent mid-task. A
hook that returns a non-zero exit sits below the prompt layer — the model
can't argue with it, negotiate with it, or forget it.
How it differs from subagent-ledger
There's already a tool in this space — subagent-ledger — and it's honest
about what it is: a display. It shows token counts, clears at session end,
and can't stop anything. subagent-budget is built on the opposite premise:
- Tokens + dollars, not tokens alone. Built-in model price tables (overridable in config) turn every record into an estimated cost, so a cap can be "$10 on research agents" instead of a token number you have to convert in your head.
- Cross-session ledger. Usage lives in
~/.config/subagent-budget/ledger.jsonland survives session ends. A budget that resets every session isn't a budget. - Hooks hard-block the launch. This is the difference between a meter and a circuit breaker.
Budget rules are globs matched against both the agent's description and its
subagent type, first match wins — so Explore* can have a tight shared pool
while everything else falls back to the default. Either dimension can be
left unlimited.
It plays nice with resume-budget-guard
If you already track spend across claude --resume with
resume-budget-guard,
the ledger formats are deliberately compatible (ts, kind, cost_usd
records). One command folds resume spend into the same caps:
subagent-budget import-rbg # imports ~/.resume-budget-guard/ledger.jsonl as agent "rbg:<session-key>" Imported spend counts toward the matching budget rules, so a resume can no
longer silently reset what a subagent cap was guarding. Idempotent — re-run
it anytime.
Honest limitations
- Transcript backfill is estimated. A parent transcript doesn't contain a subagent's own token usage, so
syncrecords one ledger entry per Task call using a configurable estimate (default 47,117 — the measured median). Userecord --tokenswith exact figures from--output-format jsonwhen it matters. - Dollars are estimates from a price table, not your invoice. Override
model_ratesor pass--costfor exact numbers. - It blocks what it sees. The pre-launch hook reads Claude Code's hook stdin; subagents spawned outside the Task tool need manual
record. - Enforcement is per-machine. A second laptop spends from a second ledger.
Stdlib only, zero dependencies, MIT. pip install subagent-budget —
GitHub ·
PyPI.