Shared Memory Between Agents: Designs That Actually Hold
Agents that share a scratchpad drift, overwrite and confuse each other. Here are four shared-memory designs, what each one breaks, and how to pick.
The first thing people build when they add a second agent is a shared scratchpad. One JSON blob, every agent reads it, every agent writes to it. It works for about a week.
Then two workers write in the same second and one edit vanishes. Then a worker reads a plan that a sibling has already invalidated. Then the blob grows past the point where anyone can afford to put it in a prompt, and someone adds a summariser that quietly deletes the field the third agent depended on.
None of that is an agent problem. It is a distributed state problem, and it has the same answers it has always had: decide who owns each piece of data, decide how conflicts resolve, and decide what happens when a reader sees a stale copy.
What agents actually need to share
Before choosing a mechanism, separate the categories, because they have different consistency requirements and lumping them together is what makes the scratchpad rot.
Facts are discovered and immutable: the database schema, the file that owns the retry limit, the failing test name. Facts append. Two agents discovering the same fact is harmless, and a fact never needs to be overwritten, only superseded with a newer observation and a timestamp.
Decisions are chosen and exclusive: the interface signature everyone will code against, the library the project will use. Decisions need a single owner. If two agents can both decide, they will decide differently and both proceed confidently.
Progress is claims and status: who is working on what, which subtask finished, what failed. Progress needs atomic updates because it is the thing agents race on.
Artefacts are the actual output: files, patches, reports. These belong on disk or in a store, not in the shared context. Pass references, never contents.
Design one: the blackboard
A single append-only log that every agent can write to and read from. Each entry carries the author, a timestamp, a type and a body. Nothing is ever mutated in place.
Append-only is what makes this survivable. Lost updates become impossible, and any agent can reconstruct the current picture by folding the log. Debugging is genuinely pleasant, because the log is a trace of how the system reached its conclusion, which is the same thing you would want from tracing an agent run anyway.
The failure mode is growth. A blackboard that ran for an hour does not fit in a prompt. You need a read view — the last N entries plus a rolling summary of what came before — and the moment you have a read view you have all the questions covered in context compaction, just with more writers.
Design two: message passing with no shared store
No shared memory at all. Agents send each other structured messages and hold only their own state. This is the safest design and the one most production systems converge on.
It removes the entire class of race conditions, because there is nothing to race on. What crosses the boundary is explicit, so it is reviewable, loggable and replayable. It also composes with handoff patterns cleanly, since a handoff is just a message with the working set attached.
The cost is duplication. Two agents that need the same forty facts each carry their own copy, and copies drift. It also pushes work onto the message design: whatever the sender forgets to include is something the receiver will invent.
Design three: single writer, many readers
One agent owns the state. Workers read a snapshot and return proposals rather than edits. The owner applies them.
This is the pattern that keeps orchestrator-worker designs from tearing themselves apart. Workers get parallelism on the expensive part — reading, searching, reasoning — while the part that must be consistent stays single-threaded. Conflicts still happen, but they happen in one place, in code you wrote, rather than in whichever agent got there last.
Snapshot staleness is the residual risk. A worker planning against a snapshot from four minutes ago may return a proposal that no longer applies. Version the snapshot, send the version back with the proposal, and have the owner reject proposals built on a superseded view.
Design four: scoped namespaces
Partition the store so each agent owns a prefix it alone may write, and everything else is read-only to it. Shared reads, private writes.
It gives you most of the convenience of a blackboard with none of the lost updates, and it doubles as a security boundary in the same way a narrow toolset does when you are worried about untrusted content reaching an agent. A compromised worker can corrupt its own namespace and nothing else.
Partitioning only works if the work partitions. If two agents genuinely need to co-own a value, a namespace scheme just relocates the argument.
Rules that hold across all four
Write facts, not conclusions. A worker that stores "the retry limit is set in config/http.ts line 41" gives siblings something checkable. One that stores "retries are fine" gives them a claim they cannot verify and will not question.
Attribute and timestamp everything. When two entries disagree, the resolution rule needs data to work with, and "the more recent observation from the agent that actually read the file" is a rule you can implement.
Keep the shared surface small enough to fit in a prompt with room to spare. If the shared state is competing with the task for context, you are paying for coordination with the capacity you needed for the work, and the same context management pressures apply.
Choosing
Default to message passing. Add a shared store only when you can name the specific duplication it removes.
If you need a store, make it append-only and give writes an owner. If several agents must write, give each a namespace. Reserve the free-for-all scratchpad for prototypes you intend to throw away, and be honest that you intend to throw it away.
Common questions
Can two agents safely write to the same shared state?
Only with a mechanism that makes lost updates impossible: an append-only log, or a namespace each agent owns exclusively. Two agents mutating the same field in place will silently drop one of the writes.
Should shared memory live in the prompt or in a database?
In a store, with a small read view rendered into the prompt. Putting the whole state in context works until it does not fit, and the summariser you then bolt on tends to delete exactly the field some agent depended on.
What is the difference between shared memory and a handoff?
Shared memory is continuous and read by many agents at once. A handoff is a one-time transfer of a working set to a single successor. Handoffs are easier to get right because the transferred context is explicit and reviewable.