Middleware

Blast radius limiter

Caps how many writes a single run may perform.

Slot: policy · Ships: off · Enable per agent in agent.toml

Each run gets a budget of write operations. Every write the agent asks for spends one. Once the budget is gone, the agent's remaining writes are refused with a message that names the cap - so the model can wind down, summarize, or keep working read-only - while reads carry on untouched. The budget is per run: the next message starts over with a full one.

When you want it

Any agent with write tools where a confused run could make sweeping changes. A loop that renames one file too many, an agent that starts rewriting a whole directory, a scheduled job that should touch a handful of records and not a thousand. The cap turns the question of how much damage one bad run can do into a number you choose.

What it does

Counts the write-declared tool calls a run makes. Up to the cap they execute normally; past it, each further write is refused before it runs, with a message telling the model the cap was reached so it can change approach rather than retry.

The count is per run, not per conversation: each new user turn starts fresh.

A write that never actually ran does not spend the budget. The approval gate and dry run both decide after the cap is claimed, so a write they refuse - or one a cancel abandons - returns its claim. Otherwise two declined approvals would exhaust a cap of two without a single change being made. A tool autonomy forbids never costs anything either: autonomy leads the policy band, so it refuses the call before the limiter ever sees it.

Turn it on

[middleware.blast_radius]
enabled = true
max_writes = 20

Settings

KeyDefaultWhat it does
max_writes20Writes allowed per run before further writes are denied. 0 denies every write.

A typo in any of these keys fails the boot rather than being silently ignored.

What the agent sees at the cap

The refused call comes back as a normal error result:

Write limit reached: this run may perform at most 20 write operations, so 'save_file' was not run. Every further write this run will be denied. Continue with read-only steps, or stop and report what is left undone.

The model reads that and can change approach. The run keeps going, and the tool itself never executed. The refusal is recorded in the audit log with origin: denied, so a capped run is distinguishable from one that simply finished.

Good to know

  • Only tools that declare themselves write operations count. The cap is exactly as good as your tools' declared operation types; a tool that changes something while declaring itself a read is never counted.
  • A write that never ran does not spend its slot. The limiter claims a slot before the call proceeds, and approval, dry run, and cancellation all land afterwards, so a write any of them stops has its claim returned. Otherwise a run whose writes were all rejected would exhaust the cap having changed nothing, and then be told it was out of budget. Only writes that actually execute count. There is no refund needed there: autonomy sits ahead of the limiter, so a forbidden tool is refused before a slot is ever claimed for it.
  • Each run has its own budget, not the session. Every new user message is a new run with a full budget. This caps one run's damage.
  • Within one batch, the refusal is reported first. When the model asks for several writes at once and the batch crosses the cap, the refusal is decided before any of that batch executes, so its result appears ahead of the writes that did run.

Check it is loaded

axl weave print --config axl-config/agents/<your-agent>/agent.toml

blast_radius appears in the policy band of the printed stack.

Next

On this page