← Blog

Identity & access · · 7 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: one 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 and returning results to the parent.

Fan-out exists for performance: serializing the steps doubles or triples user-visible latency. It also complicates identity, because each sub-agent acts on someone's behalf and that 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, reach data the parent could not reach, or escalate to a privilege the parent doesn't hold. The orchestrator that spawns it does the narrowing.

A child identity stays inside its parent's scope

  1. Keep attribution

    Preserve the operator and record the parent-child relationship.

  2. Limit resources

    Intersect the parent's scope with the child's specific task.

  3. Limit actions

    A read task does not inherit unnecessary write permissions.

  4. Expire access

    The child credential ends with the work it was issued for.

The orchestrator derives the identity; the policy gate verifies the narrowed scope. Delegation cannot expand the parent's authority. Source: this article.
Download figure

Why sub-agents exist#

Four patterns drive fan-out:

  • Parallel retrieval. The agent needs context from multiple sources. One sub-agent per source returns results in max time instead of sum time.
  • Specialization. Summarizing one document or extracting one field suits a cheaper model than the expensive top-level reasoning model.
  • 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, so a misbehaving sub-agent has a small blast radius.
  • Independent step retry. A parent step can fail. Spawning a sub-agent for it lets the parent's loop retry without rolling back its own state.

The identity layer lags these architectures. Many production stacks hand the parent's full credential to every sub-agent, so a misbehaving sub-agent can do everything the parent could, including things outside 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 is authorized to reach, the action classes it can invoke, and the run context the policy needs (the support ticket id, the customer id, the repository name).

Model it as a verifiable credential the runtime mints at run start, signed by the identity service, with the scope embedded as claims. It expires when the run ends. The orchestrator carries it and presents it to the policy gate on each action.

What narrowing means#

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

  • The sub-agent inherits the operator behind the parent's run.
  • 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 and the sub-agent was spawned to summarize one document, the sub-agent's scope is that 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, whether or not the parent had them.
  • The sub-agent's identity expires when the sub-agent's task completes, not when the parent's run ends.

Concretely, a parent identity carries 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, and 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 and expiry, each registered with the policy gate. At tens of thousands of runs per day, each fanning out, the identity-issuance rate becomes a system load characteristic.

Issuance has to be fast (tens of milliseconds per identity, per the latency budget in Why service-account permissions don't fit agents) and reliable, because a sub-agent without an identity can't act and the parent's plan stalls.

Two implementation patterns scale:

  • Pre-issued claim bundles. The identity service issues a bundle of claims at run start, and the parent derives sub-agent identities from it locally without a round trip. The bundle has its own expiry. It trades 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 identity service has to scale with agent activity, but each issuance is fast.

Both patterns are deployed; the choice follows the 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, every sub-agent's actions, and every sub-sub-agent's actions.

The security team needs two queries against the audit log:

  • "Show me every action emitted under run id X, including all sub-agents." The schema has to support this, which is why parent_run_id is a required field.
  • "For this misbehaving action, what chain of decisions led to it being spawned?" This walks the graph upward. The sub-agent's audit row carries the parent_run_id, and the parent's spawn-sub-agent row carries the sub-agent's id, so the chain is reconstructable.

Stacks that don't write parent_run_id early cannot reconstruct chains months later when an investigation lands. The field costs one column per row; omitting it costs the entire forensic path.

Sub-agent kill semantics#

The containment rules 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.

Operators also need to stop a single sub-agent without affecting the rest of the graph. Its run id is removed from the active set while the parent and sibling sub-agents continue, and the parent's plan has to handle the failed sub-agent.

Narrowing a sub-agent mid-run is less common. The orchestrator re-derives a tighter identity and updates the working credential; the policy gate sees it on the next action.

When to give a sub-agent a different identity#

Whether the sub-agent carries the parent's agent_id depends on whether it represents a different capability. A sub-agent that summarizes a document does the parent's work in a narrower form: same agent, narrower scope. A sub-agent that calls a third-party service the parent doesn't normally call is a different capability, and it should have a distinct agent id so the policy gate can apply different rules.

The agent id is durable and the run id is per-run. If policy treats the sub-agent's work as the parent's, share the agent id. If it treats it differently (different action class, different risk profile), give it its own agent id so audit queries can 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 that sits in front of every server, evaluates the sub-agent's identity against the policy, and emits the audit row.

Sub-agent identities need the parent's shape so the gateway can evaluate them with the same policy code; separate formats would force separate policy paths. The orchestrator therefore mints sub-agent identities in the parent's format with the narrowed scope. The gateway sees a token carrying the operator, the run id, the parent run id, and the scope, and the audit row stays consistent across the run graph.

Closing#

The two rules sit in the orchestrator and the identity service: inherit the operator and run lineage, narrow the scope and action classes. 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 can no longer be reconstructed months later, when an investigation needs it.

Deixic applies policy and approval to sensitive actions for calls routed through it and keeps a tamper-evident history of decisions and results. See What you can do for those controls.

Share this article

A child agent inherits attribution and receives only the scope its task needs.

Download images and slides

The four slides follow the article’s reading guide. Each image includes Deixic attribution.