Orchestration Governance
Orchestration governance gates composition, not primitives. A single agent browsing on its own, writing to a canvas it holds editor on, or sending one mesh message is never gated by this layer — each of those already carries its own permission check (a canvas role, a mesh capability), and passing that check is the end of the story for a single action taken alone.
Why composition is the thing that needs a separate gate
A single action's permission check covers that action, not the sequence around it. Orchestration governance limits chains of actions, such as one agent triggering another agent that then takes a gated action.
Why two independent gates instead of one
Forming a chain requires both a cloud entitlement (nexus.orchestration) and a local setting to be enabled — and both default off. Either one being closed is enough to block every chain. Requiring two independent keys, controlled from two different places, means neither a cloud-side entitlement flip nor a local misconfiguration is by itself sufficient to enable autonomous chains — closing either one is a real, immediate stop, not a suggestion the other side can override.
Why the controls are coarse-grained today
Maximum chain depth, maximum distinct agents per chain, an orchestrator allowlist that starts empty, a per-hop approval setting that is on by default, and a stop-all control are the levers available now. An empty allowlist by default means nothing can orchestrate until it's explicitly added — the same default-deny posture the canvas takes on roles. Depth and breadth limits bound the worst case of a runaway chain even when everything else is configured to allow it. The stop-all control exists because none of the other controls are useful in the middle of an incident if there isn't also a way to halt everything already in flight.
Why settings are re-read at enforcement time, not cached
Turning the local setting off takes effect on the very next hop, with no restart required. A cached copy of "is orchestration currently allowed" would mean an operator's decision to stop it mid-incident wouldn't actually take hold until whatever held it cached refreshed — which defeats the purpose of having a fast, local, no-cloud-round-trip control in the first place.
Why denial reasons are distinguishable
A chain can be denied for any of: no entitlement, the local setting disabled, depth exceeded, breadth exceeded, the orchestrator not on the allowlist, or a global stop in effect. Each of those demands a different fix — buying an entitlement is not the same action as raising a limit, and neither is the same as realizing someone hit stop-all five minutes ago. Collapsing all six into one generic "denied" would leave the person debugging it guessing which of six unrelated things to go check.
The distinction reaches the caller, not only the trace. A denied call answers with the reason in two forms at once: a sentence naming the condition that failed and where to change it, and a stable machine-readable code beside it, so an agent can branch on which rule stopped it instead of pattern-matching prose. The codes and the result shape are specified under tools/call.
An agent that is denied should report the reason it was given rather than retrying. Only two of the six can change without a person acting — a depth or breadth cap frees up once the run in progress finishes — and the other four stay true until someone changes a setting, a plan, or the allowlist.
The per-hop pause point, and what it holds
Per-hop approval is a real pause point, and it is on by default. With it on, a hop that has passed every other check is not performed: it is held, and an approval card appears in the NEXUS window naming the agent, what it wants to do, what it wants to do it to, and which hop of the chain this is. The hop proceeds only after you answer, and a refusal is reported to the agent as a refusal rather than a silent failure.
The card is the same one an agent's own autonomy mode raises, in the same place, because to a person both are one question — an agent wants to act unattended, may it — and it says which of the two is asking, since the remedy differs.
Three properties are worth knowing before relying on it:
- Only governed hops are held. A chain's first hop is not governed at all, so holding starts from the second hop onward — the same boundary depth, breadth, and the allowlist already use. A lone agent acting by itself is never held by this layer.
- A held call is answered immediately rather than parked. The agent is told the hop was not executed and is given the request's id; it retries the identical call once you have approved, and the retry finds your answer. Nothing is left open waiting on you, so one unanswered question never stalls other agents' work.
- An approval covers exactly that hop. It is consumed the moment the call proceeds and grants nothing standing. Trusting an agent for the rest of a session — which does relax its own autonomy prompts — deliberately does not cover an orchestration hold, because that hold is a policy about a chain, not a grant to one agent.
Turning the setting off is what lets a chain run unattended. Depth, breadth, the allowlist, and stop-all all continue to apply either way.
Delegation is a chain hop
Handing a task from one agent to another is composition, so every limit on this page applies to it: a delegated task counts against the chain's depth and against the number of distinct agents the chain has touched, and it can be denied for any of the same six reasons. The delegated result travelling back is not a new hop — the answer belongs to the exchange the trigger opened.
Finishing is an evidence-gated step, not a claim
A delegated task carries an acceptance check, and it cannot be recorded as completed on the recipient's word alone. The check is run and its evidence recorded before completion is admitted; a task whose check has not passed stays open with the refusal reason stated where the refusal happens, and one refused repeatedly escalates to a visible failure rather than retrying forever. The recorded evidence — what was run and what it produced — stays queryable per task, so a completed task can be audited rather than trusted.
This is the composition-level counterpart to the per-hop pause point: approval governs whether work is allowed to happen, and the acceptance check governs whether the work that happened is allowed to count as done.
Where to see what a chain did
Settings ▸ Agents ▸ Orchestration ▸ Recent chains lists multi-agent runs, most recently active first: the participating agents in the order they acted, how many hops the run took, and for each hop the agent, what it did, what it acted on, and the verdict — allowed, awaiting your approval, approved, refused, or denied with the specific one of the six reasons it was denied for. A hop that is waiting on you appears there while it waits, and switches to your answer the moment you give it rather than when the agent next gets around to retrying.
Refusals are listed exactly like admissions, because a record of only the hops that proceeded cannot explain a run that stopped — the denial row is the one that says the chain hit its depth cap rather than simply finishing.
Two boundaries are worth stating plainly. A run appears only once it has more than one recorded hop — a lone action, including one agent triggering another with nothing following, has not composed yet, and listing every one of those would bury the runs this exists to show. And the list is bounded and covers the current run of the app — it is there to explain what just happened, not to serve as a durable audit log. Clearing it forgets the runs shown; it stops nothing and changes no limit.
The list stays visible whether or not Cross-Agent Orchestration is currently switched on, because a run that happened before someone turned it off is exactly the run you would come here to read.