Two Agents Share Nothing Except the Message You Pass Between Them

Inside a single agent, coordination is almost free. Everything the model has read, decided, or produced sits in one context, and any later step can reach back and use it without anyone arranging for that to happen. The moment work is split across separate agents, that convenience is gone and most people do not notice it has left. Each agent runs in its own context, and nothing crosses the boundary between them on its own. A fact the first agent established, a constraint it inferred, a format it settled on: none of it reaches the second agent unless it was placed, deliberately and in full, into the message that passed between them. That message is not a convenience or a log entry. It is the entire shared surface between two isolated processes, and its design is what decides whether the system is dependable or merely appears to work until the day it doesn’t.

This reframes what a handoff message actually is. It is not a note the sender leaves for the receiver. It is a contract, in the same sense a function signature or a wire protocol is a contract: a fixed agreement about what will be present, in what form, so that the party on the other side can act without guessing. Treat it as prose to be composed freshly each time and the system inherits every weakness of ad hoc communication. Treat it as a schema, an explicit statement of what a valid message contains, and the handoff becomes something you can reason about, test, and evolve. The difference between a brittle multi-agent system and a reliable one usually comes down to whether that contract exists at all.

An unstructured handoff fails in three predictable ways

When agents pass raw, unstructured text to one another, the failures are not random. They fall into three recurring shapes, and naming them is the first step toward designing them out.

The most common is simply missing context. The sender proceeds on the assumption that the receiver already holds some fact, and because the two share no memory, that assumption is false by default. The receiver never gets the fact, cannot recover it, and produces something confidently wrong because the input it needed was never in the message. The failure surfaces far downstream, where it is hardest to trace back to the empty spot in a handoff that happened several steps earlier.

The second is inconsistent format. With no agreed structure, every message is a fresh act of interpretation. The receiver is handed a block of text and left to parse intent out of it, guessing at where the task ends and the constraints begin, or whether a sentence is an instruction or an aside. Even when all the necessary information is technically present, the absence of a shared shape means the receiver may extract it wrongly, and there is no way to tell a well-formed message from a malformed one because there is no definition of well-formed.

The third and most dangerous is implicit assumptions. The sender operates with a mental model of what the receiver expects and how it behaves, and that model is imperfect. Nothing in an unstructured exchange forces the mismatch into the open. The sender writes for the receiver it imagines, the receiver reads as the agent it actually is, and the gap between those two stays invisible until some later output is wrong in a way neither agent can explain. A structured schema attacks all three at once. It makes the required content explicit so nothing load-bearing can be silently omitted, it fixes a shared shape both sides rely on, and it forces the sender to state its assumptions as fields rather than leave them in its head.

A well-formed message carries what the receiver needs to act and nothing more

Once you accept that the message is a contract, the design question becomes concrete: what does it contain? The answer is governed by a single test applied field by field. Does the receiver need this in order to complete its task? If it cannot act correctly without a piece of information, that piece belongs in the message. If it can, that piece does not.

On the side that belongs in, four kinds of content recur. There is the task itself, an unambiguous statement of what the receiver is being asked to do. There is the context the task depends on, the specific facts and prior results without which the task cannot be carried out. There is the shape of the expected output, so the receiver produces something the next stage can consume rather than something merely plausible. And there are the constraints that bound a correct answer, the limits and requirements that separate an acceptable result from an unacceptable one. These are not a template to fill in mechanically. They are the categories the include test tends to select, because they are the categories a receiver genuinely cannot proceed without.

On the side that stays out is nearly everything else, and this is the part that is easy to get wrong out of a misplaced sense of thoroughness. The sender’s full conversation history does not belong in the handoff. Neither does the sender’s internal deliberation, the reasoning it went through to arrive at the task, the intermediate states it passed through, or context it happened to be holding that the receiver’s task does not touch. None of that improves the receiver’s work. It inflates the cost of every handoff, it introduces noise the receiver has to read past, and it makes the message harder to parse and harder to validate. The instinct to pass more so the receiver is never caught short is exactly the instinct to resist. The target is everything the receiver requires and not one thing past it.

Under-specify and it guesses; over-specify and it drowns

The include-versus-exclude decision is not a matter of taste, because erring in either direction produces a distinct and damaging failure mode. They sit on opposite ends of the same axis, and good schema design is the act of finding the point between them.

An under-specified handoff leaves the receiver without enough to act on. It does not respond by refusing. It responds by filling the gap with something invented, because a model handed an incomplete task will produce a complete-looking answer regardless. The missing constraint becomes a guessed constraint, the absent fact becomes a fabricated one, and the result is a hallucinated or simply wrong output that carries no signal that anything was missing. Under-specification fails loudly in its consequences and silently in its cause.

An over-specified handoff fails from the other direction. The receiver now has everything it needs, but it also has a great deal it does not, and the excess is not harmless. Every additional token costs money and time on a path that may run many times. More corrosively, irrelevant content crowds the signal, and the receiver has to sort one from the other before it can act. What the receiver must act on is now buried in material that looks equally like input, and the model has to do the work of separating them, work it may do imperfectly. A message that contains the answer along with ten things that are not the answer is not obviously better than one that contains only the answer; often it is worse. Threading the needle means passing enough that the receiver never has to assume, and no more, so that nothing in the message pulls against the part that matters. A schema works when the receiver can act on it without inventing anything: every fact it reaches for is already present, and no gap is left for it to close on its own.

A contract binds to an interface, not to a particular agent

There is a deeper property that separates a schema that ages well from one that calcifies, and it is borrowed directly from how durable software interfaces are designed. A message schema should describe what the task requires and what the output should look like, and it should say nothing about which specific agent will do the work.

The failure this prevents is tight coupling. When a schema contains fields that only one particular receiver knows how to interpret, or is shaped around the internal quirks of a specific implementation, the schema and that implementation are fused. You cannot substitute a different agent, a newer model, or a more capable version without rewriting the schema, and rewriting the schema means updating every sender that produces messages in that format. A design choice that looked local turns out to have wired the whole system together. The alternative is to design the contract against an interface: specify the task and the output in terms of what any competent receiver would need, not in terms of what this receiver happens to expect. Any two receivers that honor the same schema then become interchangeable, and that interchangeability, the substitutability of one conforming implementation for another, is precisely what lets a multi-agent system be upgraded a piece at a time. Replace an agent with a stronger one that honors the same contract, and the rest of the system keeps running against that contract, indifferent to which implementation now sits behind it.

A schema has to change without breaking the agents that read it

A contract that can never change is a contract that will eventually be violated by reality, so evolution has to be part of the design from the start rather than a crisis handled later. The foundational practice is to version the schema explicitly: every message carries an identifier for the format it was written in, and the receiver can inspect that identifier to know how to interpret what follows. Without it, a receiver faced with a message has no way to tell whether it is looking at the format it expects or a different one that happens to resemble it, and schema changes become indistinguishable from corruption.

Versioning alone is not enough; the receiver has to be built to tolerate variation. It should treat missing optional fields as an expected condition and continue sensibly, rather than crashing the moment a field it can work without turns out to be absent. That tolerance is what lets senders and receivers move at different speeds during an incremental rollout. Required fields are a sharper matter. A new required field cannot simply be added, because the instant it becomes mandatory, every message from any sender that has not yet been updated is invalid. Adding a required field is therefore a coordinated migration, not an edit: the senders that produce the format have to be moved before, or together with, the receivers that begin to demand it.

The property that keeps all of this stable during change has a precise meaning, and it is worth stating exactly because it is easy to invert. Backward compatibility means a receiver running the new schema can still correctly read messages produced by senders on the older schema. That is the guarantee that lets a system be updated incrementally: you can advance the receivers ahead of the senders, and the not-yet-updated senders keep working because the new receiver still understands what they emit. It is the difference between a schema change that ripples out as a routine, staged update and one that forces every agent in the system to be redeployed in lockstep for a single field.

A bad handoff is cheapest to catch at the boundary that produces it

A schema is a claim about what will be true of every message, and like any claim it can be checked before it is relied on rather than discovered false in production. The cheapest check is the presence check: nothing leaves the sender until the message is confirmed to carry every field the schema marks mandatory. This catches the most common and most damaging failure, the missing-context handoff, at the boundary where it originates instead of several steps downstream where its cause is nearly untraceable.

Beyond presence, the schema lets you interrogate sufficiency without paying to run the full system. You can simulate the receiver against the schema alone, asking whether a message that satisfies the contract carries enough for the intended output to be producible, and answer the question at design time rather than by watching a live agent fail. And you can test the failure path deliberately, by constructing messages with fields intentionally omitted and confirming that the receiver degrades in a controlled way instead of crashing or, worse, silently skipping the work and reporting success. Taken together these are the least a multi-agent system can do to test its own seams. They convert handoff mismatches from silent production failures, which are among the hardest defects to diagnose because the symptom appears far from the cause, into ordinary test failures caught before deployment. The cost of writing them is small, and it is paid against the far larger cost of tracing a broken handoff through a running system after the fact.

The contract is the system

It is tempting to treat message design as plumbing, a detail to be handled once the interesting agents are built. That inverts the actual importance. In a single-context system the agent is the thing that matters, because coordination is implicit and nearly free. In a multi-agent system the coordination stops being free, and the schema is where it lives. What each agent can assume, what it must be told, whether it can be swapped for a better one, whether the system can evolve without a coordinated redeploy, whether a failure is caught at its source or discovered three steps away: all of it is decided by the contracts between agents, not by the agents themselves. Design those contracts as deliberately as you would design a public API, because that is exactly what they are, and the reliability of the whole system is the reliability of its weakest handoff.