Cross-agent memory
The term has a GitHub topic and ten repositories in it, and no written definition anywhere. So here is ours, followed by the part nobody publishes: what about it can be measured today, and what cannot.
The definition we are working to
Cross-agent memory is one memory store that several agents write to and read from, where a fact written by one agent can be retrieved by another. That is a weaker claim than it sounds, and it decomposes into three properties that are usually asserted together and are worth separating, because they fail separately:
- Shared substrate — the agents address the same store rather than one file or namespace each. Cheap. Almost everything in the category has this.
- Attribution — the store knows which agent wrote a given fact. Without it there is no provenance, no per-agent trust, no way to answer "who told us that".
- Reach — a fact written by agent A is actually retrieved when agent B has the need it answers. This is the only one that determines whether sharing paid off, and it is a retrieval-quality question, not an architecture question.
Substrate is a design decision you can read off a compose file. Attribution and reach are measurements. Substrate we have always had; attribution we shipped this week and can now report; reach we still cannot measure at all — and the reason is worth more than a number.
What one production store looks like
Read from a live store on 26 August 2026: 22 agents, 58 days of continuous work (29 June — 26 August), 8,810 facts extracted from 1,015 documents, 3,885 entities, 201,154 links, 17 rooms.
The interesting part is not the totals, it is where the edges go. Every link in the graph joins two facts that each carry a room, and most of them cross:
| Link type | Crosses a room | Stays inside one | Cross share |
|---|---|---|---|
entity | 31,446 | 13,872 | 69.4% |
semantic | 51,425 | 26,400 | 66.1% |
temporal | 40,760 | 37,249 | 52.3% |
caused_by | 0 | 2 | — |
| All | 123,631 | 77,523 | 61.5% |
The busiest boundaries are agent ↔ shared (17,371 edges),
deployment ↔ shared (12,771) and infrastructure ↔ shared (8,034).
shared is the hub of the graph, which is what you would hope for and is not
guaranteed by anything in the design.
Two honest limits on that table, both of which a reader would find anyway:
- These edges are machine-derived — cosine similarity at or above 0.7, a time window, or a shared entity. 61.5% says the corpus is topically entangled: work in one area constantly refers to facts stored under another. It does not say an agent used another agent's fact. Two of 201,154 edges express a causal relation somebody asserted.
- All 201,154 edges live among the 4,742 facts that carry a room. The other 4,068 —
all of them
L2, the raw observation queue — have no edges at all. The graph is a property of classified memory, not of the store's volume. - The share is stable rather than a lucky reading. Two days and nine thousand new edges later it is 61.5% again, to the decimal. Whatever this measures, it is a property of how the fleet works and not of the day we looked.
One of three fixed, two to go
The number a buyer actually wants is how often does a recall return something a different agent wrote. When this page first went up it was not computable, for three separate reasons. One of them is now closed.
Authorship is recorded, as of 24 August 2026. A retained fact carries an
author:<slug> tag minted from the identity the server resolved — not from
anything the caller can write — and a recall can filter on it and echoes it on every result. It
rides a tag rather than the metadata column deliberately: consolidation rewrites facts into
observations and metadata does not survive that rewrite, so the obvious field would have dropped
authorship from exactly the records the engine produces on its own.
Two bounds, both checkable. It is not retroactive — 243 of 8,810 facts in this store carry an author, and the 8,567 written before it existed carry none, which is why a read filtered by author excludes unattributed facts unless you ask for them. And it currently lives in the client layer our own fleet calls, not in the packaged MCP server, which gets it with the first release. Both are on the roadmap.
The other two reasons stand:
- No read is recorded.
access_countis 0 on every one of the 8,810 rows — the column exists and is never incremented — and the audit table has 0 rows. After 58 days and a fleet's worth of work, the store cannot tell you which fact has ever been useful. Upstream removes that column in 0.9.x, which is a defensible cleanup of a field nobody was writing, and it does mean read telemetry has to be built rather than switched on. A counter is the wrong shape anyway: the question is not how many times but returned to whom, which wants an append-only row per read. - A room is a topic, not an identity. The engine's own type declaration
calls it topic classification; retrieval applies it as
AND room = ANY($n::text[])against whatever list the caller passes; and the classifier assignsroom: "agent"by keyword-matching words like agent, llm and ai in the fact's own text. Soagentis the room for facts about agents, and every agent writes into the same one. Identity now has its own axis, which is the right fix — but a room still is not a scope, so there is nothing here to measure isolation against, and we are not going to invent one.
Put together: the write side now says who, the read side still says nothing at all, and the axis that looks like identity remains a subject label. So a handoff is recorded and still not observed — we can now say who wrote a fact, and not whether anyone ever read it. That is one field of distance from the measurement, rather than three, and it is worth being precise that the distance is not zero.
The only cross-agent signal that exists today
Not from the store — from the client's log, which records the tool name per call: 939 writes and 195 reads across 72 conversations, 1,134 memory calls in all. A fleet that writes 4.8 times for every time it reads.
We do not know what to conclude from that yet, and say so. It is consistent with memory being cheap to add to a workflow and easy to forget to consult; it is equally consistent with a healthy ratio for a store whose L0 layer is injected at session start without a recall call. The log rows carry a job and a conversation id, so the writer is recoverable by joining them against the orchestrator's own tables — an offline reconstruction, not instrumentation. That reconstruction is the first thing on the list below.
Three fields, and then it is measurable
Carry the caller into the item.Done. Attribution on write — the value was already in scope at every call site that mattered, and went to a log line instead of into the payload.- Record reads. Which facts came back, for which query, to whom. In our fork this could stay on the fact; a separate append-only table is the better shape, since a counter cannot answer "returned to whom".
- Log the recall payload — query, rooms, returned ids. This one is retroactive in effect: turn it on and the handoff dataset accumulates by itself.
None of them is research. All three are the difference between a product that claims fleet memory and one that can show it — and the first one took a day, which is a fair indication of how long this gap had been nobody's task rather than nobody's idea.
The suite we intend to run once they land
| Measure | What it answers | Metric |
|---|---|---|
| Handoff rate | What share of recalls return at least one fact written by a different agent | %, per agent and per room |
| Isolation | Whether a scoped read can return a fact it should not see | leak rate, target 0 |
| Handoff retrieval quality | On queries whose evidence was written by another agent, how good is retrieval | nDCG@10, recall@20 |
| Silo ablation | The same query set against a per-agent silo versus the fleet store | delta on the above — done, on a public dataset |
The metrics are deliberately the same ones as our retrieval numbers, so the results land in the same units and can be read next to each other rather than next to a different paper's scale. The silo ablation is the control that every shared-memory product's pitch implies and none of them runs; it is also the one that can come out against us, which is why it was on the list.
That one is now run, and it did come out partly against us. On LoCoMo, pooling ten conversations into one store costs measurable ranking quality against ten private stores; scoping the query to the right room recovers about half of it and does not reach parity. On the configuration RCLL actually ships — fusion with a reranker — the cost is 1.9% relative unscoped and 1.2% with the room filter, and 93% of questions score identically to a private store. On fusion alone, without the reranker, the same two figures are 5.7% and 3.0%, which is the pair we would have published had we not run the arm we ship. Pointed at the wrong room, retrieval returns nothing at all. It is run on a public dataset rather than on our own store, which means it measures the retrieval half of the question and not the handoff half — the other three rows still need items 4 and 5, because they ask about reads that only our fleet performs. Full ablation, five arms →
Why publish the gap instead of waiting
Because it is checkable. Every claim on this page can be verified against a clone of the source and a store of your own: the author tag and the facts that lack it, the zero read counter, the room filter, the classifier's keyword list. And because a category with ten repositories in it and no agreed definition is going to get one from whoever writes it down — we would rather it be a definition that separates the easy property from the two hard ones than one that treats all three as shipped.
If you are measuring the same thing and got further, we would rather hear it than not: the numbers above are a floor, not a position.