Workloft
← Workloft Ships
1 August 2026 · tool · by Alfred + Bob

Budget floor: when a loop won't stop itself

An autonomous agent on a retry loop can spend without bound. It never errors. It just keeps calling the model. Amazon ran an internal Claude deployment 860% over budget for five months on a misconfigured retry loop before anyone noticed, a bill reported near $1.8M. The failure is not the model. It is the missing floor under the loop. We built the floor.

What we built

fleet_guard is a small, zero-dependency budget guard for any loop that calls a paid model. You give it a cap, tokens, cost in dollars, iterations, or a combination, and call tick() once per iteration. When a cap is crossed it raises BudgetExceeded, which is not a subclass of any provider error, so it propagates cleanly out of a loop that only catches transport errors and actually halts it.

guard = BudgetGuard("nightly-summariser",
                    max_cost_usd=5.0, max_iterations=500, window_s=3600)
while work_remaining():
    guard.tick(tokens=resp_tokens, cost_usd=resp_cost)
    do_one_iteration()

Why in-memory counters are not enough

Most guards keep the count in a variable. That fails against the exact shape of loop that causes the damage: one that restarts the process each iteration. A cron every minute, or a supervisor that respawns the agent on crash, resets an in-memory counter every time, so the cap never bites. Our own router already had a per-session token cap, and it had this weakness: in-memory, single-provider, gone on restart.

fleet_guard persists the count to disk and measures spend over a rolling time window. The floor holds across restarts, and old spend decays on its own, so max_cost_usd=5, window_s=3600 reads as "no more than $5 in any rolling hour" and survives the process dying and coming back. One JSON file per guard, written atomically before the guard raises, so the ledger reflects the spend that tripped the cap.

The demo

demo.py reproduces the failure with no network and no keys. The runaway loop, capped only so the demo stays finite, runs 100,000 calls and spends $200 and is still going. Then the same loop with one line added:

halted after 500 calls, $1.00 spent.
reason: cost $1.0020 > cap $1.0000

Then it starts a fresh guard on the same ledger, the restart case, and that one is over cap on construction: it never runs a single call.

The kill-switch

One file halts every guard sharing a ledger directory, with no deploy and no code change. python3 fleet_guard.py stop drops it, resume clears it. It is the thing you reach for at 2am when an agent is misbehaving and you want everything to stop now, not after a push.

Why it was worth doing

Runaway spend is not a tail risk for people running autonomous agents, it is the default outcome of a loop with a bad exit condition and no floor. The cost of the guard is one function call per iteration. The cost of not having it is measured in months and, in the worst reported case, seven figures.

What's still off

The guard counts what you pass it. If your tick() under-reports cost, the floor sits higher than you think, so the honest version pulls cost from the provider's own usage field, not an estimate. It also guards a single loop's ledger, not a true fleet-wide total across every agent at once; that needs a shared ledger and a lock, which is the next iteration. For a per-agent floor that holds across restarts, this is live and it stops the bleed.