GVNR
Most advice on this is a list of dashboards to watch. Watching is not stopping. This is about the controls that actually refuse an action, in the order they are worth adding, and what each one misses.
You can do the first four with no tool at all, and most of the value is there. The last two need something sitting in front of the agent.
It is free, it needs no code, and it is the only control that works when everything else you build has a bug in it. Anthropic ships usage limits at organisation, workspace and member level; OpenAI has hard and soft monthly caps in billing. Claude Code takes a per-session ceiling directly:
claude --max-budget-usd 5
Where it fails: a monthly cap is a cliff, not a brake. You find out you were wrong at the end of the month, and by then the money is gone. It also cannot tell a useful $200 from a wasted $200.
Token counts are the wrong unit. They are not comparable across models, and a cached session re-reads its whole context every turn, so raw token sums balloon into the billions while costing very little.
Weight by price instead. One effective token is one input-token of cost at that model's price, so output at roughly 5x input, cache writes at about 1.25x, cache reads at about 0.1x. Then a dollar cap converts with a single multiply, and $20 means $20 whether the agent is on a frontier model or a small one.
Where it fails: a per-session cap is still a total. An agent that burns the lot in ninety seconds and an agent that works all afternoon look identical to it.
This is the one almost nobody ships, and it is where the money actually goes. A total only notices once it is spent. A rate notices while it is happening.
Three rates are worth watching, and you can compute all of them from a sliding window of request outcomes:
| Signal | What it catches | Sane starting point |
|---|---|---|
| Dollars per minute, per agent | A single agent that has gone wrong | Ordinary work sits around $0.10 to $0.25 a minute, so $2 leaves normal sessions alone |
| Dollars per minute, across the fleet | Many agents each looking individually fine | $10 |
| New agents per minute | An orchestrator spawning orchestrators. A team that starts over an hour is a choice; eight inside a minute is a bug | 8 |
| Errors per minute | A retry storm. A rate-limited call fails cheaply, the retry after it does not | 6 |
Gate on the derivative, not the total. In pseudocode, that is the whole idea:
window = requests in the last 60s
spend_per_min = sum(cost(r) for r in window)
errors_per_min = count(r for r in window if r.failed)
new_agents = count(distinct new agent ids in window)
if spend_per_min > burn_limit: ask the human
if errors_per_min > retry_limit: ask the human
if new_agents > fanout_limit: ask the human
Make it ask once, not block. An overnight run that dies at 2am has cost you the night. One that pauses and waits has cost you nothing.
Repeated work is cheap per call and expensive in aggregate. Hash the action and its arguments, keep a short streak counter per agent, and treat a streak past three or four as a loop rather than progress. This is behaviour, not cost, so it fires before the budget notices.
Here is the part a spend cap structurally cannot do. The actions that hurt most are nearly free:
curl https://… | sh costs nothing and can own the machine.rm -rf costs nothing..env, id_rsa or .aws/ costs nothing.git push --force, npm publish, terraform apply: all cheap, all hard to undo.A budget check will wave every one of those through on a full budget. You need a separate check that runs on capability regardless of spend, with three outcomes rather than two: refuse the reckless ones outright, and make the irreversible ones stop and ask.
Where the agent supports it, do this before the tool runs rather than at the API. Claude Code exposes a PreToolUse hook for exactly this, and a refused action there never executes at all.
Be honest about the limit: pattern rules are a guard, not a sandbox. Published research found most open-source agent guards could be defeated by shell obfuscation. If your threat model is an adversary rather than an accident, the answer is process or container isolation with no credentials in reach, and a pattern guard on top of it.
Once an agent acts for a person, "what did it do" becomes a question someone else asks you. A log is not enough, because anyone with write access can revise it. Chain each record to the one before it so an edit visibly breaks the chain, and record the fields an audit actually wants: the human it acted for, the tool, the model that answered, and the rule that decided.
GVNR is the six controls above in one local process, free and self-hosted. Full disclosure: we make it.
npx --yes enforcer-governor start
Point an agent at it with OPENAI_BASE_URL or ANTHROPIC_BASE_URL, or install the Claude Code hook with npx --yes enforcer-governor install-hook. It runs on your machine and sends nothing to us. The quickstart takes about a minute, and how it compares is honest about the three cases where a gateway or a provider cap is the better answer.
Nothing above requires it. Points 1 to 4 are worth doing this afternoon whatever you use.