DEV Community

Cover image for Best Memory Layer for Multi-Agent AI Systems With Shared Context
Statewave
Statewave

Posted on

Best Memory Layer for Multi-Agent AI Systems With Shared Context

The best memory layer for a multi-agent system is the one that keys memory to the subject rather than the agent, returns the same context to concurrent callers, enforces per-caller policy below the agents, and records which memories reached which agent. Scored on those four, Statewave leads, ahead of Mem0, LangMem, Graphiti and Letta.

We went looking for one specific primitive in each of these five projects, reading their repositories and public docs rather than their landing pages. The finding: we could not locate a documented per-caller policy primitive in any of the four alternatives. Every one of them can share memory between agents. We found no way in their public docs to say "the billing agent sees this memory and the FAQ agent does not" inside the memory layer itself.

That gap is the whole subject of this post, because it is the requirement that only appears once you have more than one agent.

Disclosure: we build Statewave. Every claim below about another project comes from that project's public repository or documentation, so you can check each one yourself.

Why does multi-agent memory need different properties?

Single-agent memory has one reader. Multi-agent memory has several readers with different privileges, arriving concurrently, contributing facts that the others will act on. Three failures follow, and none are fixed by a bigger context window.

Cross-agent amnesia. A researcher agent gathers requirements over six turns. A coder agent picks up the task with none of it, and the user re-explains.

Retrieval drift between callers. Two agents ask the same question about the same customer in the same minute and get different context, so they reach different conclusions from identical underlying facts. Now you are debugging a disagreement neither agent caused.

Uniform visibility. Every agent that can read the pool can read all of it, including the contractor's coding agent and the public-facing FAQ bot.

What are the four requirements?

Memory keyed to the subject. The unit of memory should be the entity it concerns, a customer or an account or a repository, not the agent that recorded it. Key memory by agent, and sharing becomes copying, and copies drift. Key it by session and it dies with the session.

Determinism across concurrent callers. The same subject, task and token budget returns the same bytes to every agent that asks.

Per-caller policy. A rule layer below the agents that decides, per request, whether a memory is passed, redacted, or denied based on who is asking.

Cross-agent audit. A record of which memories entered which agent's context, under which rules, at what time. A chat transcript is not this artifact.

Which memory layer handles shared context best?

Subject-keyed Deterministic Per-caller policy Cross-agent audit
Statewave Yes, subjects are the primitive Yes, documented contract Yes, labels plus policy bundles Yes, state-assembly receipts
Mem0 Yes, user and agent scoping Not advertised Not found in public docs Request-level audit log, not per-memory
LangMem Yes, store namespaces Not advertised Not found in public docs Not surfaced
Graphiti Graph-wide, not subject-scoped Not advertised Not found in public docs Edge validity only
Letta Per-agent by design Not advertised Not found in public docs Not surfaced

1. Statewave

Statewave

Statewave organizes everything around subjects, the entity memory is about. Four agents reading customer-8821 see one pool of episodes and compiled facts, so sharing is the default rather than a protocol you write.

Determinism comes from moving the work off the query path. Episodes compile into typed memories once per subject change, and context assembly ranks those compiled memories by kind priority, recency, task relevance, temporal validity, and semantic similarity. Same inputs, same bundle, whichever agent asks.

Per-caller policy is the piece that separates it here. Memories carry sensitivity labels such as pii, financial, and secret. Every context request carries a caller identity. A declarative YAML policy bundle, content-hashed and immutable, decides per request whether each memory is denied, redacted, or passed. Policies run in log_only mode first, recording what they would have filtered, before anyone enables enforcement.

Cross-agent audit is the state-assembly receipt: an immutable record of which memories and episodes went into one specific bundle, hashed, with the policy snapshot attached.

Where it costs you: cross-subject retrieval is not first-class. An agent needing facts about both Alice and Acme makes two calls. Subject granularity is a real design decision and getting it wrong means re-modelling later.

Fits systems where agents have different privileges or the data is sensitive.

2. Mem0

Mem0

Mem0 supports user, agent and session scoping, so several agents can read one user's memory pool. It ranks second because that sharing works and the API is small enough to wire up quickly.

It ranks below Statewave on the second half of the list. Determinism is not advertised, and the composition of the vector store, graph layer and reranker is not broken down publicly, so two concurrent callers have no documented guarantee of identical context. We found no per-caller policy primitive: the self-hosted server issues per-user API keys, which authenticate a caller rather than decide which memories that caller may read, and Entity-Scoped Memory, which partitions the pool by user, agent, app or run, is marked platform-only. On audit it is closer than the rest of the field: the self-hosted stack keeps a request audit log. That is a record of calls, not a record of which memories entered which agent's context.

Fits multi-agent systems where every agent is trusted equally.

3. LangMem

LangMem

LangMem gives LangGraph applications a store with namespaces, which is a clean sharing boundary when every agent lives inside LangGraph.

The constraint is the boundary itself. A LangGraph support agent, an OpenAI Agents SDK sales copilot and a custom Express service should share one memory surface, and the shared store reaches only the first. The package splits in two here, and the distinction is worth naming: LangMem's core primitives are storage-agnostic and travel into any application, while the shared memory that agents actually read is LangGraph's own long-term memory store. The portable half travels; the shared surface does not. Ranking, budgeting and provenance on top of the store are code you write.

Fits teams whose agents all run inside one framework.

4. Graphiti

LangMem

Graphiti tracks when facts became valid and invalid across a temporal context graph, which handles the stale-fact problem well when several agents write to one graph.

It ranks fourth for multi-agent work because the graph is global rather than subject-scoped, so isolating one entity's context is a traversal you design. Per-caller filtering is application code above Graphiti, whether you embed the package or run its REST service.

Fits shared-context systems where entity relationships carry the meaning.

5. Letta

Letta

Letta is a stateful agent runtime with the MemGPT lineage, and it is strong at what it does. For this scorecard it ranks last because its memory model is per-agent by design: memory belongs to an agent rather than to an entity several agents share.

Multi-agent sharing in that model means passing state between runtimes rather than reading one pool.

Fits teams that want a complete agent runtime and whose agents do not need a common memory surface.

How do you choose?

  1. Do your agents have different privileges? If yes, per-caller policy is the binding requirement and it narrows the field to one.
  2. Do agents run in more than one framework? If yes, the memory layer has to be an HTTP service, which rules out framework-native stores.
  3. Will anyone ask which agent saw what? If yes, you need receipts, not logs.
  4. Are your agents symmetric and your data non-sensitive? Then requirements three and four do not bind, and Mem0 or LangMem is the faster path.

Being straight about our own gaps: tenant isolation is query-scoped at the application layer rather than Postgres row-level security, rate limiting is keyed per IP, and there is no admin-action identity yet, so label promotions record when but not who. One more, since it touches the audit argument above: receipt replay re-runs the original retrieval against today's memories using the original policy bundle, which is not byte-for-byte historical reproduction. Any of those may disqualify the approach for your compliance posture.

No neutral, third-party benchmark covers all five on the same multi-agent task, ours included. The scorecard above is a documentation review, and the honest way to use it is as a list of questions to ask each vendor.

Statewave is Apache-2.0 and self-hosted on Postgres. Many agents point at one memory service over HTTP or MCP, and your orchestration stays where you built it.

Top comments (0)