Module 5: Handoff and Delegation

Module 5: Handoff and Delegation

Description

The four previous modules built patterns where someone from outside decides first. A supervisor (M2) reads the full request and decides, before anyone does any work, which specialist to delegate it to. A pipeline (M3) fixes the order of the stages in advance, with no decision in between. A fan-out (M4) also recognizes, in advance, that two sub-tasks are independent and distributes them. In all three cases, the decision of "who does what" is made before the first agent touches its first tool.

This module builds the pattern that breaks that rule: handoff. An agent that is already working —mid-task, on something it started resolving in good faith— discovers that part of what it's being asked doesn't live in its own expertise. Instead of fabricating an ungrounded answer, or getting stuck, or going back to ask an external supervisor "who should I send this to?", the agent hands off the turn directly to the right specialist — with a minimal context package, not its full history. You'll build the pseudo-tool that represents that decision, the runner that recognizes it and stops its own loop, the transfer package that decides what travels and what stays behind, and the guards that stop two agents from passing the turn back and forth indefinitely.

Hard rule for this module (read before continuing)

This keeps the same line as Modules 1 through 4: each agent's decision —including the decision to hand off the turn— is not executed. It's still a hand-written script, labeled as concept (claude-sonnet-5). What is actually executed, for real, with Python 3.14 and its standard library, is the full mechanics of the handoff: the runner that detects the handoff pseudo-tool and stops its own loop instead of dispatching it as a domain tool, the construction of the transfer package, the automatic dispatch to the receiver with ONLY that package (never the sender's history), and the guards against endless handoff chains. One rule new to this module: the handoff package never includes the sender's message history — only a task (the specific question to resolve) and a context (a small dictionary, with exactly the data the receiver needs). Passing the full history "just in case" is exactly the anti-pattern this module calls context bloat, and you'll measure it, in bytes, with your own execution.


Where we are in the ecosystem

agent-fundamentals-and-tool-calling-guide (already complete)
  -> built ONE agent: tools, protocol, the loop, multi-tool, memory, robustness

multi-agent-orchestration-guide (this guide)
├── Module 1: Why multi-agent (and when not to)  (complete)
│   → The decision criterion, measured with real numbers
├── Module 2: The supervisor/router pattern  (complete)
│   → Deterministic routing vs. routing by model decision
├── Module 3: Sequential pipelines  (complete)
│   → The second pattern: fixed order, with no routing decision
├── Module 4: Parallel fan-out and aggregation  (complete)
│   → The third pattern: independent sub-tasks, distributed and aggregated
├── Module 5: Handoff and delegation  ← YOU ARE HERE
│   → The fourth pattern: an agent IN PROGRESS hands off the turn mid-task
├── Module 6: Shared state and the blackboard pattern
├── Module 7: Orchestrating the full Reservo system
└── Module 8: Project — the Reservo multi-agent system

This module doesn't re-explain the supervisor (M2), the pipeline (M3), or the fan-out (M4) — it reuses them as the contrast that gives the handoff its meaning. The three previous patterns share something the handoff doesn't have: in all three, the distribution decision happens before any work is in progress. The handoff is the first pattern in the guide where the need for another specialist appears during the work, not before.


Analogy: the waiter who calls the sommelier

You're at a restaurant. The waiter serving you takes your order, recommends a dish, notes how you want things cooked — they're genuinely working your order, not just repeating it back. At some point you ask: "what wine pairs well with this?" The waiter has no reason to know wine at that level of detail, and no reason to fake it either. A waiter with good judgment does exactly one thing: calls the sommelier directly, tells them what dish you ordered, and lets the sommelier answer your question. They don't walk to the kitchen to ask the chef "who should handle this wine question?" — they themselves, on the spot, recognize the limit of their own expertise and hand off the turn to whoever actually knows.

Notice what the waiter did not do: they didn't make you repeat your whole order to the sommelier from scratch, and the sommelier doesn't need to know what main course the waiter recommended earlier, or what time you arrived, or whether you asked for still or sparkling water. The sommelier only needs one concrete thing: what dish you're having, so they can recommend a wine that pairs well. That's exactly this module's handoff package: the minimum real data the receiver needs, not one line more.


The case that runs through the module: the question that exceeds the task mid-way

Modules 2, 3, and 4 left three finished specialists: booking_agent (quote, book, cancel), policy_agent (search_docs, the policy stub), and pricing_agent (compare prices). This module doesn't add any new specialist either — it reuses the exact same three, in a different situation:

Request: "Quote Focus pro 3h. And another thing, what happens if I don't show up for the booking?"

booking_agent receives the full request (the word "quote" places it there, unambiguously).
Turn 1 (executed): get_quote(Focus, pro, 3h) -> 6000 cents. This DOES live in its expertise.
Turn 2 (concept): booking_agent reads the second question -- no-show -- and recognizes
it has NO tool to resolve it. Instead of inventing an answer or getting stuck, it
hands off the turn to policy_agent with a minimal package: the specific question, plus the
price already quoted (6000), in case the answer needs to reference it.

Unlike the compound request from Module 4 ("quote Focus pro 3h and tell me the cancellation policy") —where the two parts were independent from the start, and that's why they could be distributed with fan-out before anyone did any work—, here the need for policy_agent wasn't obvious in advance: booking_agent had already started resolving the task, with a tool it did have, when it hit the limit. That difference in when the need for the other specialist is discovered is the entire axis of this module.


Boundary with what you've already seen (and with what's coming)

With the three previous patterns fresh, the underlying distinction is complete:

  • A supervisor (M2) decides WHO starts, from outside, before anyone works. It reads the raw request, once, and routes.
  • A pipeline (M3) fixes the ORDER, deciding nothing at each step. The sequence of stages is written before any concrete request exists.
  • A fan-out (M4) distributes sub-tasks already known, in advance, to be independent. The recognition of independence happens before the dispatch, not during.
  • A handoff (this module) is decided by an agent IN PROGRESS, mid-way through. There's no "before" moment where someone read the full request and distributed the work — the very agent already resolving one part discovers, on the fly, that another part exceeds its expertise, and hands off the turn without consulting anyone external again.

This last distinction is what holds up the whole module: the supervisor decides from outside, before anyone works; the handoff is decided by the agent itself, in progress, mid-way through. These aren't the same mechanism at two different moments — they're two genuinely different ways of resolving "who's next," with different costs and guarantees, which lesson 02 compares with numbers.

And looking ahead, a distinction this module leaves open on purpose: when booking_agent passes the package to policy_agent, that transfer is a direct, point-to-point message — the sender builds the package, the receiver gets it, and that's where the relationship between the two ends. There's a completely different way of sharing information between agents: a common state space that anyone can read and write, without anyone having to build a package for anyone in particular. That's the blackboard, and Module 6 builds it.


Prerequisites

Required knowledge:

  • ✅ Module 1 of this guide, complete: the decision criterion and the cost of coordinating, measured.
  • ✅ Module 2, complete: SPECIALISTS, run_specialist, Reservo's three specialists, and a supervisor's four-step anatomy (receive, decide, dispatch, aggregate) — this module's constant point of contrast.
  • ✅ Module 4, complete: the distinction between distributing work before anyone starts (fan-out) and what this module adds — discovering the need during.
  • agent-fundamentals-and-tool-calling-guide: the tool_use/tool_result protocol, run_agent_parallel, dispatch_parallel — the technical base this module extends with a new pseudo-tool.

Recommended:

  • ✅ Having run Module 2 lesson 06's full dispatcher yourself — this module contrasts its cost, number against number, with the cost of a direct handoff.

NOT required:

  • ❌ You don't need an API key or an internet connection: the decision to hand off the turn is still concept, hand-written.
  • ❌ You don't need any orchestration framework — the handoff pseudo-tool, the runner that recognizes it, and the transfer package are built by hand, with standard-library dataclasses.

Environment:

  • Python 3.14.0 with its standard library (dataclasses, concurrent.futures). Nothing to install.

Module roadmap

Lesson 01 — Module introduction (this one)

The handoff pattern, the waiter-and-sommelier analogy, and the boundary with supervisor (M2), fan-out (M4), and blackboard (M6).

Lesson 02 — Recognizing when a handoff is needed

What happens WITHOUT a handoff: an agent that runs into a question outside its expertise, executed in two real failure modes — an ungrounded answer and an attempt to use a tool it doesn't have.

Lesson 03 — The handoff package: what goes in, what stays out

HandoffPackage, and a measurement, executed, in bytes, of how much smaller the minimal package is than the sender's full history — "context bloat," quantified.

Lesson 04 — The handoff tool and the interrupted loop

handoff_to_specialist as a pseudo-tool, and run_agent_with_handoff: the runner variant that recognizes that special tool and stops its own loop instead of dispatching it as a domain tool.

Lesson 05 — Reservo's handoff, executed end to end

booking_agent quotes, hits the limit, hands off the turn; policy_agent answers, grounded in the context it received — the module's centerpiece, end to end.

Lesson 06 — Guarding against endless handoff chains

What happens if the receiver also tries to hand off the turn (ping-pong), or if it hands off to a specialist that doesn't exist — the two guards a real handoff needs.

Lesson 07 — Measuring the cost of a direct handoff

How much it costs, in model calls and in hops, to resolve the SAME task with a direct handoff versus the alternative of going back to an external supervisor every time an agent hits a limit.

Lesson 08 — Mini-project: handoffs in Reservo

Three new scenarios — a real handoff, a case that does NOT need a handoff, and a case where the handoff works but fan-out (M4) would have been the right design from the start.

Progression map

Lesson 01 (this one) → The pattern, the analogy, the boundary with M2/M4/M6
Lesson 02             → Why it's needed: the failure modes without handoff, executed
Lesson 03             → The minimal package, measured in bytes against the full history
Lesson 04             → The mechanism: the pseudo-tool and the loop that stops
Lesson 05             → Reservo's full handoff, end to end
Lesson 06             → The guards: ping-pong and a nonexistent receiver
Lesson 07             → The measured cost: direct handoff vs. going back to the supervisor
Lesson 08             → Project: three scenarios, with the judgment of when YES and when NO

Difficulty: ⭐⭐ ──────────────────▶ ⭐⭐⭐

What you'll achieve in this module

By completing the 8 lessons, you'll be able to:

  1. Precisely distinguish a handoff (decided by an agent IN PROGRESS, mid-task) from a supervisor (decides from outside, before starting) and from a fan-out (distributes what was already known to be independent from the start).
  2. Recognize the failure modes of an agent that hits an expertise limit without having a handoff mechanism — and why both are worse than handing off the turn.
  3. Design a minimal handoff package — what data the receiver actually needs, and why the sender's full history is almost never one of them.
  4. Build handoff_to_specialist and run_agent_with_handoff, the pseudo-tool and the runner that recognizes it without treating it as a domain tool.
  5. Run a full Reservo handoff, end to end, with the receiver's answer grounded in the context it got from the sender.
  6. Guard a handoff system against endless chains — ping-pong between agents, or a receiver that doesn't exist.
  7. Measure the real cost of a direct handoff versus the alternative of going back to an external coordinator every time an agent hits a limit.

Before and after

BEFORE the module:
→ "If an agent can't resolve something, the only option is going back to the supervisor"
→ Passing another agent "the full context just in case" is the safest thing to do
→ A handoff and a supervisor re-route are, in practice, the same thing
→ Any moment is a good moment for an agent to decide to transfer control

AFTER the module:
→ An agent IN PROGRESS can hand off the turn directly, without going back to anyone external --
  MEASURED, it costs fewer calls and fewer hops than the forced return
→ The minimal package (task + small context) resolves the task just as well as the full
  history, weighing a fraction -- MEASURED in bytes
→ A handoff decided BEFORE anyone works isn't a handoff -- it's a mislabeled supervisor or
  fan-out
→ A handoff system with no guards can enter ping-pong -- it needs an explicit limit

Traps to avoid while working through this module

1. "Handoff and supervisor routing are the same mechanism, just later"

No. The supervisor (M2) reads the full request before any work is in progress. The handoff is decided by an agent that is already working a real part of the task. Lesson 02 proves it by executing: without a handoff, booking_agent has no way to "return control" to a supervisor that was never watching — it would have to fabricate an answer or get stuck.

2. "Passing the full history to the receiver is safer than building a minimal package"

The opposite. Lesson 03 measures, in bytes, how much heavier the full history is — and lesson 04 shows, by executing, what breaks if you try to pass it where a specific task is expected. More context isn't safer: it's more noise the receiver has to ignore, and a real source of format errors.

3. "Any request with two parts is a handoff candidate"

No — if the two parts are independent from the moment the request arrives, the right pattern is fan-out (M4), not handoff. The handoff is specifically for when the need for the second specialist is discovered during the first one's work, not before. The mini-project (lesson 08) includes a case designed to test exactly this distinction.

4. "A handoff system doesn't need limits — the model would never get it wrong"

Yes it does. Lesson 06 builds, and actually triggers, a ping-pong case (two agents handing off the turn to each other) and a nonexistent-receiver case — both fail loud, with a clear error, because a system without those guards could resend the package indefinitely.


How to work through this module

  1. Run lesson 02 yourself, paying attention to the made-up number. Seeing, with your own eyes, that an agent without a handoff can answer with data that doesn't match the real policy — not just "ungrounded," but flatly incorrect — is what makes the rest of the module feel justified, not an academic exercise.
  2. Don't skip lesson 03's byte measurement. It's the central evidence for "what goes in, what stays out" in a handoff package — and it gets more compelling the longer the sender's conversation is before the handoff, something the lesson itself demonstrates by adding one more step.
  3. Lesson 07 closes the module's economic argument. Practicing the comparison with different numbers of internal steps before the mini-project makes lesson 08 feel like applying a criterion, not memorizing an example.

Estimated time:

Lesson 01 (this one) →  15 min reading
Lesson 02             →  20 min + running the demo
Lesson 03             →  25 min + running the demo
Lesson 04             →  25 min + running the demo
Lesson 05             →  30 min + running the demo (the densest in the module)
Lesson 06             →  25 min + running the demo
Lesson 07             →  25 min + running the demo
Lesson 08             →  30 min + applying the full pattern

Total: ~3.2 hours

Evidence of success

Before moving on to Module 6 (Shared State and the Blackboard Pattern), you should be able to:

  • Explain, in your own words, the difference between a supervisor that decides from outside and a handoff decided by an agent in progress — without confusing the two moments.
  • Build HandoffPackage, handoff_to_specialist, and run_agent_with_handoff, and run a full handoff from booking_agent to policy_agent.
  • Cite from memory lesson 03's result in bytes: how much smaller the minimal package is than the full history, and why that gap grows with longer conversations.
  • Cite from memory lesson 07's result: how many calls and hops a direct handoff saves versus the forced return to a supervisor.
  • Recognize, in a new scenario, whether a handoff applies, or whether it's actually a supervisor (M2) or a fan-out (M4) — the distinction the mini-project tests.

Summary

  • This module builds the fourth pattern of the five that Module 1 previewed: handoff — an agent already at work discovers, mid-task, that it needs another specialist, and hands off the turn directly, without going back to an external coordinator.
  • Hard rule: the decision to hand off the turn is still concept (claude-sonnet-5); the mechanism that recognizes it, the transfer package, and the guards against endless chains are actually executed with Python 3.14. The handoff package NEVER includes the sender's full history.
  • The case reuses, unchanged, Reservo's three specialists — booking_agent quotes and runs into a no-show question that exceeds its expertise, and hands off the turn to policy_agent with a minimal package.
  • Clear boundary with what you've already seen and what's coming: the supervisor (M2) decides from outside, before starting; the fan-out (M4) distributes what was already known to be independent; the handoff (this module) is decided by an agent in progress, mid-way through; the blackboard (M6) shares state without passing point-to-point packages.

Next lesson: 02 — Recognizing when a handoff is needed. We execute what happens to an agent that hits an expertise limit without having any mechanism to hand it off.


Additional resources

  1. Anthropic — Building effective agents — The principle of keeping each agent within a bounded scope, and transferring control when a task exceeds it, instead of forcing a single agent to solve everything.
  2. Anthropic — Multi-agent research system — A real Anthropic case where a sub-agent recognizes the limit of its own scope and communicates it explicitly, instead of answering beyond what it can ground.
  3. Anthropic — Tool use (function calling) overview — The tool_use/tool_result protocol that this module's handoff pseudo-tool extends, without breaking it.
  4. Python 3.14 — What's New — The version used to run all of this guide's orchestration.