Orchestrate fleets of specialized agents that divide, parallelize, and coordinate complex work — without a single agent getting overwhelmed.
Prerequisites: M12 (Tool Use), M13 (Orchestration). This module covers the leap from one clever agent to a coordinated crew.
Tap to jump to any concept.
A single Claude instance handles one thing at a time with a fixed context window. When tasks grow large enough to exceed that window, span multiple specializations, or benefit from parallelism, you need a crew — multiple agents with distinct roles working in concert.
Four signals tell you it's time to split: the task doesn't fit one context window, different steps need different expertise, sub-tasks can run in parallel, or you need failure in one part to not cascade into everything else.
A 1,200-token system prompt trying to make Claude an expert at research, writing, legal review, and formatting is worse than four 300-token specialists — each expert at one thing.
You hire one contractor to build a house. They're competent, but they handle electrical, plumbing, framing, and finishing sequentially, alone. Every sub-task blocks on the last.
The contractor gets overwhelmed. Framing mistakes delay plumbing. A single error cascades through the whole build. The house takes twice as long and quality suffers everywhere.
A construction crew assigns specialists: electricians, plumbers, framers — each with focused expertise. The foreman coordinates. Work runs in parallel. One trade failing doesn't stop another. Multi-agent systems are the crew.
When should you split into multiple agents?
FUNCTION should_split(task): # Signal 1: context window IF task.token_estimate > context_limit * 0.7: RETURN "SPLIT — context overflow risk" # Signal 2: distinct expertise IF task.domains.count > 2: RETURN "SPLIT — use specialist agents" # Signal 3: parallelism IF task.has_independent_subtasks: RETURN "SPLIT — run subtasks concurrently" # Signal 4: failure isolation IF task.failure_must_not_cascade: RETURN "SPLIT — isolate blast radius" RETURN "SINGLE AGENT is fine"
Multi-agent systems add orchestration overhead, latency, and coordination complexity. Use the minimum number of agents the task actually requires — start single, split when a specific signal fires.
Each subagent starts with a blank context window. Only what you explicitly pass in the handoff message is visible. Context does NOT flow automatically between agents.
Multi-agent systems earn their complexity only when a specific signal fires: context overflow, multi-domain specialization, parallelism, or failure isolation. Never split by default.
Three proven topologies exist for connecting multiple agents. The right choice depends on whether tasks are independent or sequential, whether you need easy debugging, and whether the roles are fixed or dynamic.
Supervisor/Worker (hub-and-spoke) is the most common and easiest to debug. Pipeline suits sequential refinement. Peer-to-peer is flexible but rare in production because debugging becomes hard when any agent can talk to any other.
The cert exam (Domain 1.2) favors Supervisor/Worker as the default pattern — it's auditable, role boundaries are clear, and failures surface at the supervisor.
Imagine running a restaurant where every chef can give orders to every other chef. A dish touches six hands with no one coordinating the order. Timing is chaos.
The fish and the steak arrive at the table 8 minutes apart. Two chefs independently started the same sauce. Nobody agreed on who owns the dessert.
The head chef (supervisor) owns the sequence and timing. Line cooks (workers) execute focused tasks and report back. That's hub-and-spoke. A single assembly line (pipeline) works when each dish must pass through every station in order. Peer-to-peer is the chaotic kitchen with no head chef.
Which topology fits your use case?
| Pattern | Best For | Trade-off |
|---|---|---|
| Supervisor/Worker | Parallel independent tasks, mixed role budgets | Extra supervisor call per cycle |
| Pipeline | Sequential refinement (draft → review → edit) | No parallelism — bottleneck at each stage |
| Peer-to-peer | Dynamic, exploratory tasks | Hard to debug, rare in production |
FUNCTION choose_topology(task): IF task.subtasks_are_independent: RETURN "SUPERVISOR_WORKER" IF task.is_refinement_chain: RETURN "PIPELINE" IF task.is_exploratory_prototype: RETURN "PEER_TO_PEER" RETURN "SUPERVISOR_WORKER" # safe default
Pipeline is strictly sequential — no step starts until the prior completes. Supervisor/Worker can dispatch multiple workers in parallel. For independent sub-tasks, hub-and-spoke is almost always faster.
Route expensive tasks to Opus, cheap tasks to Haiku. A Supervisor/Worker pattern lets you assign a model per role — the biggest cost lever in multi-agent systems.
Default to Supervisor/Worker. It's the cert-preferred pattern, easiest to debug, and supports model-per-role cost optimization. Switch to Pipeline only for true refinement chains.
Agents don't communicate through magic — every handoff is a structured message passed explicitly. The #1 failure mode in multi-agent systems is context dropping: critical information exists in one agent's context but never makes it into the next agent's message.
Good protocols define exactly what fields every handoff message must carry: sender, receiver, task ID, type, payload, original goal, and structured error context on failure.
Cert Domain 1.3: Subagents have isolated context windows. They do NOT inherit the coordinator's conversation history — only what you pass explicitly.
Your GP has your complete history — medications, allergies, past surgeries. They refer you to a specialist who has never met you and knows nothing about your case.
The specialist asks you to repeat everything from scratch. They miss context your GP considered obvious. They prescribe something that conflicts with your existing medication because the referral said "see cardiologist."
A proper referral letter explicitly includes: patient history, reason for referral, active medications, known allergies, and the GP's working hypothesis. That letter is your handoff message. Without it, the specialist (subagent) starts blind.
# Handoff message schema FUNCTION build_handoff(task, goal): RETURN { "sender": "coordinator", "receiver": task.assigned_agent, "task_id": generate_uuid(), "type": "TASK_REQUEST", "payload": task.data, "original_goal": goal, # NEVER omit "instructions": task.spec, "metadata": { "timestamp": now() } } # Error response schema FUNCTION build_error(exc, context): RETURN { "type": "ERROR", "error_type": exc.class, "message": exc.message, "context": context, "suggested_recovery": suggest(exc) }
They do not. Each subagent opens with a blank context window. The coordinator must explicitly pass every piece of information the subagent will need — there is no automatic inheritance.
Errors vanish silently if you don't structure them. A subagent that fails with no error message makes the coordinator think success. Always return a structured error payload with recovery guidance.
Every handoff is an explicit letter, not a phone call. Include the original goal in every message, structure errors so they surface, and never assume context flows automatically.
When multiple agents need to exchange data, you have two fundamental approaches. Shared state (a central database or dict all agents can read/write) is intuitive but creates race conditions when two agents write simultaneously. Message passing keeps each agent's state private and exchanges outputs explicitly — no race conditions possible.
A hybrid approach uses message passing for coordination but passes artifact IDs instead of large payloads — agents fetch the artifact directly from storage when needed.
Five colleagues share a single whiteboard. Anyone can erase and rewrite any part at any time. The board shows the "current state" of the project.
Two people reach for the same section simultaneously. One overwrites the other's update. The next reader gets a corrupted half-written state. Debugging requires figuring out whose version was correct.
Message passing is sealed envelopes. Each person keeps their own notes private and only shares finished results by handing over a sealed envelope. No one can modify your notes in-flight. The coordinator receives completed outputs, never mid-write state.
# BAD: shared state — race condition PARALLEL: agent_a: state["draft"] = result_a # write 1 agent_b: state["draft"] = result_b # write 2 overwrites! # GOOD: message passing FUNCTION coordinator_run(task): results = PARALLEL_DISPATCH([ agent_a, agent_b, agent_c ], task) # Coordinator owns state — one writer state["outputs"] = merge(results) RETURN state # HYBRID: artifact IDs for large payloads FUNCTION dispatch_with_artifact(agent, data): artifact_id = store(data) # save to storage RETURN send_message(agent, { "artifact_id": artifact_id # pass ID, not payload })
One of the main benefits of multi-agent systems is parallel execution. The moment you run agents in parallel with shared state, you have concurrent write risk. Don't design for sequential shared access and then add parallelism later.
Use the hybrid pattern: store large data in a blob store and pass the artifact ID in the message. The message stays small; the agent fetches data only when it needs it. Best of both worlds.
Default to message passing — coordinator owns state, agents return outputs. Use artifact IDs when payloads are large. Shared state + parallelism = race conditions.
When multiple agents produce contradictory outputs — different diagnoses, different code approaches, different recommendations — you need a strategy to resolve the conflict. Four strategies exist, each with different cost and reliability profiles.
Picking the wrong strategy causes either wasted API calls (voting on a simple question) or unsafe automation (confidence scoring on a high-stakes medical decision). Match the strategy to the stakes.
Three specialists review your medical case and come back with different recommendations. One says surgery, one says medication, one says watchful waiting. You need an answer.
With no resolution protocol, you freeze. Or worse, you pick the loudest voice. The stakes are high and the disagreement is real — someone needs to own the decision.
Arbitration: your GP (supervisor) reviews all three opinions and decides.
Voting: majority rules — medication wins 2:1.
Confidence scoring: the specialist with the highest certainty gets weight.
Escalation: the case goes to a hospital ethics board when stakes exceed a threshold.
FUNCTION resolve_conflict(outputs, context): # Strategy 1: safety-critical → human IF context.is_safety_critical: RETURN escalate_to_human(outputs) # Strategy 2: high-stakes → voting IF context.stakes == "HIGH": votes = run_agents(task, n=3) RETURN majority(votes) # Strategy 3: low confidence → arbitration max_conf = max(o.confidence FOR o IN outputs) IF max_conf < 0.7: RETURN supervisor_arbitrate(outputs) # Strategy 4: confident result → use it best = argmax(outputs, key="confidence") RETURN best.result
LLMs can return confidence: 0.95 for a completely wrong answer. Confidence scores reflect the model's self-assessment, not ground truth. Always pair confidence scoring with a fallback (arbitration or human escalation) for high-stakes decisions.
Escalation is a feature, not a failure. Define clear programmatic thresholds in code — don't leave it to Claude to decide when to escalate. A well-placed escalation path is what makes an agent system trustworthy in production.
Match resolution strategy to stakes: arbitration for nuanced conflicts, voting for high-stakes binaries, confidence scoring for speed, human escalation for safety-critical. Define escalation thresholds in code — not in Claude's judgment.
Tap each answer to reveal.
The full desktop module includes a complete Content Creation Pipeline walkthrough, hands-on lab with multi-agent coordination code, and 5 quiz questions with detailed explanations.
Open Full Module on Desktop →