We ran 751 agent sessions against one shared memory, and the writes do not collide
Most teams run one AI agent at a time because they expect several to overwrite each other's work. The fix is not coordination between the agents. It is refusing to let anything important stay inside the conversation, plus a write gate that blocks a save when the file moved underneath you.
1. The problem, and who has it
The whole promise of agents is that you run several and get several things done. Almost nobody does. They run one, wait, then run the next, and the speed they were sold never arrives.
The reason is reasonable. Two agents working the same project will eventually touch the same thing, and when they do the usual outcomes are all bad: one overwrites the other's conclusion, both do the same job from scratch, or one acts on something that stopped being true an hour ago. None of those announce themselves. You find out a week later when a number does not add up, and by then neither you nor the agents can reconstruct which version was right.
This is not a new class of problem. It is the one every team with a shared spreadsheet has had, and the resolution is the same one: stop keeping the authoritative version in anybody's head.
2. The rule
Nothing important is allowed to stay inside the conversation.
Every conclusion an agent reaches gets written out of its session and into its own small file, one fact per file, in a local git repository. Each file carries its own frontmatter: a name, a one-line description, the area it belongs to, and the session that wrote it. The commit message records which session changed what and why. It is closer to keeping minutes than to trusting everyone's memory of the meeting.
Three behaviours follow from that, and they are what make parallel work survivable:
- A session starts by reading an index, not by being told what happened. It picks up the area map for the directory it was started in, then opens only the notes the task needs. A new agent begins where the last one stopped.
- A session is told when something it relied on changes. If another session edits a note this one has read, a hook injects that fact on the next message, naming the note and the session that touched it.
- A write that would clobber someone else is refused. This is the part that does the real work, and it is covered below.
We run this as an open-source Claude Code plugin called receipts-wiki. The mechanism is not specific to Claude Code: a directory, a git history, and a hook that runs on file writes is the whole of it.
3. The write gate
The interesting piece is a PreToolUse hook on every write to memory. Before the write lands it compares a content hash of the file on disk against the hash this session saw when it last read the file. If they differ, the write is denied:
current = state.content_hash(path, rel)
seen = state.load(payload.get("session_id"))["reads"].get(rel)
if seen and seen != current:
reasons.append("the file changed after this session read it; read it
again and decide whether your change still applies")
That is optimistic concurrency control, the same compare-and-swap a database uses, applied to prose. An agent cannot overwrite a note it has not seen the current version of. It has to re-read, then decide whether its change still makes sense against what is now there.
The same gate refuses three other categories on the way past: a secret value in the text, injected tool or system output pasted into a note, and a relative date like "yesterday", which goes stale the moment it is written.
4. What it looks like in practice
| what | number | how it was counted |
|---|---|---|
| Agent sessions | 751 | session records in the plugin's state directory |
| Notes | 356 | files in the memory directory |
| Changes per day | 24 | mean of 362 commits over 15 days, 20 Sep to 4 Oct 2026 |
On one ordinary morning the git history looks like this, two sessions on unrelated jobs, interleaved to the minute:
07:44 memory(staysup-content): update reference-graffiti-lettering
07:44 memory(own-thing): update cursor-solana-data-audit
One session was doing strategy research. The other was drawing lettering for this website. Neither knew the other existed and they never exchanged a message.
The payoff shows up at the moment things would normally go wrong. An instruction meant for the lettering session arrived at the research session by mistake, referring to a reference image that session had never seen. The expensive outcome here is the ordinary one: the agent picks the likeliest meaning, answers with complete confidence, and you learn it was guessing much later. What happened instead was that it said the instruction belonged to a different thread, listed the three reference files that had appeared in the working tree that morning with their timestamps, and asked which was meant. It could do that because the notes it was relying on had been changed an hour earlier under another session, and a hook had written that down where it could be read.
5. What it is not
It is not awareness, and it is not autonomy. No model notices anything in this story. A hook wrote a fact to a file, another process read the file, and a wrong answer did not get produced. Calling that awareness would be the kind of claim that falls apart the moment someone checks it.
It is also not complete. Two honest gaps remain:
Clashes are refused, not resolved. The gate stops the overwrite and hands the problem back. Somebody, an agent or a person, still has to read both versions and decide what is true. Git merges text; nothing merges meaning.
A note can be stale without having changed. The system catches the case where a note moved under you. It cannot catch the case where the note sat still while the code, flag or number it describes moved. Our lint flags notes unverified for 90 days and unread for 60, but that is a reminder, not a check. The standing rule is that a memory is what was true when it was written, so files, flags and numbers get checked before anyone relies on them.
6. What to do with this
- If you run more than one AI tool on the same work, decide where what it learns gets written down when the conversation ends. If the answer is "the chat", you are one closed window away from losing it.
- Give the store a read-before-write rule. Even without hooks, a convention that an agent re-reads a file it is about to change removes most of the overwrite risk.
- Keep one fact per file rather than one big document. Small files are what make concurrent writes rare in the first place, because two agents working different jobs usually touch different files.
- Write the position down, not only the conclusions. The thing a dead or interrupted session loses is what it was part-way through.
Reproduce it
The plugin is open source at github.com/B1aZer/receipts-wiki. The write gate is in scripts/rwlib/hooks.py; the per-session read state and the last-read dates are in scripts/rwlib/state.py; the lint thresholds are in scripts/rwlib/cli.py. The numbers above come from counting files in the memory directory and session records in the state directory, and from git log --since="14 days ago" --format=%ad --date=short | sort | uniq -c over the memory repository.
Related: the research atlas · fourteen ways agents fail with every check green · verifying what an agent says it did.