Back to the map

Module 14 · Multi-agent systems · Lesson 3 of 5

Handoffs and shared state

What crosses an agent boundary: a typed handoff with goal, inputs, constraints and done-when, the user and permissions attached, results back as structured outputs, bulk in a shared store with one writer, and a versioned schema.

CoreShould-knowMid 12 minPro Updated Nov 2026

Why it matters

A boundary between two agents is a place where the task can be lost. The second agent did not see the user, did not read the forty documents, and does not know what the first agent already tried. Whatever crosses the boundary is all it has. Teams either send the whole transcript, so the second agent drowns and the bill doubles, or a one-line instruction, so it guesses. Interviewers probe the handoff because it is where multi-agent systems quietly go wrong.

The idea

What crosses the boundary

Treat the handoff as a function call, not a conversation. The caller sends a typed object: the goal (what to achieve, in one sentence), the inputs (the ids, documents or facts the callee needs, not the whole context), the constraints (budget, deadline, what not to do), and what done looks like (the shape of the result). The callee starts a fresh context containing its own system prompt and that object, nothing else. The object has a schema and is validated on the way in, so a missing field is a bug caught at the boundary rather than a wrong answer three hops later.

{
  "handoff_version": 2,
  "trace_id": "7f3a-21c",
  "goal": "Find the three most-cited objections to the Q3 pricing change",
  "inputs": { "doc_ids": ["d-118", "d-204"], "period": "2026-07 to 2026-09" },
  "constraints": { "max_tokens": 40000, "deadline_ms": 60000, "external_search": false },
  "done_when": { "result_schema": "ObjectionList", "max_items": 3 },
  "principal": { "user_id": "u-9812", "scopes": ["docs:read"] },
  "notes": "The author of d-204 already replied; do not count that reply as an objection."
}

Results come back structured

The callee returns an object of the agreed shape, not prose: the items, a confidence, the sources used, and a status that can say "could not complete" with a reason. The caller's code checks it before the caller's model reads it; prose cannot be validated and carries the callee's reasoning, which the caller pays to read.

Shared state versus message passing

With message passing, every fact an agent needs arrives in a handoff and agents share nothing else. Simple, explicit, and the handoffs grow with the task. With shared state, a blackboard or store that all agents read and write, agents post findings and read others' findings, and handoffs carry only pointers. It scales better and couples worse: an agent that reads a field another agent writes now depends on that agent's schema and timing. Combine them: the handoff carries the goal and pointers, the store carries the bulk (documents, drafts, tool outputs), and every key has one writer, which the Failure modes lesson insists on.

PlannerTyped handoffgoal, inputs, doneResearcherstructured resultcarries user id + scopesShared storewrites planwrites findingsthe handoff names the goal; the store holds the bulk; one writer per key
The handoff names the goal, inputs, constraints and done-when, and carries the user and their scopes; the store holds the bulk. The result returns as a structured object, not a transcript.

Keep the principal attached

The user's identity, intent and permissions travel with every hop. A sub-agent that runs with the system's own credentials rather than the user's is a privilege escalation waiting for a prompt injection; the Excessive agency lesson calls this the confused deputy. Put the user id and the scopes in the handoff, have each agent's tools check them, and never widen scopes at a boundary. The original request rides along verbatim, so the fourth agent checks its work against what the user asked, not three summaries of it.

Version the schema

Handoff schemas change as agents evolve, and the two sides deploy separately. Put a version in the object, accept the previous version for one release, and reject unknown versions loudly. Two agents that disagree about the handoff format fail in the most confusing way available: both run, both report success, and the result is wrong.

The lost-context failure

The first agent learned that the customer's account is frozen, concluded that the refund path was blocked, and handed off "process the refund" anyway, without the fact. The second agent, which cannot see what the first learned, tries the refund. Typed handoffs prevent this structurally: the schema has fields for findings and constraints, and the output is validated against it. A free-text handoff relies on the model remembering to mention the frozen account, and under context pressure it will not.

The cost of each hop

A handoff costs tokens twice: the caller composes it and the callee reads it, on top of the callee's own system prompt. A 1,500-token handoff plus a 2,000-token system prompt is 3,500 tokens of overhead per hop before any work happens. Over a ten-hop run that is 35,000 tokens, which is the argument for few hops, lean handoffs and the bulk in the store.

 Full transcriptTyped handoffShared blackboard
Context costHighest; every hop re-reads the whole historyLow; a few hundred to a few thousand tokensLowest per hop; agents read only what they need
ClarityThe callee must infer what is wantedExplicit goal, inputs, constraints, done-whenDepends on the store schema and discipline
CouplingLoose on paper; the callee depends on everythingCoupled to one schema, versionedCoupled through shared keys and timing
DebuggabilityPoor; nobody knows what the callee attended toGood; the object is logged and validatedMixed; reads are hard to attribute without a single writer
Handoffs and shared state · Backplane