---
title: "Implement Multi-Agent Delegation"
url: "https://docs.caracal.run/v1.0/guides/delegation/"
markdown_url: "https://docs.caracal.run/markdown/v1.0/guides/delegation.md"
description: "Start child Sessions, attach typed constraints, inspect graph impact, and revoke safely."
page_type: "page"
concepts: []
requires: []
---

# Implement Multi-Agent Delegation

Canonical URL: https://docs.caracal.run/v1.0/guides/delegation/
Markdown URL: https://docs.caracal.run/markdown/v1.0/guides/delegation.md
Description: Start child Sessions, attach typed constraints, inspect graph impact, and revoke safely.
Page type: page
Concepts: none
Requires: none

---

Use Delegation when one Session needs to hand a narrower slice of authority to another Session. The SDK creates the Delegation and carries the context; the web console shows the graph and impact.

## Prerequisites

* Two live Sessions and a parent that already holds the resource authority being delegated.
* A specific resource, scope subset, positive TTL, and intended maximum hop count.
* An authenticated work channel for transferring the opaque Delegation ID to the target Session.

`session()` always starts the child under the **same application** as the parent. Narrow the child's authority only when it should hold less than the parent. To hand authority across applications, use `delegate()` with a peer Session under the other application; it returns the Delegation, and the receiver presents it with `acceptDelegation()`.

## Implementation flow

```mermaid
flowchart LR
  Parent["Parent Session"] --> Start["Start child with narrowed authority"]
  Start --> Delegation["Bounded Delegation"]
  Delegation --> Child["Run child with delegated context"]
  Child --> Exchange["Exchange for resource mandate"]
  Exchange --> Audit["Inspect audit and graph"]
```

Python uses `Authority.narrow(...)`, `await caracal.delegate(...)`, and `async with caracal.accept_delegation(edge_id, validate=True)`. Go uses `AuthorityNarrow(...)`, `Delegate`, and `AcceptDelegation`. The [language SDK references](/v1.0/sdks/) define exact option types; the workflow and wire authority are equivalent.

## Narrow a child in the same application

Starting a child with less authority than its parent needs no explicit hand-off - pass `Authority.narrow(...)` when starting the child Session, exactly as shown in your [SDK guide](/v1.0/guides/sdk-typescript/#start-a-narrowed-child). This page's subject is the explicit flow between two Sessions that already exist.

## Delegate across applications

The issuer holds the authority and knows the receiver's Session ID; the receiver presents the returned Delegation ID. Two sides, one edge:

```ts
// Issuer side: Anton delegates read-only PiperNet access
// to a peer Session owned by the Fiona application.
const delegation = await caracal.delegate({
  toSessionId: receiverSessionId,          // shared by the receiver up front
  toApplicationId: fionaApplicationId,     // omit for same-application peers
  resourceId: 'resource://pipernet',
  scopes: ['pipernet:read'],
  constraints: { maxHops: 1 },
  ttlSeconds: 600,
})
await sendOverWorkChannel({ delegationId: delegation.delegationId })
```

```ts
// Receiver side (Fiona): present the offered Delegation inside the
// target Session's context. validate: true confirms it is live first.
await caracal.session(async () => {
  const { delegationId } = await readFromWorkChannel()
  await caracal.acceptDelegation(
    delegationId,
    async () => {
      const governed = caracal.transport({ scopes: ['pipernet:read'] })
      const target = caracal.gatewayRequest('resource://pipernet', '/reports')
      await governed(target.url)
    },
    { validate: true },
  )
})
```

Every mint inside the accepted block presents the Delegation, so the STS enforces its scopes, resource bound, TTL, and hop budget - and revoking the edge cuts the receiver off mid-run.

## Review the graph

1. Open the web console for your deployment.
2. Select **Delegation**.
3. Inspect active edges, inbound edges, outbound edges, and traversal.
4. Use impact before revoking an edge.
5. Check **Audit** for the delegated exchange and resource decision.

## Hand Over the Delegation ID Safely

The issuer and receiver share the opaque Delegation ID over their authenticated work channel, such as a queue message, RPC field, or task payload. Creation is only an offer and does not mutate receiver context. Possessing and presenting this target-Session-bound ID through `acceptDelegation()` is receiver consent; STS also checks the receiving application and live target Session. Use `acceptDelegation(delegationId, fn, { validate: true })` to confirm that exact ID with Coordinator before work runs under it. Every presentation emits a `delegation.accept` event.

## Safe constraints

| Constraint | Good default                              |
| ---------- | ----------------------------------------- |
| Scopes     | Small subset of parent authority.         |
| TTL        | Required; use minutes, not days.          |
| Hop count  | `1` unless a deeper graph is intentional. |
| Resource   | Single resource whenever possible.        |

## Troubleshooting

| Symptom                               | Check                                                                |
| ------------------------------------- | -------------------------------------------------------------------- |
| `Delegate requires an active Session` | Call delegation inside `session()` or a bound Caracal context.       |
| Resource denies delegated request     | Confirm the edge, ancestry, policy grant, and required scopes remain live. |
| Chain validation fails                | Confirm authoritative parent links are continuous; configure `requireChainContains` separately at verifiers when needed. |
| Revocation did not affect child       | Confirm cascade revocation and resource-server revocation consumers. |

## Validate the delegation

Mint the allowed subset, attempt one broader scope, revoke the edge, and retry. The subset must succeed; broadening must fail server-side; after revocation neither the child nor descendants may mint or pass resource verification.

:::caution[Failure point: lifetime]
A Delegation can expire before its target Session. The Session may remain observable but cannot mint through the expired edge. Size the edge TTL to the work and handle terminal authorization failure rather than widening authority.
:::

## Next Step

Inspect the graph and request trace in [Tail and Query the Audit Stream](/v1.0/guides/audit-stream/).
