A 128K-token context window degrades past the first thousand tokens and vanishes the moment the session ends. That single fact is what built a market: agent-memory infrastructure is now a real layer in the stack because "throw it all in the context" stopped scaling. Four frameworks have placed architecturally opposite bets on what to do instead — Mem0 leans on an extraction pipeline and multi-store fan-out, Letta productizes the MemGPT memory hierarchy as an agent-as-a-server, Zep stakes everything on a temporal knowledge graph called Graphiti, and Cognee builds an ontology-aware graph from anything you feed it. The pattern across all four: storage isn't the moat; ranking is. As of late June 2026, picking one is picking which retrieval shape your agent will live inside.
At a glance
Four frameworks, four answers to the same question: what does an agent need to remember between turns, between sessions, and between users — and how is that memory ranked when the next prompt arrives. The table sets the basics; the chart and matrix that follow show where each one leans hardest.
| Framework | Approach | Self-hosted? | Headline strength |
|---|---|---|---|
| Mem0 | Extraction pipeline fanning extracted facts into vector + KV + graph stores | Yes — Apache-2.0 OSS, plus a managed cloud | User-scoped memory by default; drop-in for chat apps |
Letta (formerly MemGPT) |
Agent-as-a-server with a tiered working/archival memory hierarchy | Yes — self-hosted server, plus Letta Cloud | Stateful agents you address by ID across processes |
| Zep | Temporal knowledge graph (Graphiti) with bi-temporal fact validity |
Community edition self-hosted; managed Zep Cloud | Time-aware retrieval — facts know when they stopped being true |
| Cognee | Graph-from-anything ETL pipeline producing an ontology-aware knowledge graph | Yes — Apache-2.0 OSS, BYO graph + vector DB | Schema-disciplined graph built from unstructured corpora |
Snapshot: 2026-06-23. Star counts and feature surfaces in this space move fast — re-check each project's repo and docs before sizing a deployment.
Mem0
Extraction pipeline
The defining choice in Mem0 is what gets persisted: not the conversation, but the facts the conversation produced. When a message arrives, an LLM extraction step pulls out atomic claims — "user prefers vegetarian food", "user lives in Berlin", "user's daughter is allergic to peanuts" — and writes those, not the underlying turns. The agent's memory grows as a deduplicated set of statements, not a growing transcript. The trade-off is upfront: every write incurs an extra LLM call to do the extraction, which is real money at high message volume. The payoff is that retrieval never has to wade through chatter to find the signal.
Multi-store retrieval (vector + KV + graph)
Each extracted fact fans out into three backends in parallel. The vector store indexes the fact's embedding for similarity search; the key-value store keeps it for exact lookup on canonical keys; the graph store records relationships between entities so a query can traverse user → child → allergies. At query time, all three return candidates and Mem0 merges them — vector gives you fuzzy recall on phrasing, KV gives you the precise answer to a structured question, graph gives you the reasoning path between entities. The reason to bother with three stores is that no single one ranks well for all three retrieval shapes: vector misses exact keys, KV misses paraphrase, graph misses the unstructured edges. Hybrid here isn't a feature — it's the architecture.
User-scoped memory by default
Every memory in Mem0 is tagged with a user_id (and optionally a session_id and agent_id) as a first-class primitive of the API. You don't build the multi-tenant story on top of Mem0; it is the multi-tenant story. For a consumer agent serving thousands of users — a chat app, a coaching bot, a personalized assistant — that scoping model is the path of least resistance: every memory operation is automatically isolated to the right user without your code threading tenant IDs through every call. The cost is that workloads which don't fit a per-user shape (a single agent reasoning over a shared corpus) push against the grain of the API.
Letta (formerly MemGPT)
Agent-as-a-server architecture
Letta inverts the question most memory libraries answer. The other three frameworks ship a memory backend you call from your agent code. Letta ships the agent itself as a long-lived server-side resource you address by ID. You don't instantiate an agent in your process and worry about persisting its state across requests — you create an agent in the Letta server, hand back the ID, and every subsequent call (over HTTP, the SDK, or MCP) resumes the same stateful agent with its memory, tools, and conversation history intact. This is the productization of the original MemGPT paper: memory wasn't a feature to bolt onto a stateless chat completion, it was the operating system the agent ran inside.
MemGPT's working/archival memory hierarchy
Underneath the server, the memory model is the MemGPT tiered hierarchy. There's a core memory block — small, always-in-context, edited by the agent itself as the persona and the user's salient facts change. There's a recall memory tier that holds recent conversation history, scrolled through with tool calls when the agent decides it needs to look back. And there's an archival memory tier — unbounded long-term storage, retrieved by vector search when the agent issues an explicit search call. The agent moves data between tiers by calling its own memory-management functions, which means promotion and demotion are decisions the model makes, not pipeline steps you write. The OS metaphor is load-bearing: core memory is RAM, archival is disk, and the agent runs page faults on its own context window.
The rename and what it signals
MemGPT was the research project and the original open-source codebase from the Berkeley team. Letta is the commercial entity (and the rebranded framework) that those same researchers built around it. The codebase didn't fork — it was renamed, and the MemGPT repo now redirects to Letta. What the rename signals is the positioning shift: from a memory-management research artifact to a production agent platform with a server, an ADE (Agent Development Environment), and a cloud offering. If you read a 2023 paper mentioning MemGPT and went looking for the project today, it's Letta — same hierarchy, same authors, different name and a much larger product surface.
Zep
Graphiti layer stamps every extracted fact with two timestamps: when the fact was true in the world, and when the agent learned it. Retrieval honors both.Graphiti temporal knowledge graph
Zep is built on top of Graphiti, an open-source temporal knowledge graph engine the same team also publishes separately. The unit of storage isn't a chat message or an embedding — it's a fact extracted from a message and inserted into a graph as an edge between entities. "Alice works at Acme" becomes an edge from the Alice node to the Acme node, typed works_at. Subsequent messages either reinforce that edge, contradict it (Alice changed jobs), or extend it (Alice's role at Acme changed). The graph is the source of truth; the chat history is the stream the graph was built from. Querying memory means traversing edges, not searching documents.
Time-aware retrieval
Every edge in Graphiti carries two timestamps: valid_at (when the fact became true in the world) and created_at (when the system learned it). That's the bi-temporal model the academic literature has argued for since the 1990s, finally applied to agent memory. A query like "what does the user do for work" doesn't just match nodes — it filters to edges whose validity window covers now. The stale fact about Acme is still in the graph (you don't lose history) but it doesn't surface in the current answer. For any domain where the world moves under the agent — CRM, support, scheduling, anything involving people whose situations change — that filter is the difference between a helpful agent and one that confidently repeats yesterday's truth.
Fact validity (not decay)
Most "memory decay" implementations are a hack: weight retrieval by recency so old facts fade out. Zep refuses the hack. A fact doesn't get less true because it's old — it gets invalidated by a contradicting newer fact, and that invalidation is recorded as a graph mutation, not a similarity score adjustment. The previous edge's validity window closes, a new edge opens. Querying historical state ("what did the user do for work last year") is a first-class operation because the graph remembers the closed edges. Decay-by-weighting collapses that distinction; bi-temporal invalidation preserves it. This is the central architectural argument Zep makes against the rest of the field: ranking by recency is a proxy; tracking validity is the real thing.
Cognee
Graph-from-anything pipeline
Cognee is the only framework in this group built around ingestion as the primary surface. You point it at a corpus — PDFs, web pages, transcripts, databases, repos — and it runs an ETL pipeline that chunks, embeds, extracts entities and relationships, and writes the result into a knowledge graph plus a vector index. The framing is closer to "build me a queryable representation of this body of material" than "remember what the user said." For agents that need to reason over a substantial existing corpus rather than accumulate facts from conversation, that ingestion-first posture is the right shape. The pipeline is configurable as a DAG of tasks, so you can insert your own extraction or cleaning steps without rewriting the orchestrator.
Ontology-aware ingestion
The differentiator inside Cognee's pipeline is that extraction is constrained by an ontology: a declared schema of entity types, relationship types, and the legal edges between them. You can use Cognee's default ontology or supply your own. Without that constraint, LLM-driven extraction produces a different graph every run — entity types drift, relationships are renamed, the same concept appears under three labels. With the ontology in place, extraction snaps to the schema: a "Person" node always means the same thing, a "works_at" edge always points the same direction. The trade-off mirrors the rest of structured-data engineering: schemas are work, but they're what makes the data composable across runs, queries, and downstream agents.
Hybrid graph + RAG retrieval
At query time, Cognee runs the question against both the vector index (RAG-style chunk retrieval) and the knowledge graph (entity-and-relationship traversal), then merges the results. The graph is good at structural queries — "which people are connected to which products" — and the vector index is good at semantic recall over the underlying text. Hybrid retrieval here means the agent doesn't have to choose: questions get the answer shape they need, whether that's a paragraph of evidence or a graph walk. This is the same architectural move Mem0 makes with its multi-store fan-out, applied to a different write path — Cognee builds the graph from documents, Mem0 builds it from conversation.
Cross-cutting comparison
What gets stored
The four divide cleanly on what hits disk after a message arrives. Mem0 stores extracted facts — atomic statements distilled from the conversation by an LLM pass, with the raw turns largely discarded. Letta keeps the conversation in tiers (working set, recall, archival) and lets the agent itself decide which slices get promoted into the always-in-context core memory block. Zep stores neither raw text nor flat facts but graph edges — typed relationships between entities, each carrying validity timestamps. Cognee inverts the question by storing whatever you ingested (documents, transcripts, structured records) projected through an ontology into an entity-and-relationship graph plus an embedding index. The practical consequence is what you can audit later: Mem0 shows you the fact list, Letta shows you the conversation tape, Zep shows you the graph mutations, Cognee shows you both the source chunks and the ontology projection.
How retrieval ranks
Ranking is where the four genuinely diverge. Mem0 runs three rankers in parallel — vector similarity for paraphrase, key-value lookup for canonical questions, graph traversal for relationship queries — and merges, so the dominant signal is whichever store had the best match. Letta's retrieval is agent-driven: the model decides when to issue a recall query, what to search for, and which results to pull into context, so ranking is whatever the model chose to ask for, not a fixed scoring function. Zep ranks by traversal cost in the temporal graph, filtered to edges whose validity covers the query's reference time — the ranker is structural and time-aware before it's semantic. Cognee runs a hybrid of vector retrieval over chunks and graph traversal over the ontology, merged at query time. The takeaway: only Zep treats time as a first-class ranking signal; only Letta lets the agent itself drive the search; Mem0 and Cognee are both multi-store rankers, distinguished by what they ingested rather than by how they rank.
Where the memory lives
Operational ownership splits the field. Mem0 supports both: an Apache-2.0 OSS self-host story (you bring your own vector DB, KV, and optionally a graph DB) and a managed Mem0 Platform that runs the same surface for you. Letta is opinionated about being a server — you can run that server yourself (Docker, Kubernetes) or use Letta Cloud, but either way the memory lives inside the Letta server's state, not as rows in your application database. Zep ships a community edition you self-host on Neo4j or FalkorDB plus a managed Zep Cloud; Graphiti itself is independently open-source if you want only the graph engine. Cognee is Apache-2.0 OSS that runs as a Python library inside your process and writes to whatever graph DB (Neo4j, Memgraph, Kuzu) and vector DB (Weaviate, Qdrant, LanceDB, pgvector) you give it — the lightest operational footprint of the four, at the cost of you operating those backends. The decision often collapses to whether you want your memory in your database or in someone else's service.
Schema discipline
Schema is the axis where these frameworks make the most different bets about what an LLM should be allowed to invent. Mem0 is free-form: extracted facts are natural-language strings, not typed records, so the same idea may show up under varied wording across the store — convenient to write, harder to query precisely. Letta is structurally typed (core / recall / archival are real tiers with real APIs) but the content inside each tier is whatever the agent put there, so semantic schema is the agent's responsibility. Zep imposes a typed graph: nodes have types, edges have types, and the extraction step is constrained to that vocabulary, which is why two conversations about the same domain produce comparable graphs. Cognee goes furthest — an explicit user-supplied or default ontology governs every extraction, so the same concept always lands under the same node type. The pattern across the four is a clean spectrum from "let the model say what it wants" (Mem0) to "the model must conform to your schema" (Cognee), with Letta and Zep parking at two different intermediate points.
When to pick which
| Use case | Pick Mem0 if… | Pick Letta if… | Pick Zep if… | Pick Cognee if… |
|---|---|---|---|---|
| Consumer agent with per-user history | User-scoped memory is a first-class API primitive; the drop-in fit for chat apps. | You want each user's agent to be a long-lived server-side resource you address by ID across sessions. | Workable, but the temporal-graph machinery is overkill if your facts rarely expire. | Overkill — Cognee's ingestion pipeline is built for documents, not chat turns. |
| Enterprise multi-tenant SaaS | The user_id / agent_id scoping makes per-tenant isolation the default rather than something you bolt on. |
One Letta server hosts many addressable agents; combine with your own tenant boundary. | The community edition gives you self-hosted graphs per tenant; Zep Cloud isolates by project. | You build the multi-tenant boundary yourself in the graph + vector backends you operate. |
| Time-sensitive facts (CRM, support, scheduling) | Vector + KV ranking won't tell you a fact is stale — you'd have to model that yourself. | Workable, but validity tracking is application code you write, not framework behavior. | Built for this — bi-temporal edges, validity windows, and as-of queries are first-class. | The ontology helps consistency, but temporal reasoning isn't the headline. |
| Build from an existing corpus (docs, transcripts, code) | Not the shape — Mem0 wants conversation, not documents. | Not the shape — Letta wants a stateful agent, not a one-shot ingestion of a corpus. | Possible via Graphiti directly, but Zep is optimized for streaming chat. |
The right tool — graph-from-anything ingestion with ontology constraints is the whole pitch. |
| Migrating from a raw RAG pipeline | Lowest-friction step up: keep your vector DB, add Mem0 in front for the extraction and KV/graph fan-out. | Larger migration — you're moving the agent itself behind a server, not just upgrading retrieval. | You get RAG plus temporal reasoning, but you're committing to a graph DB you weren't operating. | Natural fit — Cognee replaces the RAG indexing step with a graph-aware ingestion pipeline. |
| Low-ops self-hosted footprint | Python library + your existing vector DB; lightest footprint at small scale. | You operate a Letta server plus a database — heaviest of the four for an OSS deployment. | Self-host requires Neo4j or FalkorDB plus the Zep server — a real ops commitment. | Python library that talks to whatever backends you already run; no extra service to babysit. |
FAQ
Do I need a vector DB if I use one of these?
Usually yes, but you don't necessarily run it yourself. Mem0, Zep, and Cognee all rely on a vector index as part of their retrieval — Mem0 supports Qdrant, pgvector, Weaviate, and others; Cognee speaks to Weaviate, Qdrant, LanceDB, and pgvector among others; Zep Cloud manages its own. Letta uses a vector store for its archival memory tier. So the vector DB is still there, just often abstracted: you either point the framework at one you operate, or you let the managed offering hide it. If you want the trade-offs of choosing one, our pgvector vs Pinecone vs Weaviate vs Qdrant post is the companion read.
Which is best for multi-user SaaS?
Mem0 if "many users, per-user history" is the dominant shape — the API is built around user_id scoping so you don't thread tenant IDs through every call. Letta if you want each user's agent to be an addressable long-lived resource — one user, one agent ID, persistent across sessions and processes. Zep and Cognee are workable in this shape but you'll spend more time building the tenant boundary yourself; they're optimized for different problems.
Can these replace a RAG pipeline?
Partly, and only if you frame "RAG" precisely. Cognee can replace the indexing-and-retrieval halves of a RAG pipeline directly — it ingests a corpus, builds a graph plus vector index, and answers structured questions against both. Mem0 replaces RAG-style retrieval over conversation history with extraction-plus-multi-store recall. Zep replaces RAG over chat with temporal-graph traversal. Letta replaces the "remember what was discussed" half of RAG with its memory hierarchy but doesn't ingest a static corpus. None of them replace RAG over a million-document corporate knowledge base on day one — that's still mostly a vector DB plus a chunker plus a reranker, with Cognee being the closest to a graph-aware alternative.
What about MemGPT — is Letta a fork or a rename?
A rename, by the same team. MemGPT was the original research project and open-source codebase from the Berkeley group who published the MemGPT paper. Letta is the company the same authors founded to commercialize and operate the framework; the codebase wasn't forked — it was rebranded, and the project repo now lives under the Letta name. The memory hierarchy in the paper (working / recall / archival tiers managed by the agent itself) is the same hierarchy Letta ships today, with substantially more product surface around it (a server, an ADE, hosted cloud, SDKs).
How do I handle fact contradictions?
Each framework answers this differently and the answer is load-bearing for any use case where facts change. Mem0's extraction pipeline performs a deduplication-and-conflict-resolution step at write time: when a new fact contradicts an existing one, the older fact is updated or replaced rather than appended. Letta lets the agent itself rewrite its core memory block, so contradiction handling is whatever the agent decides — flexible, but only as good as the prompting. Zep is the most principled: a contradicting fact closes the validity window on the previous edge and opens a new one, so both versions persist in the graph with their respective time ranges. Cognee leans on the ontology — if two extracted relations would violate the schema's cardinality rules, one is rejected or merged at ingestion. If contradiction handling is a hard requirement, Zep's bi-temporal model is the cleanest story.
What about Supermemory and Cogito?
Both are in the same neighborhood and worth a look depending on what you're optimizing for. Supermemory is a hosted memory layer with a strong focus on API ergonomics and cross-app memory sharing — a closer competitor to Mem0's managed offering than to the self-hosted frameworks here. Cogito is younger and oriented around personal-agent memory with an emphasis on local-first storage. Neither bumped this comparison's four because the four shown here cover the architectural spectrum (extraction vs hierarchy vs temporal graph vs ontology-aware ETL) more crisply, but if your constraints are hosted-only or local-first, both are worth their own evaluation.
Further reading
On this wiki:
- pgvector vs Pinecone vs Weaviate vs Qdrant — the companion comparison on the vector DB layer underneath three of these frameworks; pick the index before you pick the memory framework that wraps it.
- Short-Term vs Long-Term Memory — the conceptual split between the in-prompt working set and the external store, and the promotion/demotion cycle that all four of these frameworks are different implementations of.
- Memory Stores: Vector, KV, Graph & Eviction — why different memory kinds want different backends, the unified interface pattern, and the eviction policies that decide what gets forgotten.
- Context Windows Explained — the finite shared token budget and the three failure modes that make external memory necessary in the first place.
Project sources:
- Mem0 on GitHub — Apache-2.0 source, multi-store backend matrix, extraction pipeline docs, and the
user_idscoping API. - Mem0 docs — managed platform reference, vector / KV / graph backend configuration, and integration recipes.
- Letta on GitHub — server source, the working / recall / archival memory tiers, and the agent-as-a-server API surface.
- Letta docs & the
MemGPT→ Letta rename note — the official statement that Letta is the rebrandedMemGPTproject from the same team. - Zep on GitHub — community edition source, temporal-graph design notes, and the bi-temporal validity model.
Graphition GitHub — the standalone temporal knowledge graph engine that powers Zep.- Cognee on GitHub — Apache-2.0 source, the graph-from-anything pipeline, ontology configuration, and the supported graph + vector backends.
- Lost in the Middle: How Language Models Use Long Contexts (Liu et al., 2023) — the primary source for the "context windows degrade past the first thousand tokens" claim that opens this post.
MemGPT: Towards LLMs as Operating Systems (Packer et al., 2023) — the original paper behind Letta's tiered memory hierarchy.