# Introducing ADCS — an open spec for agent-to-agent delegation chains

ADCS v0.1: an open JSON spec for agent delegation chains — scope intersection, budget propagation, cycle prevention, identity, audit. Ref impl shipping.

Today we're publishing **ADCS v0.1** — the [Agent Delegation Chain Specification](https://github.com/agentic-control-plane/delegation-chain-spec). It's an open spec that defines a JSON data structure and runtime semantics for the chain of agent-to-agent (A2A) hops that begins with a human and extends through autonomous agents.

Spec text: [`SPEC.md`](https://github.com/agentic-control-plane/delegation-chain-spec/blob/main/SPEC.md)
JSON Schema: [`schema/chain.schema.json`](https://github.com/agentic-control-plane/delegation-chain-spec/blob/main/schema/chain.schema.json)
Reference implementation: [Agentic Control Plane gateway](https://github.com/agentic-control-plane) (in production)
License: CC BY 4.0 (spec text), MIT (schema, examples, conformance vectors)

This post explains what the spec covers, the six design opinions baked into it, the tradeoffs each opinion accepts, and how ADCS relates to the other agent-identity work in flight.

---

## TL;DR

A2A is real now. Google's [A2A Protocol](https://a2a-protocol.org/) has 50+ launch partners and is donated to the Linux Foundation. CrewAI ships [first-class A2A delegation](https://docs.crewai.com/en/learn/a2a-agent-delegation). Anthropic's Agent SDK has subagents. OpenAI's Agents SDK has handoffs. Bedrock AgentCore models delegated identity with `Act: Agent` claims.

What's missing — and what every governance product is reinventing in incompatible ways — is the **shared data shape for the chain itself**. Who started this work? Which agents touched it? What permissions narrowed at each hop? How much budget remains? Was a cycle prevented? Today every product invents its own answer; audit logs don't compose across vendors.

ADCS is one normative answer. It's not a product. It's a JSON shape plus a small set of rules:

```json
{
  "originSub": "auth0|alice@acme.com",
  "originClaims": { "email": "alice@acme.com" },
  "links": [
    {
      "agentProfileId": "strategy-orchestrator",
      "agentRunId": "run_orch_2026041610",
      "agentName": "Strategy orchestrator",
      "effectiveScopes": ["web.*", "internal-research.delegate"],
      "effectiveTools": ["web_search", "research.delegate"],
      "remainingBudgetCents": 350,
      "delegatedAt": "2026-04-16T10:00:00Z"
    },
    {
      "agentProfileId": "remote-researcher",
      "agentRunId": "run_res_2026041611",
      "agentName": "Remote researcher (CrewAI A2A)",
      "effectiveScopes": ["web.*"],
      "effectiveTools": ["web_search", "hn_search"],
      "remainingBudgetCents": 100,
      "delegatedAt": "2026-04-16T10:01:23Z"
    }
  ],
  "depth": 2
}
```

That's the load-bearing artifact. The rest of the spec defines how `links[]` grows safely — what gets intersected, what gets propagated, what's prevented, what's audited.

---

## Why we wrote it

We've been building [Agentic Control Plane](https://agenticcontrolplane.com), a governance product for AI agents. Production customers were asking us a question we couldn't answer cleanly: *"What's the data shape for your delegation chain audit? Will my SIEM be able to correlate across agent vendors?"* The honest answer was "our shape, and not yet."

That's a procurement objection. It also became a strategy decision. Either we keep our chain shape internal — fine for our customers, but it leaves the audit surface vendor-locked — or we publish it as a spec and bet that other tools converge on it.

The **state of the art** when we surveyed it (April 2026) is fragmented:

- Google's **[A2A Protocol](https://a2a-protocol.org/latest/specification/)** explicitly punts authorization to higher layers: *"A2A does not define how the authorization must be performed."* Real spec, real adoption — leaves the chain hole open.
- Anthropic's **[MCP](https://modelcontextprotocol.io/specification/2025-11-25)** and its [authorization spec](https://modelcontextprotocol.io/specification/draft/basic/authorization) cover tool calls between an agent and a tool. Sub-agent behavior is host-side and out of scope.
- IETF **[OAuth Token Exchange (RFC 8693)](https://www.rfc-editor.org/rfc/rfc8693.html)** introduced the `act` claim and nested actor representation in 2020. Closest existing primitive. Doesn't cover budget, doesn't define agent-typed identity, doesn't have audit emission requirements.
- IETF **[Transaction Tokens (draft)](https://datatracker.ietf.org/doc/draft-ietf-oauth-transaction-tokens/)** adds monotonic scope reduction across call chains. Real WG item. Sibling [`for-agents`](https://datatracker.ietf.org/doc/draft-oauth-transaction-tokens-for-agents/) draft retargets it for AI. Compatible with ADCS — we're a profile of the same idea.
- **[Macaroons](https://research.google/pubs/pub41892/)** (Google, 2014) and **[Biscuits](https://doc.biscuitsec.org/)** (Eclipse) provide capability tokens with cryptographic attenuation. The right cryptographic envelope; the wrong layer for a JSON data shape standard.
- **[OIDC-A](https://arxiv.org/abs/2509.25974)** (arxiv preprint, Sep 2025) — defines `delegator_sub` and `delegation_chain` claims with OIDC branding. One author, GitHub repo, no working group. Worth acknowledging; not yet a standard.
- **[Agent Identity Protocol](https://arxiv.org/abs/2603.24775)** (arxiv preprint) — uses Biscuit + Datalog for chained delegations. Mathematically powerful; targeted at academic / advanced users.
- **[Authenticated Delegation paper](https://arxiv.org/abs/2501.09674)** (MIT/Anthropic, Jan 2025) — motivates the need; frames the gap. Doesn't ship a normative wire format.
- AWS **[Bedrock AgentCore](https://aws.amazon.com/blogs/security/securing-ai-agents-with-amazon-bedrock-agentcore-identity/)** uses RFC 8693 `Act: Agent` claims internally. Vendor-specific.

**Nothing real covers identity propagation + scope narrowing + budget + chain shape + open schema, all together.** That's the gap.

---

## The six design opinions

ADCS is opinionated. Opinions are how a spec creates leverage — a spec without opinions describes data; a spec with opinions describes behavior. Here are the six load-bearing opinions, with honest tradeoffs.

### 1. `originSub` is invariant

The human at the root of the chain MUST NOT change at any depth. Every hop preserves `originSub` and `originClaims` exactly.

**Why we picked this.** Auditability is a one-question test: *can you trace this action to a single accountable human?* The invariant guarantees yes, structurally. There's no clever delegation trick that loses the human.

**Tradeoff we accept.** Some delegation models want "actor replaces principal" semantics — *"I'm acting as the role I just delegated to."* That's useful for some authorization patterns (Kubernetes RBAC for example uses `impersonate`). ADCS rejects this in favor of preservation; if you need impersonation, you create a new chain.

### 2. Scope and tool narrowing is set intersection

A child agent's effective permissions = `intersect(parent_effective, child_profile)`. Permissions can only narrow.

**Why we picked this.** Set intersection is the strictest possible interpretation of least-privilege. Wildcard support (`github.*`) keeps it ergonomic; the result is mechanically auditable — for any chain, you can prove what each link can and cannot do.

**Tradeoff we accept.** OAuth Transaction Tokens use *"scope of the token is equal or less than the scope of the subject_token"* — a string-subset rule that's slightly looser. ADCS's set-intersection is strictly stronger but rejects some patterns (e.g., parent says `github.*`, child profile says `github.repos.read` — Transaction Token allows it; ADCS allows it too via wildcard match). The cases that diverge are obscure and we judged the strictness worth the simplicity.

### 3. Budget propagation is a first-class field

`child_budget = min(parent_remaining, child_max)`. When a child's budget hits zero, its tool calls are rejected with a structured error.

**Why we picked this.** Runaway loops in deep multi-agent chains are the #1 production failure mode we've seen. Bounding them at the data-structure level — not at a separate rate-limiter, not at a model-side sampling parameter — is cheap, load-bearing, and impossible to forget.

**Tradeoff we accept.** Nobody else has this. We're inventing primary art. Budget-as-cents is also opinionated: it assumes a cost model. Some teams want budget-as-tokens, budget-as-time, or budget-as-API-calls. v1.0 may add a typed `BudgetUnit` enum; v0.1 commits to cents because most LLM cost reasoning happens in dollars and integer cents avoids floating-point. **Honest call:** if your governance pillar is rate limiting, not cost, you may find this field over-specific. We think the cost framing is more universally useful and includes rate-limiting as a special case (set max_budget at zero past N calls).

### 4. Type identity (`agentProfileId`) is distinct from runtime identity (`agentRunId`)

Audit logs need to correlate the calls of *this specific execution*, not just *calls by any instance of agent X*.

**Why we picked this.** Two parallel runs of the same agent — call them researcher-instance-A and researcher-instance-B — should produce two distinct chains. If your audit log conflates them, you can't reconstruct what happened in a multi-tenant or high-concurrency setting.

**Tradeoff we accept.** Two identifiers per link is more verbose than one. OIDC-A's `delegator_sub` collapses these into one claim. We chose verbosity for forensic clarity. **Honest call:** for single-tenant deployments with no concurrency, one identifier would suffice. Most production deployments aren't single-tenant.

### 5. Cycle prevention is "target appears in chain", not just depth limit

An agent MUST NOT delegate to a `agentProfileId` that already appears anywhere in the current chain.

**Why we picked this.** Depth-limiting bounds compute cost. Cycle prevention bounds *reasoning loops*. They're different failure modes — an agent that re-invokes itself through three intermediaries can still be shallow but pathological. ADCS catches it at the structural level.

**Tradeoff we accept.** This rule is strict. It prevents legitimate patterns like "supervisor → coder → supervisor → tester" where the supervisor is the orchestrator that explicitly fans-out and fans-in. To support that pattern, you'd need a supervisor profile that's marked as a coordinator — and then either two profile IDs (orchestrator + worker) or an exception clause. v0.1 keeps the strict rule; v0.2 may add an opt-in `coordinator: true` flag. **Honest call:** if your topology is supervisor-centric, this rule will bite you. The workaround is to model the supervisor as a profile distinct from the workers it coordinates.

### 6. JSON-first, not Datalog-first

The spec specifies a JSON data shape. Cryptographic envelopes (Biscuit, JWT) are optional; the data is the contract.

**Why we picked this.** A delegation chain has multiple audiences: SOC analysts reading audit logs, junior engineers debugging an integration, compliance officers running queries against SIEM exports, AI-driven incident-response copilots reasoning about the chain. JSON is the lowest-friction shape that all of them can read. The Agent Identity Protocol uses Biscuit + Datalog; that's mathematically more expressive but excludes most of those audiences without specialized tooling.

**Tradeoff we accept.** JSON is unsigned. Anyone with write access to the audit log could fabricate a chain. ADCS spec text addresses this in §10 — *"Implementations MAY transmit chains in any envelope... When transport over an untrusted channel is required, implementations SHOULD use a signed envelope (JWT or Biscuit) so each link can be cryptographically verified."* The data shape is decoupled from the cryptographic verification layer; both can exist. **Honest call:** if your threat model includes a malicious gateway, you need the Biscuit envelope. ADCS doesn't mandate it because most threat models don't.

---

## How ADCS relates to other specs

| Spec | Covers | What ADCS adds | Relationship |
|---|---|---|---|
| [A2A Protocol](https://a2a-protocol.org/) | Transport, discovery, capability negotiation | Chain semantics A2A explicitly leaves to a higher layer | **Layers on top.** A2A invocation MAY carry an ADCS chain in a header or message-part. |
| [MCP](https://modelcontextprotocol.io/) | Tool invocation between agent and tool | Chain context that wraps each MCP call | **Wraps MCP.** Every governed MCP `tools/call` emits an ADCS audit entry. |
| [RFC 8693 OAuth Token Exchange](https://www.rfc-editor.org/rfc/rfc8693.html) | Nested `act` claims for delegation | Scope intersection + budget + tool sets + runtime identity | **Profile of.** ADCS chains MAY be expressed as JWTs with nested `act`. |
| [OAuth Transaction Tokens](https://datatracker.ietf.org/doc/draft-ietf-oauth-transaction-tokens/) | Scope monotonic reduction across call chains | Set-intersection (stricter), budget, agent-typed identity | **Strictly stronger** intersection rule + budget. |
| [Macaroons / Biscuits](https://doc.biscuitsec.org/) | Capability tokens with cryptographic attenuation | Standardized JSON shape for the chain payload | **Compatible envelope.** ADCS chains MAY be wrapped in Biscuit. |
| [OIDC-A](https://arxiv.org/abs/2509.25974) | `delegator_sub` + `delegation_chain` claim names | Concrete data shape, budget, runtime identity, conformance vectors | **Acknowledges as prior art**, chooses different vocabulary to avoid OIDC namespace collision. |
| [Agent Identity Protocol](https://arxiv.org/abs/2603.24775) | IBCTs with Biscuit + Datalog | JSON-first, simpler audit shape, budget propagation | **Sister spec.** Different design choices for different audiences. |
| [OpenTelemetry GenAI semconv](https://opentelemetry.io/docs/specs/semconv/gen-ai/) | Span attributes for agent invocation | Chain-level attributes the semconv doesn't cover yet | **Emits to.** ADCS audit entries map to OTel attributes. |

ADCS is one piece of the agent governance puzzle. It does not specify how agents authenticate, how they discover each other, or how they execute. It specifies the chain that records what happened, with the small set of rules that make the chain composable across vendors.

---

## Reference implementation

The reference implementation is the Agentic Control Plane gateway, in production today:

- [`delegation.ts`](https://github.com/agentic-control-plane) — `intersectScopes`, `intersectTools`, `computeChildBudget`, `detectCycle`, `buildChildChain`. This is the file the spec was reverse-extracted from.
- [`hookGovernance.ts`](https://github.com/agentic-control-plane) — the four-layer policy merge (workspace → role → agentType → user) with chain context.
- [`mcp/logging.ts`](https://github.com/agentic-control-plane) — audit emission with the chain serialized into every entry.

Conformance test vectors at [`conformance/`](https://github.com/agentic-control-plane/delegation-chain-spec/tree/main/conformance) verify the reference implementation produces the documented output for every operation. Other implementations should pass the same vectors.

---

## Versioning

- **v0.1.x** — early adopter implementations and feedback. Field names and semantics may shift as implementers report what's awkward. Conformance vectors expand.

---

## How to participate

We're seeking implementer feedback. Open an issue on [`agentic-control-plane/delegation-chain-spec`](https://github.com/agentic-control-plane/delegation-chain-spec) with:

- A use case ADCS doesn't yet cover
- An ambiguity in the spec text
- A field name you'd argue against
- A normative semantic you'd argue for
- An implementation report — *"we built ADCS in [language] — here's what was hard"*

If you're at one of the agent-governance vendors (Aembit, Cyata, Astrix, Zenity, Salt, Noma, Skyrelis, Tenet, Aiceberg, Singulr, KonaSense, SurePath, etc.), we'd especially value feedback. None of you currently publish a chain schema. If ADCS is the right shape, adopting it costs you nothing and gives the industry a common artifact. If it's not, the public issue is the place to make the case.

---

## What this changes for ACP

For us specifically, this changes the conversation. ACP is no longer just a governance product — it's the reference implementation of a public spec. That changes how we engage with enterprise procurement (*"we follow our own published spec, here's the JSON Schema"*), how we engage with auditors (*"the chain shape is normative"*), and how we engage with the rest of the agent-tooling ecosystem (*"adopt this if you want our customers' SIEM exports to compose with yours"*).

If you're shipping multi-agent systems to production, the conversation changes for you too: you can ask vendors *"do you implement ADCS?"* and have a concrete answer to evaluate. Today the question doesn't have an answer because no vendor publishes a chain schema. We'd like that to change.

---

## Links

- **Spec:** [github.com/agentic-control-plane/delegation-chain-spec](https://github.com/agentic-control-plane/delegation-chain-spec)
- **Reference implementation:** [github.com/agentic-control-plane](https://github.com/agentic-control-plane) (look for `delegation.ts`)
- **Agentic Control Plane:** [agenticcontrolplane.com](https://agenticcontrolplane.com)
- **Earlier writing:** [Agent-to-agent governance deep dive](/agent-to-agent), [Three-axis governance model](/three-axis-governance), [Governing CrewAI A2A: a production setup guide](/blog/crewai-a2a-delegation-production-setup)
- **Contact:** [david@reducibl.com](mailto:david@reducibl.com)

Spec is at v0.1.0 and explicitly draft. Field names and semantics MAY change before v1.0. We're shipping this now because the category is forming and we'd rather have one good shared shape than five proprietary ones.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "TechArticle",
  "headline": "Introducing ADCS — an open spec for agent-to-agent delegation chains",
  "description": "ADCS v0.1 defines a JSON data structure and runtime semantics for agent delegation chains: scope intersection, budget propagation, cycle prevention, identity preservation, and audit emission.",
  "datePublished": "2026-04-16",
  "dateModified": "2026-04-16",
  "author": {"@type": "Person", "name": "David Crowe", "url": "https://reducibl.com"},
  "publisher": {"@type": "Organization", "name": "Agentic Control Plane", "url": "https://agenticcontrolplane.com"},
  "mainEntityOfPage": "https://agenticcontrolplane.com/blog/introducing-adcs-delegation-chain-spec",
  "keywords": "delegation chain spec, agent-to-agent governance, A2A delegation chain, scope narrowing agents, agent budget propagation, cycle detection agents, agent identity propagation, AI agent governance standard, ADCS",
  "articleSection": "Specification",
  "proficiencyLevel": "Expert",
  "dependencies": "OAuth 2.0, RFC 8693, JWT"
}
</script>

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "DefinedTermSet",
  "name": "Agent Delegation Chain Specification (ADCS) v0.1",
  "description": "Vocabulary for agent-to-agent delegation chain governance.",
  "hasDefinedTerm": [
    {"@type": "DefinedTerm", "name": "Delegation Chain", "description": "A JSON data structure recording the human at the root of the chain plus an ordered array of agent hops, each carrying its effective scopes, effective tools, remaining budget, and runtime identifier."},
    {"@type": "DefinedTerm", "name": "Origin Principal", "description": "A natural person, service account, or non-agent identity that initiated the work an agent is performing. Identified by originSub. Invariant for the lifetime of the chain."},
    {"@type": "DefinedTerm", "name": "Scope Narrowing", "description": "The rule that a child agent's effective permissions are computed as the set intersection of its parent's effective permissions and its own profile permissions. Permissions can only narrow through a chain, never widen."},
    {"@type": "DefinedTerm", "name": "Budget Propagation", "description": "The rule that a child agent's remaining budget = min(parent's remaining, child's max). Bounds runaway loops in deep multi-agent chains."},
    {"@type": "DefinedTerm", "name": "Cycle Detection", "description": "Prevention of agent A delegating to a target agent whose profile ID already appears anywhere in the current delegation chain. Bounds reasoning loops, not just compute depth."},
    {"@type": "DefinedTerm", "name": "Agent Type Identity", "description": "A stable identifier (agentProfileId) for the configuration that defines an agent. Multiple runs of the same logical agent share an agentProfileId."},
    {"@type": "DefinedTerm", "name": "Agent Runtime Identity", "description": "A unique-per-execution identifier (agentRunId) distinct from agentProfileId. Allows audit logs to correlate the calls of one specific run."}
  ]
}
</script>
