# What is an Agent Delegation Chain?

An agent delegation chain is the ordered record of every agent hop, carrying identity, scope, budget, and audit at each link. The primitive behind A2A.

# What Is an Agent Delegation Chain?

An **agent delegation chain** is the ordered record of every agent hop from the human who initiated a task down to the agent currently acting. Each link in the chain carries the agent's identity, its narrowed scope, its remaining budget, and the tools it's permitted to use. The chain lets every downstream system answer two questions every request should already be answering: *who originally asked for this, and under what authority is this agent acting on their behalf right now?*

<div style="margin:36px 0 24px;overflow-x:auto;max-width:100%;">
  <svg viewBox="0 0 980 380" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Hero diagram: an agent delegation chain from human through three agents to a tool, showing narrowing scopes and decreasing budgets" style="width:100%;max-width:980px;display:block;margin:0 auto;font-family:system-ui,sans-serif;">
    <defs>
      <marker id="dc-arrow" markerWidth="10" markerHeight="7" refX="10" refY="3.5" orient="auto">
        <polygon points="0 0, 10 3.5, 0 7" fill="#5b5bd6"/>
      </marker>
      <linearGradient id="dc-scope-grad" x1="0" x2="1" y1="0" y2="0">
        <stop offset="0" stop-color="#5b5bd6"/>
        <stop offset="1" stop-color="#0891b2"/>
      </linearGradient>
    </defs>
    <!-- originSub persistent line -->
    <line x1="100" y1="330" x2="880" y2="330" stroke="#0ea472" stroke-width="1.5" stroke-dasharray="6,4"/>
    <text x="490" y="358" text-anchor="middle" font-size="10" font-weight="600" fill="#0ea472">originSub = alice@acme.com · invariant across every hop</text>
    <!-- Human node -->
    <rect x="40" y="80" width="140" height="60" rx="10" fill="#ffffff" stroke="#1d1d1f" stroke-width="2"/>
    <text x="110" y="100" text-anchor="middle" font-size="11" font-weight="700" fill="#1d1d1f">HUMAN</text>
    <text x="110" y="117" text-anchor="middle" font-size="10" fill="#4a4a52">alice@acme.com</text>
    <text x="110" y="131" text-anchor="middle" font-size="9" fill="#8a8a9a">authenticated via JWT</text>
    <circle cx="110" cy="330" r="5" fill="#0ea472"/>
    <text x="110" y="160" text-anchor="middle" font-size="9" font-weight="600" fill="#0ea472">root</text>
    <!-- Arrow 1 -->
    <line x1="182" y1="110" x2="235" y2="110" stroke="#5b5bd6" stroke-width="2" marker-end="url(#dc-arrow)"/>
    <!-- Agent A -->
    <rect x="240" y="80" width="140" height="60" rx="10" fill="#f0effe" stroke="#5b5bd6" stroke-width="1.5"/>
    <text x="310" y="100" text-anchor="middle" font-size="11" font-weight="700" fill="#5b5bd6">Agent A</text>
    <text x="310" y="117" text-anchor="middle" font-size="10" fill="#4a4a52">supervisor</text>
    <text x="310" y="131" text-anchor="middle" font-size="9" fill="#8a8a9a">agentRunId: r_84af…</text>
    <circle cx="310" cy="330" r="5" fill="#0ea472"/>
    <line x1="310" y1="140" x2="310" y2="325" stroke="#0ea472" stroke-width="1" stroke-dasharray="2,2" opacity="0.5"/>
    <!-- Scope bubble above A -->
    <rect x="240" y="28" width="140" height="42" rx="6" fill="#ffffff" stroke="#b8b8dc"/>
    <text x="310" y="43" text-anchor="middle" font-size="9" font-weight="600" fill="#5b5bd6">SCOPES</text>
    <text x="310" y="58" text-anchor="middle" font-size="9" fill="#1d1d1f">crm.read · crm.write · slack.post</text>
    <!-- Budget bar below A -->
    <rect x="255" y="165" width="110" height="10" rx="3" fill="#e0f7fb"/>
    <rect x="255" y="165" width="110" height="10" rx="3" fill="#0891b2" opacity="0.9"/>
    <text x="310" y="190" text-anchor="middle" font-size="9" font-weight="600" fill="#0891b2">$1000 remaining</text>
    <!-- Arrow 2 -->
    <line x1="382" y1="110" x2="435" y2="110" stroke="#5b5bd6" stroke-width="2" marker-end="url(#dc-arrow)"/>
    <text x="408" y="100" text-anchor="middle" font-size="8" font-weight="600" fill="#5b5bd6">delegate</text>
    <text x="408" y="124" text-anchor="middle" font-size="8" fill="#dc2626">∩</text>
    <!-- Agent B -->
    <rect x="440" y="80" width="140" height="60" rx="10" fill="#f0effe" stroke="#5b5bd6" stroke-width="1.5"/>
    <text x="510" y="100" text-anchor="middle" font-size="11" font-weight="700" fill="#5b5bd6">Agent B</text>
    <text x="510" y="117" text-anchor="middle" font-size="10" fill="#4a4a52">researcher</text>
    <text x="510" y="131" text-anchor="middle" font-size="9" fill="#8a8a9a">agentRunId: r_19bc…</text>
    <circle cx="510" cy="330" r="5" fill="#0ea472"/>
    <line x1="510" y1="140" x2="510" y2="325" stroke="#0ea472" stroke-width="1" stroke-dasharray="2,2" opacity="0.5"/>
    <!-- Scope bubble above B - narrower -->
    <rect x="440" y="28" width="140" height="42" rx="6" fill="#ffffff" stroke="#b8b8dc"/>
    <text x="510" y="43" text-anchor="middle" font-size="9" font-weight="600" fill="#5b5bd6">SCOPES</text>
    <text x="510" y="58" text-anchor="middle" font-size="9" fill="#1d1d1f">crm.read</text>
    <!-- Budget bar -->
    <rect x="455" y="165" width="110" height="10" rx="3" fill="#e0f7fb"/>
    <rect x="455" y="165" width="60" height="10" rx="3" fill="#0891b2" opacity="0.9"/>
    <text x="510" y="190" text-anchor="middle" font-size="9" font-weight="600" fill="#0891b2">$500 remaining</text>
    <!-- Arrow 3 -->
    <line x1="582" y1="110" x2="635" y2="110" stroke="#5b5bd6" stroke-width="2" marker-end="url(#dc-arrow)"/>
    <text x="608" y="100" text-anchor="middle" font-size="8" font-weight="600" fill="#5b5bd6">delegate</text>
    <text x="608" y="124" text-anchor="middle" font-size="8" fill="#dc2626">∩</text>
    <!-- Agent C -->
    <rect x="640" y="80" width="140" height="60" rx="10" fill="#f0effe" stroke="#5b5bd6" stroke-width="1.5"/>
    <text x="710" y="100" text-anchor="middle" font-size="11" font-weight="700" fill="#5b5bd6">Agent C</text>
    <text x="710" y="117" text-anchor="middle" font-size="10" fill="#4a4a52">summarizer</text>
    <text x="710" y="131" text-anchor="middle" font-size="9" fill="#8a8a9a">agentRunId: r_ff2e…</text>
    <circle cx="710" cy="330" r="5" fill="#0ea472"/>
    <line x1="710" y1="140" x2="710" y2="325" stroke="#0ea472" stroke-width="1" stroke-dasharray="2,2" opacity="0.5"/>
    <!-- Scope bubble above C - narrower -->
    <rect x="640" y="28" width="140" height="42" rx="6" fill="#ffffff" stroke="#b8b8dc"/>
    <text x="710" y="43" text-anchor="middle" font-size="9" font-weight="600" fill="#5b5bd6">SCOPES</text>
    <text x="710" y="58" text-anchor="middle" font-size="9" fill="#1d1d1f">crm.read (account only)</text>
    <!-- Budget bar -->
    <rect x="655" y="165" width="110" height="10" rx="3" fill="#e0f7fb"/>
    <rect x="655" y="165" width="22" height="10" rx="3" fill="#0891b2" opacity="0.9"/>
    <text x="710" y="190" text-anchor="middle" font-size="9" font-weight="600" fill="#0891b2">$200 remaining</text>
    <!-- Arrow 4 -->
    <line x1="782" y1="110" x2="835" y2="110" stroke="#5b5bd6" stroke-width="2" marker-end="url(#dc-arrow)"/>
    <!-- Tool call -->
    <rect x="840" y="80" width="130" height="60" rx="10" fill="#ffffff" stroke="#1d1d1f" stroke-width="2"/>
    <text x="905" y="100" text-anchor="middle" font-size="11" font-weight="700" fill="#1d1d1f">TOOL</text>
    <text x="905" y="117" text-anchor="middle" font-size="10" fill="#4a4a52">crm.read</text>
    <text x="905" y="131" text-anchor="middle" font-size="9" fill="#8a8a9a">acctId=12345</text>
    <circle cx="905" cy="330" r="5" fill="#0ea472"/>
    <!-- Labels for annotations -->
    <text x="310" y="218" text-anchor="middle" font-size="10" font-weight="600" fill="#4a4a52">narrowing scope</text>
    <text x="310" y="232" text-anchor="middle" font-size="9" fill="#8a8a9a">each hop intersects</text>
    <text x="510" y="218" text-anchor="middle" font-size="10" font-weight="600" fill="#4a4a52">narrowing scope</text>
    <text x="510" y="232" text-anchor="middle" font-size="9" fill="#8a8a9a">crm.write dropped</text>
    <text x="710" y="218" text-anchor="middle" font-size="10" font-weight="600" fill="#4a4a52">further narrowing</text>
    <text x="710" y="232" text-anchor="middle" font-size="9" fill="#8a8a9a">account-scoped only</text>
    <!-- Budget trend annotation -->
    <rect x="40" y="250" width="200" height="60" rx="8" fill="#e0f7fb" stroke="#0891b2"/>
    <text x="140" y="268" text-anchor="middle" font-size="10" font-weight="700" fill="#0891b2">BUDGET PROPAGATES</text>
    <text x="140" y="282" text-anchor="middle" font-size="9" fill="#4a4a52">$1000 → $500 → $200</text>
    <text x="140" y="296" text-anchor="middle" font-size="9" fill="#4a4a52">child ≤ parent remaining</text>
    <text x="140" y="305" text-anchor="middle" font-size="9" fill="#8a8a9a" font-style="italic">never increases</text>
    <!-- Audit annotation -->
    <rect x="260" y="250" width="200" height="60" rx="8" fill="#fff5f5" stroke="#dc2626" stroke-opacity="0.4"/>
    <text x="360" y="268" text-anchor="middle" font-size="10" font-weight="700" fill="#dc2626">CYCLES FORBIDDEN</text>
    <text x="360" y="282" text-anchor="middle" font-size="9" fill="#4a4a52">no agent appears twice</text>
    <text x="360" y="296" text-anchor="middle" font-size="9" fill="#4a4a52">detected at delegation time</text>
    <text x="360" y="305" text-anchor="middle" font-size="9" fill="#8a8a9a" font-style="italic">A → B → A = rejected</text>
    <!-- Audit emit -->
    <rect x="480" y="250" width="200" height="60" rx="8" fill="#f0effe" stroke="#5b5bd6"/>
    <text x="580" y="268" text-anchor="middle" font-size="10" font-weight="700" fill="#5b5bd6">EVERY HOP AUDITED</text>
    <text x="580" y="282" text-anchor="middle" font-size="9" fill="#4a4a52">structured audit record</text>
    <text x="580" y="296" text-anchor="middle" font-size="9" fill="#4a4a52">parentAgentRunId linked</text>
    <text x="580" y="305" text-anchor="middle" font-size="9" fill="#8a8a9a" font-style="italic">full chain queryable</text>
    <!-- Chain depth -->
    <rect x="700" y="250" width="200" height="60" rx="8" fill="#ffffff" stroke="#b8b8dc"/>
    <text x="800" y="268" text-anchor="middle" font-size="10" font-weight="700" fill="#1d1d1f">BOUNDED DEPTH</text>
    <text x="800" y="282" text-anchor="middle" font-size="9" fill="#4a4a52">plan-capped (4–8 hops)</text>
    <text x="800" y="296" text-anchor="middle" font-size="9" fill="#4a4a52">deeper → flatten topology</text>
    <text x="800" y="305" text-anchor="middle" font-size="9" fill="#8a8a9a" font-style="italic">prevents runaway</text>
  </svg>
  <div style="text-align:center;font-size:12px;color:#8a8a9a;margin-top:8px;font-style:italic;">A delegation chain: originSub persists; scopes narrow at each hop; budget propagates but never increases; every link is audited.</div>
</div>

---

## The Short Version

In a single-agent system, identity is easy: a human authenticates, their JWT rides every request, and the backend verifies it. Simple.

In a multi-agent system, identity is hard. The human starts the run; then agent A delegates to agent B; then agent B calls agent C; then agent C makes a tool call. By the time the tool call reaches a real backend system, *four* parties are involved — but typically only one identity is attached: a shared service account or API key.

A delegation chain fixes this. It's a data structure that carries:

- **originSub** — the human at the root. Never changes through any hop.
- **A list of links** — one per agent, in order. Each link records: agent name, effective scopes, effective tools, remaining budget, timestamp.
- **Invariants** — scopes can only narrow (never widen), budgets can only decrease, cycles are forbidden, and every hop is audited.

With a delegation chain, a downstream system always knows who ultimately asked, which agent is currently acting, and whether the current agent has authority to do the specific thing it's trying to do.

---

## Why Delegation Chains Exist

The need for delegation chains emerged from practical pain in production multi-agent systems. Three specific problems drove the design:

**1. Over-privileged delegation.** When agent A delegates to agent B via a shared API key, agent B has the same access as agent A. If agent A could write to Salesforce, so can agent B — even if agent B was only supposed to send a Slack message. Without scope narrowing at each hop, delegation silently expands privilege.

**2. Identity loss across hops.** Audit logs in multi-agent systems routinely say "the AI did it" with no attribution to the human who initiated the work. That's fine until regulation, a security incident, or a customer complaint demands "who specifically authorized this particular action." With no delegation chain, the answer is unknowable.

**3. Cycles and unbounded delegation.** Without structural limits, an agent can delegate to another agent that delegates to another agent that delegates back to the first. Budgets don't propagate. Quotas don't decrement. Stacks get deep and costs spiral. Delegation chains bound these failure modes.

The concept isn't new in spirit — it's an extension of OAuth's on-behalf-of flow, SPIFFE's workload identity, and Kerberos-style delegation tickets. What's new is the need for it in AI agent contexts, where delegation happens at high frequency, often between autonomous agents with different scope requirements, and often across organizational boundaries.

---

## How a Delegation Chain Works

Concretely, a delegation chain is a linked list of **delegation links**. The chain starts with a human (the `originSub`) and extends by one link each time an agent delegates to another agent.

Here's a simplified view of the data structure:

```ts
interface DelegationChain {
  originSub: string;             // the human at the root — never changes
  originClaims: Record<string, unknown>;
  links: DelegationLink[];       // [0] = first agent; [last] = current agent
  depth: number;
}

interface DelegationLink {
  agentProfileId: string;        // the type of agent (what it is)
  agentRunId: string;            // this specific run (unique per invocation)
  agentName: string;
  effectiveScopes: string[];     // narrowed via scope intersection
  effectiveTools: string[];      // narrowed via tool intersection
  remainingBudgetCents: number;  // propagated from parent, never increased
  delegatedAt: string;           // ISO 8601 timestamp
  parentAgentRunId?: string;     // explicit parent link
}
```

Two invariants always hold:

1. **`originSub` never changes.** No matter how deep the chain goes, the human at the root is always recorded. You can always trace any action back to the person who started the run.

2. **Scopes only narrow; budgets only decrease; cycles are forbidden.** Each delegation link's scopes are the intersection of the parent's scopes and the child's requested scopes. Budgets propagate but never increase. Cycles are detected and rejected at delegation time.

<div style="margin:28px 0;overflow-x:auto;max-width:100%;">
  <svg viewBox="0 0 800 280" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Venn diagram: effective scopes are the intersection of parent scopes and child requested scopes" style="width:100%;max-width:800px;display:block;margin:0 auto;font-family:system-ui,sans-serif;">
    <!-- Title -->
    <text x="400" y="24" text-anchor="middle" font-size="12" font-weight="700" fill="#5b5bd6" letter-spacing="1">SCOPE INTERSECTION (RULE 2)</text>
    <text x="400" y="42" text-anchor="middle" font-size="10" fill="#4a4a52">effectiveScopes = parentScopes ∩ childRequestedScopes</text>
    <!-- Parent scope circle -->
    <circle cx="280" cy="150" r="95" fill="#5b5bd6" fill-opacity="0.15" stroke="#5b5bd6" stroke-width="2"/>
    <text x="220" y="95" font-size="11" font-weight="700" fill="#5b5bd6">PARENT SCOPES</text>
    <text x="200" y="115" font-size="10" fill="#1d1d1f">crm.read</text>
    <text x="200" y="130" font-size="10" fill="#1d1d1f">crm.write</text>
    <text x="200" y="145" font-size="10" fill="#1d1d1f">slack.post</text>
    <!-- Child requested circle -->
    <circle cx="460" cy="150" r="95" fill="#0891b2" fill-opacity="0.15" stroke="#0891b2" stroke-width="2"/>
    <text x="480" y="95" font-size="11" font-weight="700" fill="#0891b2">CHILD REQUESTED</text>
    <text x="510" y="115" font-size="10" fill="#1d1d1f">crm.read</text>
    <text x="510" y="130" font-size="10" fill="#1d1d1f">github.pr</text>
    <text x="510" y="145" font-size="10" fill="#1d1d1f">jira.create</text>
    <!-- Intersection highlight -->
    <text x="370" y="155" text-anchor="middle" font-size="13" font-weight="700" fill="#0ea472">crm.read</text>
    <text x="370" y="172" text-anchor="middle" font-size="9" fill="#0ea472" font-weight="600">✓ EFFECTIVE</text>
    <!-- Denied scopes annotation -->
    <text x="160" y="240" text-anchor="middle" font-size="10" font-weight="600" fill="#4a4a52">parent has, child didn't ask</text>
    <text x="160" y="254" text-anchor="middle" font-size="9" fill="#8a8a9a" font-style="italic">crm.write · slack.post</text>
    <text x="160" y="266" text-anchor="middle" font-size="9" fill="#8a8a9a">not inherited</text>
    <line x1="160" y1="220" x2="240" y2="160" stroke="#8a8a9a" stroke-width="1" stroke-dasharray="2,2"/>
    <text x="600" y="240" text-anchor="middle" font-size="10" font-weight="600" fill="#dc2626">child asked, parent doesn't have</text>
    <text x="600" y="254" text-anchor="middle" font-size="9" fill="#dc2626" font-style="italic">github.pr · jira.create</text>
    <text x="600" y="266" text-anchor="middle" font-size="9" fill="#dc2626">REJECTED (scope widening)</text>
    <line x1="600" y1="220" x2="500" y2="160" stroke="#dc2626" stroke-width="1" stroke-dasharray="2,2"/>
    <!-- Side note: principle -->
    <rect x="680" y="110" width="110" height="90" rx="10" fill="#fff" stroke="#5b5bd6" stroke-dasharray="3,3"/>
    <text x="735" y="130" text-anchor="middle" font-size="10" font-weight="700" fill="#5b5bd6">Principle</text>
    <text x="735" y="148" text-anchor="middle" font-size="9" fill="#4a4a52">children can</text>
    <text x="735" y="161" text-anchor="middle" font-size="9" fill="#4a4a52">never widen</text>
    <text x="735" y="174" text-anchor="middle" font-size="9" fill="#4a4a52">privilege —</text>
    <text x="735" y="187" text-anchor="middle" font-size="9" fill="#4a4a52">only narrow it.</text>
  </svg>
  <div style="text-align:center;font-size:12px;color:#8a8a9a;margin-top:8px;font-style:italic;">Effective scopes are always the intersection. A child can only receive permissions the parent already has — monotonically narrowing down the chain.</div>
</div>

See [Agent-to-Agent Governance](/agent-to-agent) for the full product view, and the [ADCS open specification](/spec/delegation-chain) for the normative rules (RFC 2119 conformance language, JSON Schema, and conformance test vectors).

---

## Six Normative Rules (from the ADCS spec)

The **Agent Delegation Chain Specification (ADCS)** is Agentic Control Plane's open specification for delegation chains. It's free, MIT/CC BY 4.0, and has a reference implementation in production.

ADCS defines six normative rules every delegation chain must satisfy:

1. **Origin invariant** — `originSub` is set at chain creation and never modified.
2. **Scope intersection** — each child link's effective scopes are a subset of the parent link's effective scopes.
3. **Budget propagation** — child budget ≤ parent's remaining budget; child consumption decrements the parent.
4. **Cycle prevention** — an agent cannot appear twice in the same chain (within configured depth).
5. **Type vs runtime identity** — `agentProfileId` identifies what kind of agent; `agentRunId` identifies this specific invocation. Both matter.
6. **Audit emission** — every delegation event emits an audit record with full chain state.

The spec is implementable on top of any transport — MCP, HTTP, gRPC, A2A. You bring the plumbing; ADCS tells you what to carry.

<div style="margin:28px 0;overflow-x:auto;max-width:100%;">
  <svg viewBox="0 0 800 280" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Diagram: a delegation cycle being rejected — Agent A delegating to Agent B delegating back to Agent A" style="width:100%;max-width:800px;display:block;margin:0 auto;font-family:system-ui,sans-serif;">
    <defs>
      <marker id="cyc-arrow-ok" markerWidth="10" markerHeight="7" refX="10" refY="3.5" orient="auto">
        <polygon points="0 0, 10 3.5, 0 7" fill="#5b5bd6"/>
      </marker>
      <marker id="cyc-arrow-bad" markerWidth="10" markerHeight="7" refX="10" refY="3.5" orient="auto">
        <polygon points="0 0, 10 3.5, 0 7" fill="#dc2626"/>
      </marker>
    </defs>
    <text x="400" y="24" text-anchor="middle" font-size="12" font-weight="700" fill="#dc2626" letter-spacing="1">CYCLE PREVENTION (RULE 4)</text>
    <text x="400" y="42" text-anchor="middle" font-size="10" fill="#4a4a52">no agent may appear twice in the same chain</text>
    <!-- Agent A -->
    <rect x="80" y="100" width="130" height="60" rx="10" fill="#f0effe" stroke="#5b5bd6" stroke-width="1.5"/>
    <text x="145" y="126" text-anchor="middle" font-size="12" font-weight="700" fill="#5b5bd6">Agent A</text>
    <text x="145" y="144" text-anchor="middle" font-size="10" fill="#4a4a52">supervisor</text>
    <!-- Agent B -->
    <rect x="335" y="100" width="130" height="60" rx="10" fill="#f0effe" stroke="#5b5bd6" stroke-width="1.5"/>
    <text x="400" y="126" text-anchor="middle" font-size="12" font-weight="700" fill="#5b5bd6">Agent B</text>
    <text x="400" y="144" text-anchor="middle" font-size="10" fill="#4a4a52">delegate</text>
    <!-- Agent C -->
    <rect x="590" y="100" width="130" height="60" rx="10" fill="#f0effe" stroke="#5b5bd6" stroke-width="1.5"/>
    <text x="655" y="126" text-anchor="middle" font-size="12" font-weight="700" fill="#5b5bd6">Agent C</text>
    <text x="655" y="144" text-anchor="middle" font-size="10" fill="#4a4a52">delegate</text>
    <!-- Arrow A → B (valid) -->
    <line x1="212" y1="130" x2="330" y2="130" stroke="#5b5bd6" stroke-width="2" marker-end="url(#cyc-arrow-ok)"/>
    <text x="271" y="120" text-anchor="middle" font-size="9" fill="#5b5bd6" font-weight="600">delegate ✓</text>
    <!-- Arrow B → C (valid) -->
    <line x1="467" y1="130" x2="585" y2="130" stroke="#5b5bd6" stroke-width="2" marker-end="url(#cyc-arrow-ok)"/>
    <text x="526" y="120" text-anchor="middle" font-size="9" fill="#5b5bd6" font-weight="600">delegate ✓</text>
    <!-- Arrow C → A (cycle — rejected) -->
    <path d="M 590 145 Q 400 220 210 145" fill="none" stroke="#dc2626" stroke-width="2.5" stroke-dasharray="8,4" marker-end="url(#cyc-arrow-bad)"/>
    <text x="400" y="210" text-anchor="middle" font-size="11" font-weight="700" fill="#dc2626">✗ CYCLE DETECTED — REJECTED</text>
    <text x="400" y="226" text-anchor="middle" font-size="9" fill="#dc2626" font-style="italic">Agent A already in chain → cannot delegate back</text>
    <!-- Outcome boxes -->
    <rect x="80" y="240" width="320" height="32" rx="8" fill="#f0fdf4" stroke="#0ea472"/>
    <text x="240" y="259" text-anchor="middle" font-size="10" font-weight="600" fill="#0ea472">A → B → C : valid chain, depth = 3</text>
    <rect x="420" y="240" width="300" height="32" rx="8" fill="#fff5f5" stroke="#dc2626"/>
    <text x="570" y="259" text-anchor="middle" font-size="10" font-weight="600" fill="#dc2626">A → B → C → A : rejected at validation</text>
  </svg>
  <div style="text-align:center;font-size:12px;color:#8a8a9a;margin-top:8px;font-style:italic;">Cycles are detected when a new delegation would cause any agent to appear twice in the chain. The request is rejected before execution.</div>
</div>

---

## When You Need a Delegation Chain

You need a delegation chain any time agent A invokes agent B on behalf of a human user. In practice, that's the moment you have:

- A **supervisor/worker pattern** (common in LangGraph, CrewAI, OpenAI Agents SDK handoffs)
- **Sub-agents** (Claude Agent SDK Skills invoking sub-Skills; Claude Code subagents)
- **Tool servers that call other tool servers** (MCP server A proxying to MCP server B)
- **Cross-organizational agent invocation** (your agent calling a partner's agent)

If you have any of these patterns and you're using a shared service account or API key, you have a delegation problem waiting to produce an incident. [Agentic Control Plane](/what-is-an-agentic-control-plane) implements delegation chains directly; see the [reference architecture](/reference-architecture).

---

## Delegation Chains in the Wild

The terminology "agent delegation chain" is crystallizing across industry and research:

- **Academic grounding:** arXiv paper [*Authenticated Delegation and Authorized AI Agents*](https://arxiv.org/abs/2501.09674) (MIT/Harvard, Jan 2025) formalizes the authorization delegation problem for AI agents. A second paper — [*SentinelAgent*](https://arxiv.org/abs/2604.02767) — studies delegation-chain integrity attacks.
- **Standards activity:** IETF draft `draft-klrc-aiagent-auth-01` proposes authentication primitives for AI agents.
- **Vendor commentary:** Okta, Cloud Security Alliance, Kiteworks, and Scalekit have all published pieces using the exact phrase "delegation chain."
- **Open specification:** [ADCS (Agent Delegation Chain Specification)](/spec/delegation-chain) from Agentic Control Plane is the first open spec specifically targeting this problem, with a reference implementation.

The field is still early, but the abstraction has clearly clicked for the industry.

---

## Related Concepts

**Delegation chain vs OAuth on-behalf-of (OBO):** OAuth OBO is a single-hop delegation primitive. Delegation chains extend that to arbitrary depth, with scope/budget propagation at each hop and structural cycle prevention.

**Delegation chain vs SPIFFE workload identity:** SPIFFE solves workload identity (who is this service?). It doesn't answer "on whose behalf is this workload acting right now?" Delegation chains layer on top of SPIFFE-like workload identity.

**Delegation chain vs trace context:** OpenTelemetry trace context propagates request IDs for observability. Delegation chains propagate *authorization state*. Both are chain-shaped; they serve different audiences (dev vs compliance) and shouldn't be conflated.

**Delegation chain vs handoff:** A "handoff" (in OpenAI Agents SDK, CrewAI, LangGraph) is a transport-level event. A delegation chain is the authorization shape that should accompany every handoff.

---

## FAQ

**Is a delegation chain the same as an audit log?**
No. An audit log records what happened. A delegation chain records the *authorization context* that existed at each hop when it happened. The audit log is a readable output; the chain is the data structure enforced in real time.

**Can delegation chains work across organizations?**
Yes, with the right trust model. ADCS supports cross-organizational chains where each party signs its own links. Practical interop requires a trust-establishment protocol (mutual TLS, federated identity, or a purpose-built handshake).

**Does every agent call need a chain?**
Every agent call that runs *on behalf of a human user* needs a chain. Autonomous agents with no human delegation (e.g., scheduled background jobs that don't represent a user) operate under a service-account model, not a chain.

**How deep can a chain go?**
ACP caps delegation depth per plan — typically 4-8 hops for most workflows. Cycles are forbidden regardless of depth. If you're hitting chain-depth limits, that's usually a sign the agent topology is too deep and should be flattened.

**What happens when a chain fails validation?**
The governance layer denies the action and writes an audit entry explaining which invariant failed (cycle detected, scope widening attempted, budget exceeded, unknown parent link, etc.). The downstream system never sees the request.

**Are delegation chains related to Forrester's Agent Control Plane market?**
Yes. Forrester's announced market evaluation of the Agent Control Plane category identifies delegation-chain governance as a core capability. ACP's ADCS spec is one industry attempt to standardize how the data structure should look.

---

## Further Reading

- [ADCS — The Open Spec](/spec/delegation-chain) — normative rules, JSON Schema, conformance vectors
- [Agent-to-Agent Governance](/agent-to-agent) — the product view
- [What Is an Agentic Control Plane?](/what-is-an-agentic-control-plane) — where delegation chains fit
- [Agent Identity](/agent-identity) — the identity primitives delegation chains depend on
- [Three-Axis Governance](/three-axis-governance) — tool / agent / user policy at every link
- Blog: [EU AI Act Article 14 and AI Agent Delegation Chains](/blog/eu-ai-act-article-14-ai-agent-delegation-chains)
- Academic: [Authenticated Delegation and Authorized AI Agents](https://arxiv.org/abs/2501.09674) (arXiv 2501.09674)
- Academic: [SentinelAgent](https://arxiv.org/abs/2604.02767) (arXiv 2604.02767)

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "What Is an Agent Delegation Chain?",
  "description": "An agent delegation chain is the ordered record of every agent hop from the human who initiated a task to the agent currently acting — carrying identity, scope, budget, and audit at each link.",
  "author": {"@type": "Organization", "name": "Agentic Control Plane"},
  "publisher": {"@type": "Organization", "name": "Agentic Control Plane"}
}
</script>

