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.jsonl and 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 sync records one ledger entry per Task call using a configurable estimate (default 47,117 — the measured median). Use record --tokens with exact figures from --output-format json when it matters.
  • Dollars are estimates from a price table, not your invoice. Override model_rates or pass --cost for 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.