An agent that remembers needs four things: somewhere to put raw events, something that turns them into facts, a way to retrieve those facts under a token budget, and a framework to run the loop. No single tool does all four well, which is why this list is eight tools and not one.
We build Statewave, an open-source memory runtime, so treat the entry about us accordingly. Everything below is Apache-2.0, MIT, or the PostgreSQL License, verified from the LICENSE file rather than the badge, checked on 1 September 2026. MCP is mid-transition from MIT to Apache-2.0.
Grouping below is by what each tool owns, because the most common mistake in this category is picking two tools that own the same layer and none that own the missing one.
The memory layer
1. Statewave
A memory runtime that sits behind your agents over HTTP. You send raw events as episodes; it compiles them into typed memories with confidence scores and validity windows, and you request a ranked, token-bounded bundle when you need context.
from statewave import StatewaveClient
| with StatewaveClient("http://localhost:8100") as sw: sw.create_episode(subject_id="user-42", source="chat", type="message", payload={"text": "Alice asked about pricing tiers"}) sw.compile_memories("user-42") print(sw.get_context("user-42", task="answer pricing", max_tokens=1000).assembled_context) |
|---|
What it owns: storage, consolidation, ranked retrieval, conflict resolution, provenance. What it deliberately does not own: your agent loop. Storage is Postgres with pgvector and no separate vector service. npx @statewavedev/statewave boots the API, admin console, and Postgres locally. The server defaults to demo mode with stub hash-based embeddings and the heuristic compiler, which means no real semantic search but a working loop.
Determinism is the property we care most about. The same subject, task, and token budget return the same bytes, which is what makes retrieval regression-testable.
Where it costs you: cross-subject retrieval is two calls, and the default compiler is heuristic regex. Switch to STATEWAVE_COMPILER_TYPE=llm for better extraction from messy conversation, or keep the heuristic compiler deliberately if no customer text may leave your network.
2. Mem0
Mem0 is the shortest path from nothing to an assistant that remembers a user. Its API is four calls wide: add, search, update, delete. Apache-2.0 for the library, with a managed platform sold separately.
Pick it when time to first working result matters more than being able to explain a specific retrieval later. Composition of its vector store, graph layer, and reranker is not broken down in public docs, so auditability means reading source.
3. Graphiti
Graphiti is a temporal knowledge graph that tracks when a fact became valid and when it stopped being true. That is a real answer to stale memory, which most fact stores handle by overwriting and hoping.
A note that saves evaluation time: many lists point to getzep/zep for this project. That repo’s README describes itself as examples for the managed Zep Cloud rather than the product, checked 1 September 2026. Graphiti is the self-hostable piece.
4. Cognee
Cognee builds a self-hosted knowledge graph with ontology grounding, combining embeddings with graph reasoning. Apache-2.0.
Reach for it when the relationships between entities carry the meaning, not just the facts about each one. It is more machinery than a preference store needs.
The orchestration layer
5. LangGraph
LangGraph models agents as state machines with explicit nodes and edges, which makes multi-step flows debuggable in a way that a while-loop over tool calls is not. MIT.
Its checkpointer handles per-thread state well. Worth being precise about the boundary: thread-level persistence is not the same as cross-session, cross-agent memory, and conflating them is how teams end up with an agent that remembers a conversation but not a customer.
6. Letta
Letta carries the MemGPT lineage and is a stateful agent runtime rather than a memory layer. It owns the reasoning loop, tool calls, and context management. Apache-2.0.
Check what you are adopting before you commit to it. letta-ai/letta now describes itself as a landing page for the project, with the retired Letta V1 server preserved on an archive branch and marked unsupported and not for production use. The current path is the hosted platform and the Letta Agent SDK, so Letta is no longer the self-hostable “one decision instead of four” it used to be.
The protocol and storage layers
7. Model Context Protocol
MCP is the piece people skip, then rebuild badly. It is an open protocol for exposing tools and data to LLM clients, built on JSON-RPC.
Why it belongs on a memory list: if four agents in three frameworks need the same memory, a protocol endpoint is what stops you writing three adapters. We expose Statewave over MCP for exactly this, so a Claude custom connector and a Python agent hit one memory service without either knowing about the other.
8. pgvector
pgvector adds vector types and distance operators to Postgres. Not glamorous, and it removes an entire moving part from your architecture.
One detail worth knowing: use an HNSW index rather than IVFFlat for anything that grows. IVFFlat recall depends on lists and probes matching your row count, so a corpus that outgrows its tuning quietly returns worse neighbors. We migrated for that reason and wrote up the details in the Postgres post.
How to assemble these
Stacks that work: pair one tool per layer:
● Fast prototype: LangGraph plus Mem0. Two decisions, working today.
● Self-hosted with audit requirements: your framework plus Statewave on Postgres and pgvector, exposed over MCP.
● Relationship-heavy domains: Graphiti or Cognee for memory, LangGraph for orchestration.
A common anti-pattern is picking Letta and Mem0 together, or LangGraph checkpointers and expecting cross-session memory. Both are two tools fighting over one layer while a different layer stays empty.
If you want the working code rather than the list, we keep three runnable demos: multi-agent memory with conflicting sources and automatic supersession, multi-agent shared context where a planner and coder stop contradicting each other, and a personal assistant that boots in five minutes without an LLM key.
No neutral, third-party benchmark compares these on the same task with the same corpus. Ours covers a subset and we ran it, which is exactly why it is not the one to settle your decision. Run the eval on your own data before committing to any of them.








Top comments (4)
Grouping by ownership layer is the right way to compare these. I would also test each tool with the same deliberately conflicting history: one fact changes, an old instruction is revoked, and two agents write different interpretations. That reveals whether the system stores text or actually manages state.
That's a sharper test than most published benchmarks, because each case breaks a different assumption. How it lands for us, honestly:
A fact changes: handled. At compile time the newer fact supersedes the older one when the two overlap closely enough in wording or share a claim key. The old one isn't deleted; it stays in the store, marked superseded, with its validity window closed.
An instruction is revoked: depends on the wording. A revocation only supersedes the instruction if it overlaps it closely or hits the same claim key, and a negation often doesn't, because "stop doing X" and "do X" share fewer words than you'd expect. An instruction that simply lapses, with no newer write at all, is never superseded.
Two agents disagree: resolved, not reconciled. The newer write wins and the older one stays as superseded. Nothing judges which interpretation is right; recency does.
So on your scale: state for the first case, closer to text for the second, and an ordering rule for the third. The revoked instruction is the one I'd most like to see run against all eight tools, ours included.
That is an excellent fault line. Recency is deterministic, but revocation is semantic and can fail exactly when the wording diverges. I would make the shared test adversarial: original instruction, paraphrased revocation, expiry without a replacement, and conflicting same-time writes. Report both the compiled state and the full provenance chain. If all eight tools behave differently under the same cases, that comparison would be genuinely useful. Happy to help shape the cases.
Your four cases are sharper than your original three, and "recency is deterministic, revocation is semantic" is the cleanest way I've seen it put.
First, a correction to my last reply, because your fourth case exposed it. I wrote that when two agents disagree, the newer write wins. That only holds when the two writes overlap closely in wording or share a claim key. Two genuinely different interpretations usually don't, so both stay active and the agent sees both, unreconciled. That's closer to text than I made it sound.
For the two you added:
Expiry without a replacement: once a fact's validity window closes, it drops out of retrieval. Nothing takes its place, and nothing in the bundle says something expired, so the agent simply stops knowing it. Clean, but silent.
Same-time writes: when they do count as conflicting, the tie breaks deterministically, on each write's stated start of validity and then on its record ID. Reproducible, but on a true tie nothing about the content decides which one wins.
On reporting: the compiled state and each memory's source episodes we can show. If you sketch the four cases as concrete inputs, I'd like to see them, the paraphrased revocation first, since that's the one we already expect to miss.