Agent Governance ToolkitAgent Governance Toolkit 4.1.0 · Python 3.10+
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
47 small wins to finish your pathNext lesson →

Delegation that cannot escalate

Delegation lets an agent mint a child identity that carries a subset of its own capabilities, and the toolkit refuses to hand a child any capability the parent does not already hold, so a delegate can never gain more power than its parent.

Last updated: 14 Oct, 2026 · Agent Governance Toolkit 4.1.0

The shop agent from the Signing an action and verifying it lesson holds three capabilities: read, refund and order_status. Suppose it wants a small worker that only issues refunds. delegate makes that child, and it enforces one rule worth proving: a child cannot be granted something the parent lacks.

Delegating a narrower capability

delegate takes a name and a capability list and returns a new AgentIdentity. The child gets its own key pair and DID, records the parent's DID, and counts its distance from the root in delegation_depth.

python
child = parent.delegate(name, capabilities, description=None)   # -> AgentIdentity

Before the honest delegation, the example tries the dangerous one. The shop agent attempts to hand a child the admin capability, which it does not hold. The call raises, and only then does it delegate the narrower refund-only child that it is allowed to make.

ExampleAn escalation is refused; a narrower delegation is allowed
# a child may only receive capabilities the parent already holds
try:
    rogue = shop.delegate("admin-bot", capabilities=["admin"])
except ValueError as e:
    print("escalation blocked:", e)

# the honest delegation: a narrower slice of what the parent has
refund_bot = shop.delegate("refund-bot", capabilities=["refund"])
print("child caps :", refund_bot.capabilities)
print("child depth:", refund_bot.delegation_depth)
print("parent set :", refund_bot.parent_did == str(shop.did))

Reading the refusal and the child

  • The escalation is refused. Asking for admin, which the parent does not hold, raises a ValueError whose message names the capability that is not in the parent's set. No child is created.
  • The child carries only what was asked. The refund-only delegate holds ['refund'], a strict subset of the parent's three capabilities.
  • The child records its parent. Its parent_did matches the shop agent's DID, and its delegation_depth is 1, one step from the root.
  • The rule is enforced in code, not in a prompt. There is no way to ask for more than the parent holds and have it granted, which is the whole value of delegation over copying a key.

Delegation vs copying the agent's key

Delegating a childCopying the key
CapabilitiesA subset, enforcedAll of them
Own identityYes, its own DIDNo, it is the same agent
Traceable to a parentYes, via parent_didNo
Can over-reachNo, escalation raisesYes, it holds everything

Where delegation helps

  • A worker sub-agent that should do one job, such as refunds, without the power to close accounts.
  • A short-lived task handed a narrow slice of the parent's authority for the length of the task.
  • A third party you integrate with, given a child identity whose capabilities you can reason about on their own.
Watch out. Delegation narrows capabilities, not trust in the chain. A child is only as trustworthy as its parent, so revoking the parent must invalidate the child. The next lesson shows that the delegation chain reflects a revoked parent, which is why you verify the whole chain, not one link.
Try it yourself
  • Delegate a read-only child with capabilities=["read"] and confirm its depth is 1.
  • Delegate a grandchild from the refund-only child and watch delegation_depth become 2.
  • Try to delegate capabilities=["delete_account"] from the shop agent and read the ValueError in full.

You understood something today that you didn't yesterday.