Agents need a shared language
A multi-agent system splits a task across specialized agents — a planner, a researcher, a writer, a critic. For them to cooperate, they must exchange information in a structured, predictable way. That medium is JSON: a shared state object and well-defined messages that each agent reads and updates.
Design a shared state object
Rather than passing free-form text between agents, maintain a single JSON state that flows through the pipeline:
{
"task": "Write a launch announcement for JSONKit's new extension",
"status": "drafting",
"research": [
{ "fact": "Extension auto-formats JSON pages", "source": "spec" }
],
"draft": "JSONKit now ships a browser extension...",
"critique": null,
"history": ["planner", "researcher", "writer"]
}Each agent reads the fields it needs, writes the fields it owns, and passes the object on. The history array records the hand-off path for debugging.
Define the hand-off contract
Each agent should have a clear input/output contract expressed as JSON:
| Agent | Reads | Writes |
|---|---|---|
| Planner | task | status, plan steps |
| Researcher | task, plan | research[] |
| Writer | task, research | draft |
| Critic | draft | critique, status |
Validate the state against a schema between hand-offs so a malformed update from one agent does not silently corrupt the run.
Messages vs shared state
Two patterns coexist:
- Shared state (blackboard): all agents read and write one evolving JSON object. Simple, great for linear pipelines.
- Message passing: agents send each other typed JSON messages (
{ "from": "planner", "to": "researcher", "payload": {...} }). Better for dynamic, conversational coordination.
Many systems use both — a shared state for the artifact, messages for control flow.
Keep agents focused with tight schemas
The reliability lessons from single-agent tool design apply doubly here: give each agent a narrow responsibility and a strict output schema. A researcher that must return research as an array of { fact, source } objects is far more controllable than one asked to "add some research." Validate every agent's output before merging it into the shared state.
Orchestration and termination
A coordinator (itself often an LLM or a simple state machine) decides which agent runs next based on status. Define explicit terminal states (done, failed) and a maximum step count, because agent loops can otherwise run — and bill — indefinitely. Log the state at each step so you can replay a run that went wrong.