A3 Authority Envelope
Version: 1.0.0 Status: Stable. Changes follow the versioning rules in the README. Licence: Community Specification License 1.0 (LICENSE.md). Independent implementation is explicitly permitted and encouraged. Depends on: Decision Trace Format 1.0 (envelopes are recorded in and verified over a trace, and signed with its key set); Capability Schema 1.0 (clearance identifiers).
An agent acting for a person must never be able to do more than both of them are allowed to. Most systems get half of this: they check what the agent is allowed to do, or what the user is allowed to do, and then let the other half through on trust. The confused deputy — an agent used to exceed its caller’s authority — lives in that gap.
This specification defines the authority envelope: a signed claim stating exactly what a task may do, computed as the intersection of the agent’s grants and the originating principal’s grants, scoped to one task, time-boxed, and carried across delegation so that a sub-task can never hold more than its parent. Because it is a signed object with both inputs inside it, any system that receives it — a tool gateway, another runtime, an auditor a year later — can check the intersection itself rather than trusting whoever handed it over.
The words MUST, SHOULD and MAY are used as in RFC 2119.
1. Properties
| Property | Meaning |
|---|---|
| Intersection | clearances is exactly what the agent holds ∩ what the principal holds. Never a union, never either side alone. |
| Self-evidencing | The envelope carries both sides (held), so the intersection is recomputable by anyone. |
| Non-transferable | It names one trace and one task; it is useless anywhere else. |
| Monotone under delegation | A child envelope’s clearances, budget, expiry and depth are bounded by its parent’s; its principal is its parent’s. Authority flows down and only shrinks. |
| Verifiable | It is signed by the issuing control plane with a key from the trace’s key set. |
| Binding on actions | Every action recorded in the trace names the clearances it required; a verifier checks each against the envelope. An approval authorises an action within the envelope; it never adds to it. |
2. The envelope
{
"v": "1.0",
"trace_id": "019267b4-…",
"task_id": "task-4471",
"principal": {"type": "human", "id": "sub|8f3a"},
"agent": {"name": "order-analyst", "namespace": "support"},
"clearances": ["orders.read"],
"held": {
"agent": ["customers.read", "orders.read", "refunds.issue"],
"principal": ["orders.read"]
},
"budget": {"tokens": 400000, "usd": "0.75", "wall_clock_ms": 600000, "actions": 40},
"expires": "2026-09-16T14:10:00.000Z",
"depth": 0,
"parent": null,
"issued_at": "2026-09-16T14:00:00.020Z",
"issuer": "control-plane",
"sig": "…"
}
| Field | Required | Meaning |
|---|---|---|
v |
yes | Specification version. |
trace_id, task_id |
yes | The one task this envelope is for. |
principal |
yes | The originating principal: type is human or service, never agent. |
agent |
yes | The agent definition that will act. |
clearances |
yes | The intersection. Sorted, unique. May be empty. |
held.agent |
yes | Every clearance the agent had been granted at issue. Sorted, unique. |
held.principal |
yes | Every clearance the identity interface reports the principal as holding at issue. Sorted, unique. |
budget |
yes | tokens, usd (decimal string), wall_clock_ms, actions. What the task may consume. |
expires |
yes | RFC 3339 UTC. Nothing may run under this envelope after it. |
depth |
yes | Delegation depth; 0 for a task submitted from outside. |
parent |
yes | null, or {"trace_id", "seq"} of the parent’s delegation.spawned record. |
issued_at |
yes | RFC 3339 UTC. |
issuer |
yes | Key identifier of the signing control plane, resolvable in the trace’s key set. |
sig |
yes | base64url Ed25519 signature over utf8(envelope_hash). |
envelope_hash = sha256(JCS(envelope without sig)), encoded sha256:<hex>, using RFC 8785 canonicalisation exactly as the trace format does. Signing the hash string rather than the object keeps the construction identical to trace records, so the same keys and verifiers apply.
The envelope is recorded verbatim as authority_envelope in the trace’s task.admitted record. The trace format requires only clearances and expires there; this specification requires the whole object.
3. Issuance rules
An issuer MUST:
- Obtain
held.agentfrom the agent’s granted clearances andheld.principalfrom the identity interface at issue time, not from any cached or caller-supplied value. - Compute
clearancesas the exact set intersection, sorted. - Set
expiresno later than the task’s deadline, if it has one, and no later than the parent’sexpiresfor a delegated task. - Set
budgetno greater than the parent’s remaining budget for a delegated task (§5). - Sign with a key whose key-set entry names the control-plane component.
An issuer MUST NOT issue an envelope whose principal.type is agent. An agent’s own identity never originates authority.
4. Use rules
- A gateway or any other enforcement point MUST refuse an action whose required clearances are not a subset of
clearances, and MUST record the required clearances on the action’stool.invokedrecord asclearances_required, so the check is verifiable. - An action MUST NOT run after
expires. - An approval (Approval Protocol) authorises an action within the envelope. If the action’s required clearances exceed the envelope, approval does not cure it; the action is refused before approval is sought.
- An enforcement point receiving an envelope from another system MUST verify its signature and scope before honouring it.
5. Delegation
When a task delegates work to another agent, the child task receives its own envelope, derived from the parent’s. A child envelope MUST satisfy, relative to its parent:
| Rule | Requirement |
|---|---|
| Principal | child.principal equals parent.principal. Delegation never re-originates authority. |
| Clearances | child.clearances ⊆ parent.clearances. The child’s held.agent is the child agent’s own grants; held.principal is the parent’s clearances (the parent’s effective authority is the principal-side input to the child’s intersection). |
| Budget | Each dimension of child.budget ≤ the parent’s remaining budget at delegation: parent.budget minus the parent’s recorded consumption and minus budgets already delegated to earlier children. |
| Expiry | child.expires ≤ parent.expires. |
| Depth | child.depth = parent.depth + 1, and ≤ the parent agent’s declared maximum delegation depth. |
| Link | child.parent names the parent’s delegation.spawned record; that record’s authority_envelope equals the child envelope. |
A runtime MAY additionally require that a parent declare the kinds of work it delegates, and refuse a delegation outside that declaration. Such a refusal is a policy decision, recorded as one; it narrows what may be delegated and never widens it, so an envelope issued by a runtime that enforces it verifies exactly as one issued by a runtime that does not.
A dimension a parent never limited is written as zero and bounds nothing, so a parent that has spent a dimension it did limit MUST refuse the delegation rather than issue a child with zero on that dimension. Zero as “nothing left” and zero as “no limit” are indistinguishable in the record, and an implementation that hands the first down creates a child that is unbounded where its parent was exhausted.
The parent trace’s delegation.spawned record carries the child envelope verbatim; the child trace’s task.admitted carries the same object. A verifier with both traces checks them against each other.
6. Verification procedure
Runs over a trace, or a bundle of traces, that has passed the Decision Trace Format verifier. Every error is reported.
Per trace:
- Structure.
task.admitted.authority_envelopeis a complete envelope. ElseE_STRUCTURE. - Scope.
trace_idandtask_idequal the trace’s. ElseE_ENVELOPE_SCOPE. - Signature.
issuerresolves in the key set to a control-plane key valid atissued_at, andsigverifies overenvelope_hash. ElseE_ENVELOPE_SIG. - Intersection.
clearancesequals sorted(held.agent∩held.principal). ElseE_INTERSECTION. - Principal.
principal.typeishumanorservice, and equalstask.admitted.originating_principal. ElseE_PRINCIPAL. - Expiry.
expiresis not beforeissued_at; notool.invokedhastsafterexpires. ElseE_ENVELOPE_EXPIRY. - Actions. For every
tool.invoked,clearances_required(absent means none) ⊆clearances. ElseE_ACTION_UNAUTHORISED. This applies equally to approval-gated invocations.
Per bundle, for every trace whose envelope has a non-null parent:
- Link. The parent trace is in the bundle; the record at
parent.seqisdelegation.spawned; itsauthority_envelopeequals this envelope (byenvelope_hash). ElseE_CHILD_LINK. - Monotonicity. Principal equal (
E_CHILD_PRINCIPAL); clearances subset (E_CHILD_WIDENED); each budget dimension ≤ parent remaining at the spawn record (E_CHILD_BUDGET); expiry ≤ parent’s (E_CHILD_EXPIRY); depth = parent + 1 (E_CHILD_DEPTH).
What the verifier cannot establish: whether held.principal was true — whether the identity interface reported honestly. It establishes that the issuer committed to a specific claim about it, under signature, and that everything downstream was consistent with that claim.
7. Relationship to the other specifications
- Decision Trace Format gives the envelope its record, its key set and its bundle linkage. The format’s own bundle check (
E_ENVELOPE_WIDENED) is a coarse version of §5; this specification is the precise, signed one. - Capability Schema defines clearance identifiers and what an agent declares it holds. A declaration is what the agent claims;
held.agentis what the issuer confirmed at issue. - Approval Protocol operates within the envelope. The plan’s
originating_principalis the envelope’sprincipal; a gated invocation is subject to rule 7 like any other.
8. Conformance
Issuer: produces envelopes that verify. Enforcer: refuses actions outside the envelope and records clearances_required. Verifier: produces the specified result for every vector in vectors/authority-envelope/. Initial vectors: a valid envelope with an action inside it; an intersection that includes something the principal does not hold; a bad signature; an action requiring a clearance outside the envelope; an approved action outside the envelope; a valid delegation bundle; a child with a clearance its parent lacks; a child budget above the parent’s remaining; a child with a different principal; a child at the wrong depth; a child expiring after its parent; an envelope scoped to another task.
9. Settled in 1.0, and future work
Settled:
held.principalrecords the principal, not the identity provider’s assertion. An optionalevidencefield carrying that assertion (for example an OpenID Connect token’s issuer andjti) can be added in a minor version, so that a verifier can go one step further back.- Budget across a delegation tree is “remaining at the spawn record”, reconstructed from
budget.consumedrecords. A parent that under-reports consumption can over-delegate. The control is the supervisor’s signature on those records: the under-report is on the record, signed by whoever made it. - An envelope cannot be narrowed by the submitter in 1.0. A principal asking to run with less than they hold is useful, and can be added as an optional field in a minor version without changing how an envelope is computed when it is absent.