The setup
Alice runs the bookkeeping for a quarter. She writes a mandate for her assistant agent: budget
50.00 EUR in total, at most 3.50 EUR per call and 10.00 EUR per day, approval required above
1.00 EUR, extraction and finance capabilities allowed, one named agent allowed
(acme/company-lookup), a deny list, a data policy of seven days retention with no training use,
and delegation.max_depth: 1. That last field is the one that makes delegation finite: the callee
may hire agents, and those may not hire anyone.
She asks the assistant to process a batch of four invoices. The assistant picks
holon-labs/invoice-pipeline@0.4.0, an orchestrator. Its manifest declares its own price,
0.10 EUR per run, and what it delegates: extraction.table at up to 0.05 per call, and
acme/company-lookup@^1 at up to 0.01 per call, with a downstream cap of 3.00 EUR paid by the
original payer.
So the worst case is arithmetic anyone can redo before calling: 0.10 of the agent's own price
plus the 3.00 downstream cap, 3.10 EUR. That number is above Alice's approval threshold of
1.00, so the call does not run. It is held, and Alice decides.
Approval first, reservation second
Two details in that order matter.
Nothing is reserved while the call waits. A pending approval holds no money: the budget is not touched and the balance is not held. An approval that sits for six days does not freeze a cent. It expires after seven days and forgets the input it stored.
And the approval is bound. It is tied to the mandate, the exact agent version, a hash of the
input, and the max_cost it was requested with. The same token cannot be replayed against another
agent, another input or a bigger budget: the test suite has a case where an approval granted for
the pipeline is presented for a different orchestrator, and the call goes back to pending. Inside
a delegated run nobody can approve anything, because an agent must never be able to approve its
own spending.
Alice approves. Now the gateway reserves 3.10 EUR on her account and against her budget, before
the agent starts. Parallel calls see each other's reservations, so two runs cannot together
overrun a budget by both checking it first.
The sub-mandate can only narrow
The pipeline never receives Alice's mandate. The gateway derives a sub-mandate for this run,
alice/bookkeeping-q4.r4, and every field is computed rather than chosen by the agent:
| Field | Value |
|---|---|
| issuer and grantee | Alice's assistant, then the pipeline |
allow |
exactly what the pipeline declared it calls, and nothing else |
budget.total |
the downstream cap, 3.00 EUR |
require, data, deny, approval, fx |
inherited unchanged |
delegation.max_depth |
the parent's, minus one |
That derived mandate is then checked with the same attenuation rules a hand-written sub-mandate faces: validity inside the parent's window, no budget ceiling above the parent's, every allow pattern covered by a parent pattern, every deny kept, every data condition kept or tightened. A sub-mandate can narrow everything and widen nothing.
The consequence is concrete. The pipeline asks for a capability, extraction.table, and never
names an extractor. The gateway ranks the implementers that fit, inside the sub-mandate, and
picks. The orchestrator cannot route work to an agent Alice's mandate would refuse, cannot spend
above 0.05 on one extraction, and cannot call anything it did not declare. The test suite has
that case too: an orchestrator that tries to call an agent missing from its own calls gets a
refusal.
What the run cost
Four invoices, seven child calls, two of them failed. The failures are declared refusals, and they are not billed: two invoices came back as unmatched rather than as entries.
The parent receipt settles at own: 0.10, downstream: 0.092, total: 0.192 EUR, against a
worst case of 3.10. The split on the orchestrator's own 0.10 is 0.01 to the platform and
0.09 to its author. The difference between the hold and the bill is released, the mandate
records 0.192 spent, and no hold remains.
The receipt tree is the audit trail. The parent lists its seven children, each child is a receipt
with its own mandate (the derived one), status, cost and splits, and the failed ones carry
billed: false. The parent is not settled until every child has settled, including any still in
flight after a timeout. Nothing in any of those rows contains the invoices, which is the subject of
what a receipt must say.
Why it is built this way
Delegation is where agent platforms usually lose control of money. One agent calls another, which calls another, and the human who authorised the first call has no ceiling on the last one.
Three things prevent that here, and each is boring on its own. The worst case includes the downstream cap, so the number the human approves is the real ceiling. Every hop consumes one level of depth, so chains terminate. And the sub-mandate is derived and checked rather than supplied, so an agent cannot grant itself a permission it was not given. Giving an agent a budget covers writing the mandate at the top of that chain.