Authority envelopes and delegation
For: cluster operators and plugin authors.
The authority envelope
When a job starts, the edge writes block 0 of its authority envelope. Every way a job starts goes through it: the runtime API (oz0 run, the console, chat, Ask, the MCP server, A2A), webhooks, routines (a fire a schedule starts gets its block when the edge hands out its first step, before it runs anything), event deliveries, tool calls by hand, chat posts, scheduled evals, quality gates and rollouts' shadow runs, and an operator's start through the Temporal port.
A block becomes the job's only once the start really created the job's run with that block in its memo. A retry of the start that made a running job (a retried webhook, the same oz0 run --id sent again by its caller) returns that job on the envelope it started with; a start under the ID of a job that any other start made is refused with already_exists, and its answer shows what the caller may read of the job now.
A block is also its run's: a later run of the same job ID keeps it only when it continues that run (a continue-as-new, a workflow retry, a reset).
A job ID started again after its job ended runs on the envelope of the new start, never on the one the earlier run ran on, and an operator's start through the Temporal port (a start, a signal-with-start, an update-with-start) always gets a block 0 of its own (operator:<name>), whatever envelope its memo names.
A schedule an operator writes through the Temporal port starts its runs with no envelope.
| Field | What it holds |
|---|---|
subject | On whose authority the tree runs: a person (user:ada), a routine's owning team (team:ops), or what started it otherwise (apikey:<id>, operator:<name>, webhook:<flow>, event:<source>, system:<what>) |
agent, agent_version, plugin, install_gen | The agent or flow, the version it starts on, its plugin, and the plugin's install generation, which an upgrade keeps and a removal and new install change |
purpose | The SHA-256 of the start's input, or the routine, webhook, event source or eval that started it |
scopes | What the tree may reach, computed by the edge from the plugin's manifest and the grants at the start, never chosen by a model: plugin:<name>, tool:<plugin>/<tool>.<function>, agent:<plugin>/<name> |
budget_usd, max_depth, expires_ms | The tree's ceilings: its budget, how deep it may delegate (the tree depth the root agent or the tenant sets, none when neither does), and when its authority ends (the job's timeout, none without one) |
policy_version | The version of the tenant's tool policy at the start |
epoch | The tenant's authority epoch, which a kill switch's fence compares |
level, granted_by, level_policy_version | The autonomy level the tree runs at (L2 until autonomy levels arrive), who granted it, and the version of the policy that set it |
labels | The tree's sensitivity labels, when the tenant has them |
Temporal's history holds only the envelope's hash, in the job's memo; the edge keeps the blocks, and oz0 job get shows the hash as envelope.
Each hop only narrows
A child job, a flow tool's flow, a colleague's question, an MCP or A2A task another job of the tenant started for the same person, and Ask's hand-over each add a block to the envelope of the job they come from. The edge appends it when it sees the hop (a child's start passes the edge as a command of the parent's workflow task), and nothing else can:
- the subject and the epoch are the parent's;
- the scopes are what both the parent holds and the child's own plugin reaches;
- the budget, the depth and the expiry can only stay or fall, and depth grows by one;
- the level is the lowest along the chain: delegation never raises it.
A runtime may ask for less authority for a child (a smaller budget, fewer scopes) and never for more: a child start that asks for more than its parent holds is refused, the job fails with the reason, and the audit log records envelope.widening_refused. A grant an admin adds while a tree runs does not widen that tree; a grant withdrawn is refused at once, as before.
The edge MACs every block with a key it derives for the tenant from the cluster's secrets key, which only edges hold when management runs apart: neither a node nor management can write a block, and an edge that holds the secrets key takes no block MACed any other way.
In one process without a secrets key (dev mode, a single server) the key is derived from the master key.
Only the edge names a job's envelope: one a node's runtime writes into a child's start, its own memo or a continue-as-new is dropped, and a memo that names another job's block gives a job nothing.
Constraints that survive every hand-off
A job may start with constraints: restrictions its work and every job it delegates to must respect, such as data classes, rules or policy findings.
oz0 run triage "Look into ticket 4711" --constraint "no personal data leaves the EU" --constraint "cite the ticket"
The runtime copies them word for word into every child's start and every colleague's question, and shows each model the list as given, in a section of its own before its task or the question; no model is asked to summarise them. Ask's hand-over turn and the agent jobs a flow tool's steps start do not get them yet. Each job's memo holds their digest, shown as constraints_digest, and an eval case can plant constraints and expect them at a depth of the tree (constraints_reach).
An orchestrating model reads the agents it may delegate to by role and stable ID (id <plugin>/<agent>: <description>); the platform never tells it the model, the provider or the model family behind an agent.
Revocations reach exactly the jobs that lost their authority
A kill switch, a grant narrowed, a plugin removed, an API key revoked, or a person who can no longer start jobs is a revocation. It moves the tenant's authority epoch on by one (revocations that land together share one step), and each envelope carries the epoch its tree started under.
One function decides whether a revocation reaches a job, from the job's envelope chain: a killed agent anywhere in the chain, the subject who started it, a scope the grantee held and no longer gets by any path.
The edges use it to refuse every call of a reached job whose envelope is older (the fence, keyed by the call's binding), and the edge that computes the batch uses it to stop those jobs and no other, over every running workflow of the tenant.
A person's revocation is written only when the change closed their last path to start jobs, judged after the change, so two changes that together take a cluster admin's last path stop their jobs though neither alone would.
Each batch ends in a receipt, signed with the audit key: every stopped job, and every carrier the platform cannot prove stopped, such as a remote agent's session at its provider, as indeterminate with the reason. See kill switches.