How to set a hard spending limit on an AI agent
· By the Shotoku team
Short answer:check the budget in code before every paid call, and refuse the call when it would go over. Use two limits: a cap per call for one expensive request, and a rolling daily cap for loops of cheap ones. Billing alerts and instructions in a prompt don’t do this, because neither one blocks the next call.
Why don’t alerts and prompts stop overspending?
| Method | Blocks the next call? | The problem |
|---|---|---|
| Rule in the prompt | No | The model can misread it, ignore it or be talked out of it |
| Billing alert | No | It tells you after the money is spent |
| Provider spend cap | Sometimes | Coverage varies by provider, and it usually applies to a whole project, not one agent |
| Check in code before the call | Yes | You have to route every paid call through it |
Even a budget setting may only be an alert. GitHub’s Copilot budgets, for example, stop usage only if you turn that option on.
A loop of small calls is the case to plan for. Each call looks harmless, so a per-call cap never fires. One widely repeated story describes agents looping for 11 days and running up a $47,000 bill. We couldn’t trace it to a primary source, but the failure it describes is real: no limit sat in front of the next call.
How do you add a hard limit?
Install Shotoku and create a policy:
Set a limit per call and per day for each vendor. Anything you haven’t listed waits for a human:
Then check before each paid call:
What happens when an agent hits the limit?
We ran this policy on the current npm release, with an agent looping on $1.50 calls:
| Request | Result |
|---|---|
| Six calls at $1.50 | approved, $9 spent |
| Seventh call at $1.50 | denied: $10.50 would exceed the $10 daily limit |
| One call at $3 | denied: over the $2 limit |
| $0.10 to a vendor not in the policy | pending_approval: waits for a human |
| Any call with the policy file missing | denied |
The last row matters most. If something goes wrong with the policy, the agent is refused rather than waved through. The check is deterministic too: the same request, policy and history always give the same answer, with no model involved.
What are the limits of this approach?
- You supply the amount. Shotoku doesn’t meter tokens or read invoices. Pass a realistic upper bound for each call, because a low estimate means a low count.
- Only checked calls count. If code can reach the API without the check, the budget can’t see it. For MCP tools, wrapping the server closes that route.
- Daily limits here are per rule. A single daily budget per agent across all vendors is in the repo but not yet in the npm release.
Common questions
What should a daily limit be set to?
Start from what a normal day costs and leave some headroom. Too tight and a good run gets blocked. Too loose and a loop runs for longer. Check your history after a week and adjust.
Should an over-limit call fail or wait for a human?
For a background agent, failing is usually right, because nobody is there to answer. If a person is available and the work matters, route it for approval instead. See the refund example.
Does this send my spending data anywhere?
No. The policy and the decision record are local files, and Shotoku holds no funds or keys. It makes the decision and your code makes the payment.
Next, try the quickstart or read the policy reference.