ERC: Bounded Agent Actions - a metering layer for agent authority
There are a lot of agent ERCs landing right now, so I want to be clear up front about what this one isn’t. It doesn’t enforce anything, it doesn’t run a workflow, and it doesn’t settle. What it does is narrow: it keeps a running count of how much of a bounded mandate an agent has already spent across its actions, so a downstream contract can look up how much room is left. That’s the whole idea: one small on-chain object, a cursor, with a single interface to read it and advance it. I’m proposing it on its own, not as part of a bigger framework, because the counting is the piece I think is actually missing today.
The bounded-execution discussion over on ERC-8301 is circling the same gap from the execution side. I brought the metering angle up there, but it felt like it deserved its own thread rather than taking that one over, so here we are.
One thing to flag: this interface does not, on its own, make a bound impossible for the principal’s own key to bypass. Counting and enforcing are two different jobs. Something underneath has to actually hold the line: a vault that custodies the assets, or a module sitting on the account’s only execution path. I’ve written that into the spec as an explicit requirement on whoever implements that layer, rather than something the interface quietly assumes. I’m putting it first because it’s what keeps this proposal from stepping on the enforcement standards. This interface does the accounting; the enforcing happens somewhere else.
There’s one design decision that everything else hangs on; You can express a bound two ways: 1) as a predicate that gets recomputed from public state on every action, or 2) as a counter that each action writes to. If everything settles on a single surface, the predicate is enough, because execution there is serialized, so a check that reads and writes in the same transaction already sees everything that came before it. The moment you cross surfaces, that stops being true: no single contract holds the running total, and there’s no check you can run at action time that reconstructs it. That’s the reason this has to be a standing object that actions write to, instead of something you bolt on as a per-call hook.
I want this to sit next to the standards we already have, not on top of them. Concretely, with ERC-8301: a step gate reads getCursor(id) and calls advanceCursor in the same step. 8301 makes sure a task moves through its stages in order; the cursor records how much authority those stages have used up; and the substrate is what keeps that total inside the committed bound. The same shape works elsewhere. It composes with a 7710 caveat enforcer, with an 8001 agreement (the agreement records what was accepted, the cursor records what’s left), and with an 8274 verification standing in as the witness for an advance.
The base interface deliberately doesn’t assume any particular enforcement mechanism underneath it. “Doesn’t assume anything” can quietly turn into “doesn’t pin down anything,” though, so I’ve also written one concrete profile to implement against: a budget substrate that fixes what the cursor means (running spend), what the commitment holds (a cap and an asset), what the witness is, and the one invariant that matters, spent <= cap. It comes with a typed IBudgetSubstrate, so a consumer can call remaining() and get a number back directly. There’s a minimal CC0 reference registry here and the ERC-165 ids are frozen.
I also have a private, more complex implementation in this area, which is why the public one is intentionally minimal. It is clean, meters but doesn’t enforce, holds no assets, and it’s bypassable on purpose. We created it to show that the interface is implementable and that the profile interoperates.
I’m posting this as a draft to start the conversation, and I would genuinely value input, especially on three things: 1) Is splitting the cursor from the profile the right cut, or am I drawing that line in the wrong place? 2) Is the interoperability guarantee in the budget profile actually tight enough to be worth anything? And 3) where should this overlap with the 8301 bounded-execution guardrails, and where should it stay out of their way?
Looking forward to your thoughts ![]()