# Multi-agent shared memory breaks on the write, not the read

> Shared memory for several AI agents: the three write shapes, why rewrites lose updates, and how to keep the text an overwrite replaced.

Source: https://baalda.com/blog/multi-agent-shared-memory
Site: Baalda, https://baalda.com
Published: 2026-10-13

**Short answer.** Multi-agent shared memory is one store several agents read and write: a blackboard, a shared block or a database. Reads are easy. The failure is two agents rewriting one entry, where the last write wins and the first is lost. Pick a store whose writes append or target exact text, and that keeps what an overwrite replaced.

Multi-agent shared memory is one store that several agents read from and write to, so that what one agent learns is there for the next one. Reading it is the easy part. It goes wrong on the write: two agents rewrite the same entry, the second write lands on top of the first, and in almost every store on offer the first is simply gone. Every guide that ranks for this question spends its length on where to put the memory and how to retrieve from it. This one is about what happens to it when it is overwritten, which is the problem [Baalda](https://baalda.com) was built around.

## What is multi-agent shared memory?

Three shapes turn up again and again, and they differ more in packaging than in idea.

- **A blackboard.** Agents do not message each other. They all read from and write to one shared space, and each picks up what the others left there. GreenNode's design guide recommends exactly this, with every entry carrying "agent ID, timestamp, confidence score".
- **A shared block.** Letta attaches one memory block to several agents. Its documentation puts it plainly: "Shared memory blocks let multiple agents access and update the same memory. When one agent updates the block, all others see the change immediately."
- **A shared database.** Agno's version is the simplest of all: "Agents that use the same database and memory table can read memories stored for the same `user_id`." Point two agents at one SQLite file and they share memory.

On top of any of these sits a scoping decision: what is global, what belongs to one workflow, what stays private to one agent. Vectorize's Hindsight guide splits it into per-user, per-project and per-team banks. That is all sound advice, and it is all about the read side.

## Where does shared memory between agents actually go wrong?

At the moment two agents change the same thing. One page on the first screen of results says this out loud, and it is Letta's, which deserves credit for it. Its shared memory guide rates its own three editing tools by how safe they are when several agents use them on one block:

| Letta tool | What it does | Safe with several agents? |
|---|---|---|
| `memory_insert` | Appends | "Yes (append-only)" |
| `memory_replace` | Replaces one target string | "Mostly (fails if target string changed)" |
| `memory_rethink` | Rewrites the whole block | "No (last-writer-wins)" |

And then the sentence the rest of the category leaves out: "Multiple agents doing `memory_rethink` on the same block simultaneously leads to lost updates."

That table is the most useful thing on the whole results page, and it generalises well past Letta. Every shared memory write is one of those three shapes. An append cannot destroy anything. A targeted replace fails loudly when the ground has moved under it. A full rewrite is a bet that nobody else wrote since you read, and when two agents make that bet at once, one of them loses.

## Why does the overwritten version usually disappear?

Because in most stores, memory is a row, and a write replaces the row.

GreenNode's guide offers the two standard fixes from distributed systems: "optimistic locking with version vectors, or last-write-wins with timestamps for low-stakes data." The first turns a silent loss into a refusal, which is a real improvement: the losing agent is told, re-reads and tries again. The second is a polite name for the lost update Letta describes.

Neither keeps the text that was replaced. And the dangerous rewrites in a multi-agent system are rarely a race in the same millisecond. They are an agent told to "tidy up the shared notes" that collapses forty lines another agent wrote into four, a summariser that consolidates three findings into one sentence, a worker that read the memory an hour ago and writes back its own stale copy. Optimistic locking only catches the last of those. The first two are perfectly valid writes from a well-behaved client, and afterwards the store holds only the new version. Nobody can see what was dropped, because nothing kept it.

## What does shared memory look like when the agents write files a team owns?

This is where the answer stops being generic. In Baalda the shared memory is a vault of plain markdown notes, the same files the people on the team open in the app, and every agent reaches it over MCP. Each agent gets its own named token from Vault Settings, MCP, and the connections page shows each one with when it was last used, so three agents are three cards you can revoke separately. The full tool list is on the [MCP tool reference](/docs/mcp-tools).

The tools map onto Letta's three shapes almost one for one:

- **`append_note`** is the append. It takes an `idempotencyKey`, so an agent that retries after a dropped connection cannot add the same finding twice.
- **`edit_note`** is the targeted replace. Each anchor has to match exactly once, and a missing or ambiguous anchor refuses the whole call with nothing written. The [post on giving an agent memory](/blog/give-ai-agent-memory) covers how that behaves in detail.
- **`update_note`** is the full rewrite, with an optional `expectedRevision` (the sha256 of the text `read_note` returned) that refuses the write if the note changed since the agent read it.

Two things make the rewrite safer than a row update even before anything else happens. Every note is a CRDT document, so an agent's write takes the same path as a person typing and shows up live in any open editor. And `update_note` is not applied as delete-everything-then-insert. The server computes the smallest single replacement between the old text and the new, and its own source explains why: "a concurrent edit elsewhere in the note merges instead of being clobbered by a delete-all." If one agent rewrites a note to change one paragraph while another agent appends to the bottom, both changes survive.

A typical exchange looks like this: the agent reads the summary note and gets back its markdown plus a revision, appends one finding to the shared log, then rewrites the summary on the condition that nobody has changed it since the read.

```json
{ "name": "read_note", "arguments": { "docId": "n_summary" } }

{ "name": "append_note", "arguments": {
    "docId": "n_findings",
    "text": "\n- Retry storm traced to the queue consumer, not the API.",
    "idempotencyKey": "run-4812-finding-3" } }

{ "name": "update_note", "arguments": {
    "docId": "n_summary",
    "content": "# Summary\n…",
    "expectedRevision": "9f2c…" } }
```

## What happens when one agent wipes out another agent's work?

The server keeps the text from before. This is the part no store on the results page offers.

Whenever a single update leaves a note with 20 percent or less of its text, and the note had at least 200 characters to begin with, the server saves the note as it stood immediately before that update, as a version. It does this on both of its write paths, the live one that carries edits to an open note and the one used when nobody has the note open, so a write arriving over MCP is covered the same way as a person's. In Version History it appears as **Before large deletion**, and restoring it is itself an edit, so the restore can be undone too. The [versions and recovery docs](/docs/versions-and-recovery) describe it from the user's side.

It deliberately does not refuse the write. The comment in the source gives the reason: a CRDT client that has applied an operation keeps it, and a server that dropped it would leave the two sides permanently unequal. So the update lands, and the recoverable half of a refusal is kept instead.

The numbers, as of 13 October 2026:

| What | Limit |
|---|---|
| A note counts as sharply shrunk when one update leaves | 20% of its text or less |
| Notes too small to count | under 200 characters |
| Ordinary versions kept per note | 50, captured after 10 minutes without edits |
| "Before large deletion" versions kept past that cap | the 10 most recent, for 30 days |

So when the tidy-up agent collapses forty lines into four, the forty lines are one click away for the person who notices, a day or three weeks later. The memory is a file a person can read, so somebody can notice, which matters as much as the version itself.

## How should several agents divide one memory?

The write shapes suggest a layout, and it works in any store, not only ours.

1. **Give each agent a scratch area it alone writes to.** One folder per agent for working notes. Full rewrites are fine there, because nobody else is writing.
2. **Make shared findings append-only.** A log note that every agent adds to with `append_note` and nobody rewrites. Appends cannot lose anything, and idempotency keys stop retries from duplicating.
3. **Change shared summaries by anchor, not by rewrite.** When an agent has to correct a line in a note other agents depend on, it uses `edit_note` against the exact sentence, so a stale view fails instead of overwriting.
4. **Keep a person on the notes that decide things.** The decisions note is where agents propose and a person confirms. It is the one place where it matters most that the memory is a document rather than a record.

That last point is what the multi-agent guides leave out altogether. The [Claude Code team post](/blog/claude-code-second-brain-for-a-team) covers the human version of the same problem, two people's sessions writing one note.

## Where does this not help?

Being straight about the limits is the difference between a guide and a pitch, so here they are.

- **Attribution is per person, not per agent.** A token authenticates as one user in one vault. Three agents running on your tokens are three connection cards, but in Version History their edits are all yours. If you need to know which agent wrote a line, each agent has to run as its own member of the vault, with its own seat and its own permissions.
- **The deletion version catches sharp shrinks only.** An agent that rewrites one paragraph wrongly while leaving the length alone is not a large deletion. That case is covered by the ordinary versions, captured after ten minutes without edits, which is coarser.
- **MCP writes never trip the burst brake.** By default the server holds a user's writes in a vault for 30 minutes when ten populated notes are emptied within a minute, on the theory that no person edits that way. Self-hosters can change all three numbers. A tool call is treated as an explicit request, so an agent emptying fifty notes is not stopped. Each note still gets its "Before large deletion" version, but you restore them yourself.
- **It is not an in-process memory.** Every call is a JSON-RPC request over HTTP. For agents inside one framework passing state many times a second, Letta's shared blocks or your framework's own state store are the right tool, and they are faster.
- **There is no automatic extraction.** Nothing watches the conversation and writes facts on the agent's behalf, the way Mem0 or a background consolidation step does. The agent writes on purpose, by calling a tool, or nothing is written.

If your agents are a pipeline inside one process and no person ever reads what they remember, a shared block or a shared table is simpler and you should use one. If several agents and several people need the same memory, and somebody needs to see what changed and put it back, it has to be a document. Overwrites happen either way. The difference is whether the old text is still there afterwards.

## FAQ

### How do multiple AI agents share memory?

By reading from and writing to one store that outlives each run. Letta attaches one memory block to several agents, so "When one agent updates the block, all others see the change immediately." Agno points agents at the same database, where they "can read memories stored for the same user_id". A blackboard is the same idea as a pattern. In Baalda the store is a vault of markdown notes that each agent reaches over MCP with its own token.

### What is a lost update in multi-agent memory?

Two agents read the same entry, both write back a full new version, and the second write replaces the first. Letta's own documentation rates its full-rewrite tool, memory_rethink, as unsafe with several agents for exactly this reason: "last-writer-wins", and "Multiple agents doing memory_rethink on the same block simultaneously leads to lost updates." Appends and targeted replacements do not have the problem in the same way.

### Can I get back what another agent overwrote?

In most memory stores, no: the entry is a row and the write replaced it. In Baalda, when a single write leaves a note with 20 percent or less of its text, and the note had at least 200 characters, the server first keeps the note as it was. It shows in Version History as Before large deletion and the 10 most recent stay pinned for 30 days. Smaller wrong rewrites rely on the ordinary versions, up to 50 per note.

### Can I tell which agent wrote which part of a shared note?

Not if the agents share one person's account. A Baalda MCP token authenticates as one user in one vault, so three agents on your tokens show as three separate connections you can revoke, but their edits are attributed to you in Version History. To attribute writes to an agent, run it as its own member of the vault with its own seat and permissions.
