Holon Caller Mandate — v0.1 (draft)
The manifest says what an agent offers. The mandate says what an agent is allowed to do: which agents it may call, how much it may spend, and what may happen to the data it passes on.
It is the piece that lets agents act without a human watching every call, while the human stays in control. More autonomy is granted by widening a mandate, not by removing it.
Machine-checkable definition: schema/holon-mandate.schema.json.
holon mandate check <mandate.yaml> <holon.yaml|dir>... # may the grantee call these agents?
holon mandate attenuate <parent.yaml> <child.yaml> # is the sub-mandate within its parent?
holon search [query] --mandate <mandate.yaml> # rank only what the mandate permits
1. Model
alice (human)
└─ root mandate ──────────► alice/assistant
└─ sub-mandate ──────► holon-labs/invoice-pipeline
└─ calls ► acme/table-extract
- A root mandate is issued by a human account to an agent (the grantee).
- The grantee MAY issue sub-mandates to the agents it calls. A sub-mandate MUST be an attenuation of its parent: it can narrow everything and widen nothing.
- The gateway checks every call against the caller's mandate before the call is made. Every call produces a receipt: which agent, under which mandate, the worst case, the actual cost, and the decision with its reasons.
This is the capability-token pattern (as in macaroons or UCAN) applied to spending and delegation between agents.
2. Fields
| Field | Rule |
|---|---|
issuer / grantee |
Who grants, who acts. For a sub-mandate, issuer MUST be the parent's grantee. |
valid.from / valid.until |
Mandates always expire. |
budget.total, per_call, per_day |
Decimal strings. per_call bounds a single call's worst case. |
budget.fx |
Rates into budget.currency. A call priced in a currency without a rate is refused. Conversion rounds up. |
approval.above |
Calls whose worst case exceeds this are held for the issuer's approval instead of being refused. |
allow.capabilities |
Class patterns: extraction.table, extraction.* (subtree) or *. |
allow.agents / deny.agents |
namespace/name or namespace/*. Deny wins. |
allow.published |
Hosted gateway: true lets capability calls be routed to agents published by other authors. Off by default; calling an agent by name is not affected. |
require |
charge_on_success, runtimes, and measured thresholds: min_success_rate, max_latency_p95_s, min_runs_30d, min_eval_score (evaluations). |
data |
max_retention, training_use: false, allow_egress: false. |
delegation.max_depth |
How many more levels of agents may appear below the direct callee. Defaults to 0. |
3. Admission: may this call happen?
For a caller holding mandate M and a callee with manifest A, the call is:
- denied if any of the following fails:
- M is valid now, and A is not matched by
deny; - A matches
allowby capability class or by agent; - if A declares
calls:delegation.max_depth ≥ 1, and every declared downstream capability or agent is itself withinallow; - A's pricing, runtime and data policy meet
requireanddata; - A's measured record meets the thresholds. No record means the threshold is unmet: an unmeasured agent is not a trusted agent;
worst case ≤ per_call, and neithertotalnorper_daywould be exceeded counting the worst case.
- M is valid now, and A is not matched by
- held for approval if it passes and the worst case exceeds
approval.above. - allowed otherwise.
worst case = price ceiling (amount, or max for per-unit and quote) + downstream.cap
for passthrough pricing, converted into the mandate's currency.
Budgets are charged at the worst case when a call starts, and the difference is released when it settles. Parallel calls therefore cannot overrun a budget together.
4. Attenuation
A sub-mandate C of parent P is valid only if:
C.parent = P.idandC.issuer = P.grantee;- C's validity window is inside P's;
- same currency, and every budget ceiling in P exists in C and is not higher;
the same applies to
approval.above; - every
allowpattern in C is covered by a pattern in P; - every
denypattern in P is kept in C; - every
requireanddatacondition in P is kept or tightened; C.delegation.max_depth ≤ P.delegation.max_depth − 1. Each hop consumes one level, so delegation chains always terminate.
5. Ranking under a mandate
holon search --mandate removes the agents the mandate denies (each with its first
reason) and ranks the rest by relevance, then by cost per successful run
(worst case ÷ success rate), then by p95 latency. List price alone is a poor signal:
a cheap agent that fails half the time costs double.
Cold start
An unmeasured agent is not trusted, so a mandate with measured thresholds refuses brand-new
agents. Platform evaluations close the gap. They produce eval_score and feed
success_rate without counting as usage. A mandate that requires min_eval_score (plus, if it
wants, min_success_rate) accepts a new agent once it has been evaluated. min_runs_30d stays
for mandates that also want a usage history.
6. Open questions
- Signatures: mandates must be signed by the issuer and chained by hash. v0.1 specifies content only.
- Revocation: a revocation list checked by the gateway, and what happens to calls in flight.
- Spend state:
spent.totalandspent.todayare gateway state. The reference CLI takes them as flags (--spent-total,--spent-today). - Data classes: tagging inputs (PII, health, secrets) and restricting which agents may see each class.