Multi-agent systems are powerful. But there's a quiet failure mode nobody talks about: the handoff. The moment Agent A passes work to Agent B is where context gets lost, tasks get duplicated, and users get confused.
This guide covers the patterns that actually work.
Why Handoffs Fail
Before we fix it, understand what goes wrong:
- Context collapse — Agent B doesn't know what Agent A already tried
- Goal drift — The original request gets paraphrased until it's unrecognizable
- Ownership ambiguity — Both agents think the other one is handling it
- State mismatch — Agent B picks up from a stale snapshot
Sound familiar? These are solvable problems. Here's how.
Pattern 1: The Handoff Envelope
The simplest and most reliable pattern. When handing off work, wrap the task in a structured envelope that contains everything the receiving agent needs.
{
"task_id": "task-20260306-001",
"original_request": "Research competitors in the AI agent config space and summarize findings",
"requested_by": "user:pk",
"created_at": "2026-03-06T14:00:00Z",
"handed_off_at": "2026-03-06T14:05:00Z",
"handing_off_agent": "orchestrator",
"receiving_agent": "researcher",
"context": {
"already_tried": ["Google search for 'AI agent configs'"],
"known_facts": ["User wants focus on open-source options", "No budget constraints mentioned"],
"blockers": []
},
"expected_output": "markdown_summary",
"deadline": null,
"escalate_to": "orchestrator"
}The receiving agent reads this envelope first — before doing anything else. It answers: What is the task? What's already been done? Who do I report back to?
Pattern 2: The Relay Ledger
For longer multi-agent pipelines, maintain a shared ledger file that every agent appends to. Think of it as a baton in a relay race.
# Task Ledger: task-20260306-001 ## Leg 1 — Orchestrator (14:00–14:05) - Received user request - Decomposed into: research → analyze → summarize - Delegated research to: researcher agent - Status: HANDED OFF ## Leg 2 — Researcher (14:05–14:18) - Searched web for AI agent config competitors - Found: OpenAgents, AgentHub, FlowWise, LangChain templates - Compiled raw findings to: /tmp/research-raw.md - Status: HANDED OFF → analyst ## Leg 3 — Analyst (14:18–...) - Starting analysis of raw findings - ...
Each agent adds its leg when it picks up the task and when it hands off. The orchestrator can check this file at any point to know exactly where the work stands.
Key rule: Never delete entries. Append only.
Pattern 3: Explicit Acknowledgment
Before an agent starts working on a handed-off task, it must write an acknowledgment. This prevents the "ghost handoff" where the receiving agent never actually picks up the work.
# Pseudo-code for receiving agent startup
def start_task(handoff_envelope):
# Write acknowledgment FIRST, before any work
write_ack({
"task_id": handoff_envelope["task_id"],
"received_by": MY_AGENT_ID,
"received_at": now(),
"status": "acknowledged"
})
# NOW do the work
result = do_work(handoff_envelope)
# Write completion
write_ack({
"task_id": handoff_envelope["task_id"],
"status": "complete",
"output": result
})If you check the ledger and there's no acknowledgment after 60 seconds, the orchestrator should re-assign the task. Don't wait forever.
Pattern 4: Context Compression Before Handoff
This one saves tokens and improves accuracy. Before handing off, the sending agent compresses the relevant context.
Bad handoff:
"Here's the last 8,000 tokens of conversation — figure it out"
Good handoff:
"User wants a competitor analysis. I've already checked Google. Raw findings are in /tmp/research-raw.md. User cares most about open-source options. Return a 3-paragraph markdown summary."
The rule: The handing agent is responsible for summarizing its own context. Never dump raw history on the receiving agent.
Structure it as:
- Goal (one sentence)
- What's done (bullet list)
- What's needed (specific output)
- Constraints (format, length, tone, deadlines)
Pattern 5: The Return Receipt
When work is complete, the final agent doesn't just disappear — it writes a return receipt back to the original requester.
{
"task_id": "task-20260306-001",
"completed_by": "summarizer",
"completed_at": "2026-03-06T14:31:00Z",
"output_location": "/reports/competitor-analysis-20260306.md",
"summary": "Found 4 main competitors. OpenAgents is closest match. Full details in output file.",
"confidence": "high",
"open_questions": ["Pricing page for AgentHub was 404 — may have changed plans"]
}The orchestrator reads this, confirms the task is done, and delivers the result to the user. The loop is closed. Nothing falls through the cracks.
Anti-Patterns to Avoid
❌ Implicit handoffs via shared file
Don't have Agent A write to a file and assume Agent B will notice. Use explicit messaging or a task queue.
❌ "Soft" handoffs in conversation
"Hey, can you pick this up?" is not a handoff. It's a hope.
Always use a structured handoff envelope, even in conversational systems.
❌ Overloading the orchestrator
If every message goes through the orchestrator for routing, it becomes a bottleneck. For sequential pipelines, let agents hand off directly (with the orchestrator CC'd via the ledger).
❌ No timeout handling
Set explicit timeouts. If Agent B doesn't acknowledge in X seconds, the orchestrator reassigns. Silent failures kill multi-agent systems.
❌ Losing the original request
By the time the work reaches Agent D, the original user request should still be verbatim in the handoff envelope. Never let it get paraphrased away.
Putting It Together: A Simple Implementation
Here's how you'd wire this up with file-based state (works with any agent framework):
/tasks/
task-001/
envelope.json ← Original handoff envelope
ledger.md ← Append-only relay log
ack.json ← Acknowledgment from current agent
output.md ← Final output (when complete)Every agent knows to check /tasks/{id}/ when it receives a task ID. The structure is predictable. No custom routing logic required.
When to Use What
| Scenario | Recommended Pattern | |----------|-------------------| | Simple 2-agent handoff | Handoff Envelope | | 3+ agent pipeline | Relay Ledger + Envelope | | Async agents, delayed pickup | Explicit Acknowledgment + Timeout | | Large context, expensive models | Context Compression | | User-facing delivery at end | Return Receipt |
The One-Line Rule
If you remember nothing else: the handing agent is responsible for the quality of the handoff. Don't make the receiving agent reconstruct context it doesn't have. Package it cleanly, label it clearly, and close the loop when the work is done.
Multi-agent systems fail at the seams. Keep the seams tight.
Want the full playbook?
Get copy-paste AI templates, prompt frameworks, and agent patterns — all in one place.
Get Access — It’s FreeNo credit card. No fluff. Just the good stuff.