Guide ยท 7 min read

A spending limit the agent cannot raise.

Most things called a limit are a cap on one provider, a number inside the process being limited, or a chart that moves after the money is gone. A limit that holds needs to be outside the agent, shared across the run, and provable afterwards.
the eleventh sub-agent asksshared envelope
{
  "action_type": "tool.invoke",
  "resource": "api.openai.com",
  "cost_cents": 900,
  "currency": "USD"
}
the answer
{
  "outcome": "denied",
  "rule": "run_budget_exhausted",
  "headroom": { "budget_remaining_cents": 0 }
}

It gets the same answer the first one would have if the first one had spent the envelope. That is what shared means.

Why the usual answers stop short

Five limits that are not a limit.

Each of these enforces something real. None of them is a ceiling on what this agent, across this run, may spend in total.
What people useWhat it does not cover
A hard cap at the model providerHolds for that provider. Knows nothing about the other three, the search API, the scraper, or the payment the agent is about to make. Your exposure is the sum and nothing sums it.
A limit in the orchestratorReal enforcement, and it lives inside the process it is supposed to constrain. Whatever compromises the agent compromises the check, and changing the number needs a deploy.
A virtual card with a ceilingStops one transaction that is too big. Does not see the same charge repeated nineteen times, and never sees the paid API call that is not a card transaction at all.
A cost dashboard with alertsTells you what happened. By the time the chart moves the money is spent. Observability is not control.
A prompt instructionAsks the agent to police itself. Useful as a hint, worthless as a boundary.

The longer versions: versus an if statement in your orchestrator and versus card limits.

What a real limit needs

Five properties, and they are not optional.

1
Held outside the agent
If the limit lives where the agent runs, the agent can reach it. The ceiling has to be state the agent can read the consequences of but not edit.
2
Shared across the whole run
One envelope that every call draws down, not a per-call cap. Ten calls under a per-call limit is not a limit, it is ten limits.
3
Delegable without multiplying
Fan out to five workers and they draw from the parent budget. Each inheriting the full ceiling multiplies your exposure by the fan-out factor.
4
Across every kind of spend
Model calls, paid tools and real payments against one ceiling, so a runaway loop on tools eats the headroom the payment would have needed.
5
Producing evidence
A decision that only lives in your database binds an executor that chooses to ask. A signed answer binds one that must present it.

In practice

One envelope, every action type.

Policy is data rather than deployed code, so raising a ceiling is a change to a record and shows up in review. The daily window below covers every action type at once, which is what stops a loop on tools from quietly consuming the budget a payment was going to need.
policy.jsonvalidates on write
{
  "mode": "allowlist",
  "rules": [
    { "kind": "spend_window", "max_cents": 25000, "window_seconds": 86400 },

    { "kind": "rate_limit", "max_actions": 200, "window_seconds": 60,
      "action_types": ["tool.invoke"] },

    { "kind": "cost_cap", "max_cents": 5000,
      "action_types": ["payment.create"] },

    { "kind": "condition", "effect": "require_approval",
      "rule_name": "unknown_vendor",
      "when": { "not": { "field": "resource", "operator": "in",
        "value": ["api.openai.com", "api.anthropic.com"] } } }
  ]
}

An unknown rule kind or a missing setting is rejected when you save it, not when an agent is waiting on it at three in the morning.

The same engine governs non-AI automation, which is usually where teams get their first measurable win:refund and payout authority. If you want the record of what was spent as well as the rule about what may be, that is the ledger.

Questions

What engineers ask before wiring it in.

Does this replace the guardrails in my agent framework?+

No, keep them. They catch things a spend layer never sees, like what the model is about to say. The difference is that a framework hook holds no budget across runs and cannot produce evidence that anything was authorized.

What about latency on every tool call?+

One call before the action, and a simulate call when you want a dry decision that reserves nothing. Design the check into the path you already have rather than adding a round trip per token.

What happens if the control layer is unavailable?+

You choose: fail closed and the agent stops, or fail open and you accept the exposure for that window. The important part is choosing deliberately rather than discovering the answer during an incident.

Can one budget cover model spend and real payments?+

That is the point of using dotted action types. tool.invoke and payment.create draw down the same envelope, so spend on one consumes headroom for the other.

Where does this stop being true?+

A control layer only binds the paths you route through it. An agent holding a credential that reaches a rail directly is not governed by anything here, which is why the signed decision matters: make the executor demand it.

Give one agent a ceiling and try to break it.

Test mode is the whole engine, with no card. Fan out sub-agents against a shared budget and watch the envelope hold.