← Blog

Identity & access · · 8 min read

Sub-agent identity: inherit and narrow

The two rules that govern how a sub-agent's identity should be derived from its parent's, what a sub-agent claim looks like, and how audit reconciliation works across the run graph.

Jonathan Haas

Production agent stacks fan out. A top-level run that handles a customer request often spawns sub-agents to parallelize work: one sub-agent searches the knowledge base, another drafts a response, another checks the response against policy. Each sub-agent is its own loop, calling its own tools, returning results to the parent. The fan-out is performance-driven: serializing the steps doubles or triples user-visible latency. The fan-out is also identity-complicated: each sub-agent has to act on someone's behalf, and the someone has to be traceable through the run graph.

The rule that scales is inherit and narrow. A sub-agent's identity is derived from the parent's, with permissions strictly narrowed for the work the sub-agent was spawned to do. The sub-agent cannot widen scope beyond the parent's, reach data the parent could not reach, or escalate to a privilege the parent doesn't hold. The orchestrator that spawns the sub-agent is the component responsible for the narrowing.

Why sub-agents exist#

A few patterns drive fan-out in practice:

  • Parallel retrieval. The agent needs context from multiple sources. Spawning one sub-agent per source returns results in max time instead of sum time.
  • Specialization. The model used for the top-level reasoning is expensive; the work of summarizing a single document or extracting a single field is better served by a smaller model. The sub-agent uses a cheaper model and reports back.
  • Sandboxing. The work is risky enough that the operator wants it isolated. The sub-agent runs in a sandbox with narrower permissions than the parent; even if the sub-agent goes wrong, the blast radius is bounded.
  • Independent step retry. The parent's plan has a step that can fail; spawning a sub-agent for the step lets the parent's loop retry without rolling back its own state.

These patterns are real and the architectures that ship them are well-established. The identity layer is the part that often lags. Many production stacks distribute the parent's full credential to every sub-agent, which means a misbehaving sub-agent can do everything the parent could do — including things it has no business doing for its narrower task.

What the parent's claim contains#

The parent run's identity carries the claims the policy gate evaluates: the agent id, the operator behind the run, the run id, and the scope the run is allowed to act on. The scope includes the resources the agent has been authorized to reach, the action classes it is allowed to invoke, and the run-context information the policy needs (the support ticket id, the customer id, the repository name).

A useful mental model for the parent's identity: a verifiable credential the runtime mints at run start, signed by the identity service, with the scope embedded as claims. The credential expires when the run ends. The agent itself doesn't store it long; the orchestrator carries it and presents it to the policy gate on each action.

What narrowing means#

When the orchestrator spawns a sub-agent, the orchestrator mints a new identity for the sub-agent, derived from the parent's. The derivation has rules:

  • The sub-agent inherits the operator behind the parent's run. The operator field is the same.
  • The sub-agent gets its own run id, with the parent's run id recorded as parent_run_id. The audit log uses both for traceability.
  • The sub-agent's scope is the intersection of the parent's scope and the work the sub-agent was spawned for. If the parent had access to the entire customer dataset but the sub-agent was spawned to summarize one document, the sub-agent's scope is the single document.
  • The sub-agent's allowed action classes are an explicit subset of the parent's. A sub-agent spawned to read does not inherit the parent's write permissions, regardless of whether the parent had them.
  • The sub-agent's identity expires when the sub-agent's task is complete, not when the parent's run ends. A sub-agent that returns in seconds doesn't need credentials that outlive its work.

Concretely, a parent identity might carry scope: { customer: "cust_42", actions: ["read", "write"] }. A sub-agent spawned to summarize a single ticket carries scope: { customer: "cust_42", ticket: "tk_007", actions: ["read"] }. The customer constraint is inherited; the ticket constraint is new; the action set is narrowed.

The orchestrator is the trusted component that performs the narrowing. The policy gate verifies the orchestrator's signature on the sub-agent's identity and refuses to evaluate sub-agent actions whose claimed scope isn't a strict subset of a verifiable parent's scope.

The fan-out problem#

A parent that spawns 100 sub-agents needs 100 identities, each with its own scope, each with its own expiry, each registered with the policy gate. At reasonable agent volumes — tens of thousands of runs per day, each fanning out — the identity-issuance rate becomes a system load characteristic.

The issuance has to be fast (tens of milliseconds per identity, per the latency budget covered in Why service-account permissions don't fit agents). It also has to be reliable: a sub-agent that can't get an identity is a sub-agent that can't act, which means the parent's plan stalls.

Two implementation patterns that scale:

  • Pre-issued claim bundles. The parent's identity service issues a bundle of claims at run start that the parent can derive sub-agent identities from locally, without round-tripping to the identity service. The bundle has its own expiry. This trades some flexibility (the parent can only derive identities the bundle anticipates) for issuance latency.
  • Streamed issuance. The identity service is co-located with the orchestrator and issues sub-agent identities at line rate. The trade-off is that the identity service has to scale with agent activity, but each issuance is fast.

Both patterns are deployed; the choice depends on the agent stack's existing infrastructure.

Audit reconciliation across the run graph#

Every sub-agent action emits an audit row carrying the sub-agent's identity and its parent_run_id. Reconstructing a parent run's full activity means walking the run graph: the parent's actions plus every sub-agent's actions plus every sub-sub-agent's actions.

A query the security team should be able to run against the audit log: "show me every action emitted under run id X, including all sub-agents." The implementation depends on the audit store, but the schema has to support it — which is why parent_run_id is a required field, not an optional one.

A second query the security team should be able to run: "for this misbehaving action, what was the chain of decisions that led to it being spawned in the first place?" This walks the graph upward. The audit row for the sub-agent's misbehaving action carries the parent_run_id; the row for the parent's spawn-sub-agent action carries the sub-agent's id. The chain is reconstructable.

In practice, agent stacks that don't write parent_run_id early end up unable to reconstruct chains months later when an investigation lands. The cost of writing the field is one column per row; the cost of not writing it is the entire forensic path.

Sub-agent kill semantics#

The containment rules covered in Stopping a running agent extend to the sub-agent graph. When the operator stops the parent, the runtime's default is to stop every descendant sub-agent. The active-runs set is the mechanism: the parent's run id is removed, and the policy gate refuses subsequent actions for any run whose ancestor includes the stopped run.

A useful operator capability is to stop a single sub-agent without affecting the rest of the graph. The semantics: the sub-agent's run id is removed from the active set; the parent's runs continues; sibling sub-agents continue. The parent's plan now has a failed sub-agent; the parent has to decide how to proceed.

A less common but important capability is to scope a sub-agent — narrowing its identity mid-run. The mechanism is identical to the initial narrowing: the orchestrator re-derives a tighter identity and updates the sub-agent's working credential. The policy gate sees the new identity on the next action.

When to give a sub-agent a different identity#

A subtler question: should the sub-agent's identity carry the same agent_id as the parent, or a different one?

The answer depends on whether the sub-agent represents a different capability. A sub-agent spawned to summarize a document is doing the parent's work in a narrower form — same agent, narrower scope. A sub-agent spawned to call out to a third-party service the parent doesn't normally call is a different capability — the sub-agent should have a distinct agent id that the policy gate can apply different rules to.

Practical rule: the agent id is durable; the run id is per-run. If the sub-agent is doing work the policy treats as the parent's, share the agent id. If the sub-agent is doing work the policy treats differently — different action class, different risk profile — give it its own agent id and let the audit query distinguish them.

MCP context: sub-agents calling other MCP servers#

Most production agent stacks in 2026 call tools through Model Context Protocol servers, often via an MCP gateway. Sub-agents inherit this: a sub-agent that wants to call a tool talks to an MCP server. The gateway sits in front of every MCP server, evaluates the sub-agent's identity against the policy, and emits the audit row.

The key implication: the sub-agent's identity has to carry the same shape as the parent's identity, so the gateway can evaluate it with the same policy code. Identity heterogeneity across parent and sub-agents would force the gateway to maintain separate policy paths, which is operational drag.

The pattern that works: the orchestrator mints sub-agent identities in the same format the parent's identity uses, with the narrowed scope. The MCP gateway sees a token; the token has the operator behind it, the run id, the parent run id, and the scope. The gateway evaluates. The audit row is consistent across the run graph.

Closing#

The two rules — inherit the operator and the run lineage, narrow the scope and the action classes — sit in the orchestrator and the identity service. Skip the parent_run_id field on a sub-agent's audit row, and the chain from a misbehaving action back to the run that spawned it stops being reconstructable months later, when an investigation needs it.

Deixic's identity layer enforces inherit-and-narrow on every sub-agent the orchestrator spawns. See What you can do for the action-time gate the sub-agent's identity is evaluated against.