One file. Zero dependencies. Stdlib only. Drop agent_guard.py next to your agent and
import it. No pip install, no account, no network calls.
This is the free subset of the Agent Ops toolkit: the five guards that stop an unattended agent from quietly burning money while it looks busy.
| # | Failure mode | What it costs you | Guard |
|---|---|---|---|
| 1 | Silent budget bleed — tiny "no-op" calls until the account is drained | the whole budget, invisibly | BudgetGuard (per-category caps) + RunLogger.no_op_rate() |
| 2 | Runaway loop — stuck retrying the same action forever | tokens × ∞ | LoopBreaker (repeat-signature + hard iteration cap) |
| 3 | Unbounded single call — one expensive call blows the month | the month | @guard decorator (pre-check + post-charge) |
| 4 | Escalation sprawl — agent pings the owner for everything, or acts on money itself | trust + real money | require_owner_action() (only payout|purchase|setup|other) |
| 5 | Invisible history — no record of what ran, what it cost, how it ended | you can't fix what you can't see | RunLogger (append-only JSONL) |
# just copy the file
cp agent_guard.py /your/project/Requires Python 3.8+. Nothing else.
from agent_guard import BudgetGuard, RunLogger, LoopBreaker, guard
budget = BudgetGuard("state/budget.json", caps={"llm": 5.0, "api": 2.0})
runs = RunLogger("state/run-log.jsonl")
@guard(budget, "llm", est_usd=0.05, logger=runs, agent="researcher")
def call_model(prompt: str) -> str:
# ... your real LLM call here ...
return "ok"
call_model("summarise this") # charged, logged as "shipped"
print(budget.remaining("llm")) # 4.951. Budget bleed — cap by category, not by total. A total cap hides which line is eating the budget.
budget = BudgetGuard("state/budget.json", caps={"llm": 5.0, "api": 2.0})
budget.charge("llm", 0.03, note="summarise") # raises BudgetExceeded past the cap2. Runaway loop — one tick() per iteration; it raises StuckLoop on the 3rd identical
signature.
lb = LoopBreaker(max_repeats=3, max_iterations=50)
while True:
lb.tick(action_signature) # raises StuckLoop when stuck
do_the_thing()3. Unbounded call — wrap the expensive function; it is checked before and charged after.
@guard(budget, "llm", est_usd=0.05, logger=runs, agent="writer")
def expensive(prompt): ...4. Escalation sprawl — the only things an agent may escalate are payouts, purchases, and
setup steps it cannot do. Anything else raises ValueError.
require_owner_action("attach the ZIP in Gumroad", "setup") # ok
require_owner_action("rewrite the landing page", "marketing") # ValueError — that's your job5. Invisible history — append-only JSONL, plus the metric that actually matters:
runs.log_run("researcher", "no-op", cost_usd=0.01)
print(runs.no_op_rate(last_n=20)) # fraction of recent runs that shipped nothingA run that costs money and ships nothing is invisible in a spend total — it looks like a cheap
run, not a wasted one. no_op_rate() makes it visible. If it climbs above ~0.3, your agent is
spinning, and the fix is a rule change, not a bigger budget.
python agent_guard.pyPrints a full end-to-end transcript: budget-guarded calls, a blocked call, the no-op rate, a loop that gets stopped, and an owner-action that gets rejected.
MIT — see LICENSE.txt. Use it commercially, fork it, ship it inside your product.
This is the free subset. The full AI Agent Ops Starter Kit (budget guard, multi-provider LLM router, decision log, distribution-first checklist) is at https://renevibe76.gumroad.com/l/iaofux
Run on Python 3.13 (Windows), 2026-10-20, python agent_guard.py:
1) budget-guarded calls
call 1: llm remaining = 0.1500
call 2: llm remaining = 0.1000
call 3: llm remaining = 0.0500
2) no-op rate (the silent budget killer)
no_op_rate(last 4) = 0.50
total cost logged = 0.2700
3) loop breaker
iteration 1: ok
iteration 2: ok
iteration 3: STOPPED -> stuck loop detected: signature 'same-action' repeated 3x (max_iterations=10)
4) owner-action gate (only payout|purchase|setup|other allowed)
logged a 'setup' action: ok
rejected as expected -> category must be one of ('payout', 'purchase', 'setup', 'other'), got 'marketing'. If it is not a payout, a purchase, or a setup step, it is the agent's job.
Exit code 0. Stdlib only, no network calls, no API keys needed to run the demo.