Search "agent memory github" and you get a wall of repos that all promise the same thing: your agent will finally remember. Star counts won't help you choose between them, because they aren't four builds of one idea. They are four different answers to the question what should "memory" even mean here — a drawer of facts, a graph of facts-over-time, a whole agent with memory built in, or a pipeline that turns your documents into something recallable. Pick the wrong shape and you'll fight the tool forever. Here's the field guide, with the one axis that actually decides.
The four shapes, in one line each#
All four are Apache-2.0 and Python. That's where the similarity stops.
Mem0: extraction-based fact memory, the drop-in option#
Mem0 (~63k stars) is the one most teams reach for first, and for a good reason: it treats memory as a library call, not an architecture. You hand it a conversation; an LLM extracts the durable facts ("prefers window seats," "works in EST"); it stores them, deduplicates against what's already there, and serves them back on retrieval.
memory.add(messages, user_id=user_id)
relevant_memories = memory.search(query=message, filters={"user_id": user_id}, top_k=3)
That's the whole surface area. Under the hood it defaults to a pluggable vector store, with an optional graph layer if you want relationships. The payoff is speed to a working per-user memory; the tradeoff is that what it remembers is a flat set of extracted facts — great for "who is this user," weaker when the relationships between facts or their history matter. If you want to understand the add-then-reconcile step that makes it work, we pulled it apart in inside Mem0's add-only memory engine.
Mem0 makes memory a function call. That's its whole pitch, and for most personalization it's enough.
Zep / Graphiti: a knowledge graph that knows when#
Graphiti (~30k stars) is the open-source engine underneath Zep's hosted service, and it answers a question the others largely ignore: what happens when a fact stops being true? It's bi-temporal — every fact records both when it was true in the world and when the system learned it. New information doesn't overwrite the old fact; it invalidates it, so you can still ask "what did we believe about this account last March."
That power has a cost: Graphiti is a library, not a drop-in, and it needs a real graph database behind it — Neo4j, FalkorDB, Amazon Neptune, or Kuzu. You're running graph infrastructure. The clean split to remember: Graphiti is the library you self-host, Zep is the managed platform built on it. Reach for it when your agent's world changes under it as it runs and stale facts are an actual hazard, not a nuisance. (If you're weighing graph-shaped memory more broadly, we compared the tradeoffs in how to give an agent persistent memory.)
Letta: not a memory store — a whole agent#
Letta (~24k stars) is the odd one out, and mislabeling it is the most common mistake here. It is not a memory library you bolt onto your agent — it is the agent runtime. Descended directly from the MemGPT paper (Packer et al.), its central idea is treating the LLM like an operating system managing its own memory: a small, always-in-context core memory the agent edits itself, plus larger out-of-context archival and recall stores it pages in and out as needed.
You run Letta as a stateful server backed by Postgres or SQLite, and your agents live inside it with their memory as a first-class, persistent part of the runtime. That's a heavier commitment than pip install and a function call. Reach for Letta when you want the whole stateful-agent platform — self-editing memory, persistence, tools — rather than a component to slot into an agent you're building yourself. Point it at "I just need to remember a user's timezone" and you've adopted an operating system to store a string.
Cognee: a pipeline that turns a corpus into memory#
Cognee (~30k stars) frames memory as an ETL-style pipeline. Its core loop — ingest, build the graph, then query — turns documents and conversations into a combined knowledge graph plus vector store you can recall against.
await cognee.add("Cognee turns documents into AI memory.")
await cognee.cognify() # build the graph
results = await cognee.search("What does Cognee do?")
It's the most storage-flexible of the four: vector backends from pgvector to LanceDB to Qdrant, graph backends from Neo4j to Kuzu, SQLite for local metadata. That flexibility is the tell for when to use it — Cognee shines when "memory" really means "make my pile of documents and history queryable as a connected whole," which sits closer to graph-RAG than to per-user fact tracking. If your problem is a corpus, not a user, this is the shape.
The lighter option: Memobase#
If all four feel like too much, Memobase (memodb-io/memobase, ~2.8k stars, Apache-2.0) narrows the scope hard: user-profile-based long-term memory for chatbots. It maintains a structured, evolving profile per user rather than a general graph or agent runtime — less to run, less to reason about, and often exactly enough for a companion or assistant app.
How to choose#
Skip the star race — three of these five are within a rounding error of each other, and the number tells you nothing about fit. Ask what memory has to be for your problem:
- A drawer of facts about each user, with the least code? Mem0.
- Facts that change over time, where "what was true when" is a real query? Zep/Graphiti — and accept the graph database.
- A whole stateful agent, not a component? Letta.
- A corpus you need to make recallable as a connected whole? Cognee.
- Just a per-user profile for a chatbot? Memobase.
Once you've settled the shape, the choice narrows to a head-to-head: our Mem0 vs Zep vs Letta decision guide runs the three you'll most often weigh against each other, and the Cognee vs Graphiti vs Mem0 comparison covers the graph-shaped end.
Two prior questions decide more than any of these tools. First, whether you even need a memory library versus plain retrieval — settle that with agent memory vs RAG before you install anything. Second, what storage actually sits underneath — because a graph-backed choice like Graphiti or Cognee is an infra decision as much as a library one, and the vector-store comparison is where that call gets made. Get the shape right first; the repo follows from it.



