Chained Delegation

3 agents, 2 hops, attenuating scope. The token chain grows with each delegation; the leaf agent verifies the entire history before accepting the work.

SCENARIO

The 3-agent chain

Orchestrator holds the root authority. It delegates research to Researcher, who in turn delegates writing to Writer. Each hop attenuates scope. If anyone in the chain misbehaves, the leaf agent's verification catches it.

Orchestrator [research:read, write:draft, delete]
    |--> delegates to Researcher [research:read, write:draft]      (drops `delete`)
                |--> delegates to Writer [write:draft]              (drops `research:read`)

STEP 1

Mint the root authority token

from aip_core.crypto import KeyPair
from aip_token.chained import ChainedToken

orchestrator_kp = KeyPair.generate()
authority = ChainedToken.create_authority(
    issuer="aip:web:acme.com/orchestrator",
    scopes=["research:read", "write:draft", "delete"],
    budget_cents=500,
    max_depth=3,
    ttl_seconds=3600,
    keypair=orchestrator_kp,
)
print("depth:", authority.current_depth())  # 0

The authority block is signed by the orchestrator's private key. max_depth=3 caps how many delegation hops can be appended. budget_cents=500 is the total ceiling for the chain — children may set their own ceilings, but the runtime tracks aggregate spend against this.

STEP 2

Delegate to the researcher (chain grows to depth 1)

from aip_a2a import append_delegation_block

to_researcher = append_delegation_block(
    authority,
    delegator="aip:web:acme.com/orchestrator",
    delegate="aip:web:acme.com/researcher",
    scopes=["research:read", "write:draft"],   # subset of parent
    context="research-task-2026-05-08",        # required, non-empty
    budget_cents=200,                          # narrower than 500
)
print("depth:", to_researcher.current_depth())  # 1
About context: a per-task string that binds the delegation to a specific intent. A token issued for "research-task-1" is not the same authorisation as one for "research-task-2". Empty context is rejected at delegation time.

STEP 3

Researcher delegates to writer (chain grows to depth 2)

# Researcher receives the chain via metadata.aip_token, verifies it,
# then attenuates further:

to_writer = append_delegation_block(
    to_researcher,
    delegator="aip:web:acme.com/researcher",
    delegate="aip:web:acme.com/writer",
    scopes=["write:draft"],          # drops research:read
    context="draft-summary",
    budget_cents=50,
)
print("depth:", to_writer.current_depth())  # 2

STEP 4

Writer verifies the full chain — fails closed

from aip_a2a import A2AVerifyMiddleware

def writer_handler(body, *, context):
    # Only runs if the chain is valid end-to-end.
    return {"result": "drafted"}

mw = A2AVerifyMiddleware(
    writer_handler,
    own_aip_id="aip:web:acme.com/writer",
    root_public_key_bytes=orchestrator_kp.public_key_bytes(),
    required_scope="write:draft",
)
response = mw({"params": {"metadata": {"aip_token": to_writer.to_base64()}}})
print(response)  # {'result': 'drafted'}

The verifier checks: every signature, scope-attenuation at every hop, depth ≤ max_depth, no expired block, declared budget non-negative, and that the final delegation targets the writer's own AIP id.

STEP 5

What you can't do

Try modifying the example to reproduce these — every one fails:

Deny by default. The verifier never returns "valid but suspicious." It either accepts the entire chain or rejects with a specific error code. There is no permissive middle.

STEP 6

When to use max_depth vs budget

max_depth caps the structural extent of delegation. Use it to express "at most one specialist redelegation," or "no further hops past this point." It's a per-chain hard limit set at the root.

budget_cents caps the cumulative cost or work the chain can authorise. Each block declares its own ceiling; the runtime tracks aggregate spend. Use it to express "this whole task is worth at most $5."

They are complementary: depth limits structure, budget limits effect.

FULL EXAMPLE

Working code

The runnable version of this scenario lives at examples/a2a-multi-agent. Clone, install, run ./run.sh. For the normative spec, see spec §Delegation.