The Shapes of Agent Memory – Files, Stores, and Experience

August 12, 2026

An agent that remembers across sessions can keep its memory as curated markdown files, as an auto-mined structured store, or as trained experience. I measured all of them: files against a structured store under one fixed model, a store-only head-to-head across the structured lineages, and an experience bank on the agentic benchmarks where the state of the art trains memory into the weights.

Three side-by-side memory shapes: a file-based index of markdown lines, a structured store of embedded units linked by a graph, and trajectories of agent experience with one successful episode ringed.

Three side-by-side memory shapes: a file-based index of markdown lines, a structured store of embedded units linked by a graph, and trajectories of agent experience with one successful episode ringed.

An agent that only remembers within one conversation is a stranger with excellent manners: it greets you warmly every single day, and it has no idea who you are. The moment you want it to know your projects, your preferences, and the thing you told it last Tuesday, you need memory that outlives the context window. There are three common shapes a modern agent memory system takes (Fig. 1). Two are stores that sit beside a frozen model, and they anchor opposite ends of a design axis; the third moves the memory behavior into the model itself.

The first keeps memory as files the model curates: a short index plus topic files, written in plain markdown, read back by searching and reading them like any other file. It is what a coding agent reaches for when it has a filesystem and no database, and it is what Claude Code, Cline, Cursor, and Windsurf ship today. OpenClaw is the most thoroughly worked-out version of it: its default memory-core plugin keeps a curated MEMORY.md beside dated session logs, and it adds a background consolidation pass that the other file-based products do not have. The second keeps memory as a structured store: every turn is mined into small atomic facts, embedded into a vector index, threaded into a temporal graph, and read back by ranked retrieval. It is what you build when memory is the product, and it is what the dedicated memory startups mem0, Letta, and Zep sell. The third keeps memory as experience the model is trained to use: episodes still land in a bank, but everything that makes them memory, what to retrieve, whether to trust it, how to turn it into action, is trained into the acting policy by reinforcement learning. It is the agentic state of the art (MemHarness), the shape the field reaches for when retrieval stops paying, and it is where this post ends.

In this post, I measure which shape is better rather than argue it, which meant building the first two. The structured arm is a hybrid of the two structured lineages, plus a layer neither has: an associative graph learned from which places actually get retrieved together, so recall can reach an item the query never ranked. The file-based arm is a reconstruction of a shipping coding agent’s auto-memory, traced claim by claim to public documentation and published with its spec, not a strawman written to lose. Both run behind the same agent loop, on the same local open-weight model, scored by the same judge on the same public benchmark, so only the memory layer can move the number, and the per-question rows, with the scripts that recompute each figure and an explicit ledger of the few published scores whose rows could not be released, are in a40-labs/memory. Hosted models come in where fairness demands: the head-to-head reads every store through one shared reader and judge, gpt-4o-mini, the same model the graph vendor’s own numbers were scored with; the agentic experiment fields a frontier actor, claude-sonnet-5. The trained shape cannot join the controlled comparison at all, because the training is the method: unplug its bank and you have a different policy, not a baseline. The last section meets it on its home ground instead.

TL;DR The structured store beats files on accuracy and on token cost at once; files win where memory stays small, or where the right answer is “I don’t know”. Against my own interest, the hybrid is statistically indistinguishable from a plain vector index on LoCoMo; paired on long-haystack LongMemEval-M the same two stores separate by 15 significant points in the hybrid’s favour, which is consistent with structure paying as histories grow (the arms differ in more than structure, so the bundle is what is measured), and no single benchmark ranks memory systems. Swapping the model stack that reads and judges the memory moves the score further than swapping between any two of the stores that work, which is why numbers do not travel between protocols. On the agentic benchmarks, retrieved experience paid only where the actor was weak with headroom left; where the task yields to reasoning, a frontier actor reaches the trained system’s bar with no memory at all, and where the reward has a shape only practice teaches, the trained policy stands alone.

Two panels. Left, store-based memory: a frozen model writes to and reads from a store beside it, the store holding both kinds, file lines and structured dots; writes come from the model's curation or an embedder, reads from grep or ranked recall; it bolts onto any model and is paid at write and read time. Right, experience-based memory: an actor enclosed in a dashed trained-by-reinforcement-learning boundary exchanges episodes with an episode bank, writing finished episodes back and retrieving them; one model, inseparable, paid in training compute.
Figure 1. Where memory lives. Store-based memory bolts a writable, searchable store onto any frozen model and pays at write and read time; experience-based memory keeps a bank too, but trains the model's use of it, paying in training compute.

Store architectures

Two panels. Left, file-based memory: a new turn leads the model to write or edit a file, a one-line entry into a roughly 200-line MEMORY.md index, which points to separate topic files; reading means putting the index in context then grepping and reading files, with no embeddings and literal search. Right, structured memory: a new turn is auto-extracted into atomic units that are embedded with no LLM write, split into a dense-plus-sparse vector store and a temporal fact graph that supersedes old facts, consolidated in the background, and read back by ranked retrieval plus a preload of salient units.
Figure 2. The same job, two architectures. File-based memory puts the model on the write path and a text search on the read path. Structured memory puts an embedder on the write path and a ranker on the read path.

Both sit beside a frozen model and persist facts across sessions. The difference that matters is who does the work, and when.

File-based

File-based memory spends its budget at write time, through the model. After a turn, the model decides whether anything is worth keeping, and if so it edits a file: a new line in the index, or a paragraph in a topic file. The index is small on purpose, because it is loaded into context every session; a common budget is the first 200 lines or so. Everything else lives in topic files that are not loaded until the model goes and reads them. Recall is therefore whatever the model can find by keeping the index in view and grepping the rest. There is no embedder and no ranker. The whole system is the model’s own judgment plus a text search, which is exactly why it is so easy to ship: if you have file tools, you have this.

This approach is everywhere in shipping coding agents: Claude Code’s auto-memory (a per-project MEMORY.md index over model-curated topic files), the memory tool primitive in Anthropic’s API, the community’s Cline “Memory Bank” and its descendants, and the automatic memories in Cursor and Windsurf. Keep it distinct from the instruction-file family (AGENTS.md, CLAUDE.md, .cursorrules), which is human-authored static context; the accumulated, model-written kind is what this post evaluates.

Structured

Structured memory spends its budget at write time too, but not through the model. Every turn is mined into atomic units, each embedded and stored with dense and sparse vectors, and salient facts are threaded into a graph whose edges carry validity windows so a later fact can supersede an earlier one. A background pass consolidates duplicates and merges the graph. Nothing on the write path asks the model to reason; it is extraction and embedding. Recall is a ranked hybrid query, and the most salient units are preloaded before the first user word, so the agent often answers without searching at all.

This is what the dedicated memory startups sell: mem0 extracts facts into a vector-first store with an optional graph layer, Letta (formerly MemGPT) pages tiered memory in and out of context, and Zep builds a bi-temporal knowledge graph, the strongest form of the idea. All of them put an extractor and a ranker where the file-based approach puts the model’s judgment and a grep.

Two design decisions fall straight out of this split, and they are the whole game:

  • What gets saved. File-based memory saves what the model chooses to save. Structured memory saves everything, then ranks.
  • What gets found. File-based memory finds what a literal search surfaces from an index that must stay small. Structured memory finds what a similarity ranker surfaces from a store that can grow without bound.

Two lineages: place, and entity-and-time

Calling all of that one “shape” hides a real split, because the structured pole has two lineages that organize memory around opposite primitives: by place, or by entity and time.

The place-organized lineage files memory by where it belongs rather than by who it is about. MemPalace is the cleanest public example: people and projects become wings, topics become rooms, and the original conversation text lives in drawers inside them, retrieved by semantic search scoped to a region rather than swept across a flat corpus. The defining choice is what it declines to do at write time. It stores the text verbatim, and does not summarize, extract, or paraphrase, so ingest is an embedding and a filing decision with no model reasoning in it at all. Its structural weakness is aggregation: an answer scattered across many rooms depends on one ranked query surfacing all of it at once, and no artifact in the store has gathered it in advance.

The entity-and-time lineage (Zep’s Graphiti) stores a knowledge graph instead: raw messages kept as ground truth, LLM-extracted entity nodes that are resolved and deduplicated across sessions and carry maintained summaries, and one-line distilled fact edges between entities. Every edge holds validity timestamps, relative dates are resolved to absolute ones at ingest, and a contradicting new fact closes the old edge’s validity window rather than deleting it. The reader receives distilled facts with date ranges plus entity summaries, never raw messages. The cost inverts: an LLM reasons at ingest, on every message, for extraction, resolution, and invalidation.

Two panels. Left, place-organized: an always-loaded tray of identity and salient facts above three rooms holding fact chips, with a solid scoped-recall arrow into one room and a dashed broad-search arrow across all rooms; tagline cheap writes, no entity merge, freshness by ranking. Right, entity-and-time: one resolved entity node with edges to fact chips, each carrying a date range, one edge dashed with its validity window closed as superseded, and a timeline strip showing a new fact closing the old fact's window; tagline entity aggregation, validity windows, LLM at ingest.
Figure 3. The two lineages. Place-organized memory files facts by location and loads in layers; entity-and-time memory keys every fact to a resolved entity and stamps it with a validity window a new fact can close.

Three consequences follow (Fig. 3):

  • Aggregation. An entity node accumulates every fact about a person by construction, so an enumeration question (“what are all of X’s hobbies?”) arrives with a pre-built aggregate. A place-organized store has no such artifact: it must hope one ranked query surfaces every scattered item, and the members of an enumerable answer are usually semantically far apart (running, pottery, and movie nights share little beyond the person), so no single query ranks them all into the top-k even when every item is in the store. Keep this weakness in mind for the results: the hardest questions for this study’s structured arm, on both benchmarks, are exactly the ones that assemble an answer from facts scattered across many sessions.
  • Time. Supersession lives in the store for one lineage (validity windows the reader can trust) and in ranking heuristics for the other.
  • Cost. Place-organized is cheap at write time and leans on retrieval; entity-and-time pays heavy LLM cost at ingest to make reading cheap and precise.

Neither dominates. If your workload is scoped recall over evolving topics, the place lineage’s load layers are the better fit; if it is cross-session aggregation and “what is true now”, the graph lineage earns its ingest bill. Which raises the obvious question: why not take the cheap half of each?

Hybrid

The hybrid takes exactly that bargain, and it is the design this study measures (Fig. 2’s right panel is its architecture). Take the place-organized store’s write path wholesale: atomic dated facts filed by location, embedded with no LLM reasoning, recalled by layered loads and ranked hybrid search. Then borrow one thing from the entity-and-time lineage: validity windows, so a contradicting new fact can close an old one’s window instead of competing with it at recall time. That combination is not unique to this study, and it would be misleading to imply otherwise: MemPalace ships a temporal entity graph with validity windows of its own, alongside its rooms. What differs here is smaller and more specific, and it is the third layer below.

What the hybrid buys is the cost profile of place with the time semantics of the graph: writes stay embedder-cheap, and “what is true now” questions get dated, supersedable facts rather than ranking heuristics alone. One temporal nuance the graph lineage does not spell out: supersession must distinguish conflicting states from additive events. “Works at Acme” should close “works at Beta”; “scored 2 goals this week” must never close “scored 3 goals last week”, or counting questions become unanswerable. What the hybrid deliberately leaves out is the graph lineage’s expensive half: no LLM at ingest, so no entity resolution and no maintained summaries, and cross-session aggregation stays its structural weak point.

The design’s answer to that weak point is a third layer the two lineages do not have: an associative graph learned from usage statistics. Locations that co-occur in retrievals more often than chance predicts get linked (a statistical test, not embedding similarity: “these go together” is a stronger claim than “these look alike”), and recall runs as anchor, expand, fuse: ranked search anchors on what it can find, the association graph expands to linked locations the query never ranked, and the fused result caps the graph’s contribution (Fig. 4). The design principle underneath answers both lineages’ disclosed failure modes at once: the graph is only ever allowed to add candidates, never to displace the anchor set. That guards the retrieval, not the reader, since added context can still distract the model downstream; what the measurements showed is no harm at the scale tested, not monotonicity. Where the entity-and-time store is hard-bounded by its extractor, the hybrid keeps raw dated facts as the anchor, so a graph failure degrades to plain ranked retrieval; and where pure place organization can never reach an item its one query failed to rank, expansion gives it a query-independent path there.

One panel. Three rooms of dated fact chips form the place core. In the middle room a current fact with an open validity window sits above a superseded fact whose window is closed, labeled a new fact closes the old fact's window. A dashed orange association arc links the first and third rooms, labeled as learned from places that co-occur in retrievals beyond chance. Recall flows in three numbered steps: a query anchors on one room by ranked hybrid search, expands along the learned association to a room the query never ranked, and fuses both into a capped context where the graph adds candidates without displacing the anchors.
Figure 4. The hybrid. The place core keeps raw dated facts cheap to write; a validity window lets a new fact close an old one; recall anchors on ranked search, expands along usage-learned associations to places the query never ranked, and fuses with a cap, so the graph adds candidates without displacing the anchor set. Whether the added context helps the reader downstream is a separate, empirical question.

One scope note for honesty, and it is a large one: the benchmark protocol below writes facts directly into the store, which never triggers the background consolidation where supersession lives (the next subsection is about that pass), and the association graph starts empty. So the configuration actually measured is the hybrid’s place-organized core: dated facts plus hybrid ranked search. Read its scores as a floor, with one update from later work that cuts against my own design: when the association graph was subsequently seeded from real co-retrieval statistics and given one controlled, paired shot at exactly the aggregation failures it exists to fix, it changed nothing. No harm (the capped fusion held), but no recovery either. The associative layer stays a design capability, not a measured contributor.

Consolidation

Every architecture so far has been described by two paths, write and read, and every description is incomplete. There is a third path, and it is not a fourth architecture: a pass that runs between sessions and reorganizes what is already stored. The field calls it dreaming, after the consolidation that happens in sleep, and it is the only path that can repair a store that is already wrong.

It cuts across the taxonomy rather than extending it. Files can be consolidated, place-organized stores can be consolidated, and the entity-and-time lineage consolidates so eagerly it is easy to miss: resolving a mention against existing entities and closing a superseded fact’s window is exactly this work, moved to ingest and paid per message. That relocation is the real choice on offer. Consolidate at ingest and every write pays for order the store may never need; consolidate in the background and writes stay cheap while the store carries its own mess until the pass comes around.

The two implementations below sit at opposite ends of that trade (Fig. 5).

Two panels. Left, file-based memory promotes upward: a short-term buffer of items labelled by how often each was recalled, with the frequently recalled ones promoted by arrows into a MEMORY.md box loaded every session, gated on score, recall count, and distinct queries. Right, the structured store merges sideways: three differently worded restatements of one fact collapse into a single canonical unit carrying the provenance of all three, annotated with the merge rule, a cosine bar of 0.92 on vectors the store already has, no model calls, and its tiers of exact dedup on write, per chat when idle, and whole store daily; a dashed note adds that a version phrased in entirely different words is missed and catching it would need a model to judge each pair.
Figure 5. Consolidation in both store architectures. The file-based version runs a model nightly to promote what usage proves valuable into the always-loaded index; the place-organized store collapses restatements into one canonical unit on similarity alone, spending no model calls at all. That thrift is also the bound: similarity catches restatements and misses paraphrase, which is where the cost of judgment comes back.

OpenClaw runs the file-based version nightly, in three phases borrowed from a night’s sleep: a light phase deduplicates the recent buffer, a phase named after REM (the rapid-eye-movement stage where human brains replay the day and connect it to older memories) looks across conversations for recurring themes, and a deep phase promotes survivors into MEMORY.md, the index every session loads. What makes it more than cleanup is the gate: an item earns its place by being used, clearing a score threshold and several recalls across distinct queries. The store learns what matters from what the agent kept reaching for, a signal neither the write nor the read path can see.

This study’s hybrid does the same job on different material, in three tiers. Identical writes never duplicate, because a unit’s content hash is its primary key. A minute after a conversation goes idle, a pass rebuilds that conversation’s index cards. Then once a day the whole store is swept: units are clustered by similarity, using the vectors they already carry, and each cluster collapses to its longest phrasing with the others’ provenance folded in. The bar is set high so merely related facts stay apart, and because the pass reuses stored vectors instead of re-embedding, it spends no model calls at all. So OpenClaw promotes upward into a file the model reads; the hybrid collapses sideways into a store the ranker searches.

Two limits come with that design, and both are visible before any measurement. Cheap similarity catches restatements but misses the same event told in other words, and closing that gap means a model judging each pair, which puts per-item reasoning cost back into the one path that had none. And the value of tidying at all depends on the reader: a model answers correctly about a handful of restatements sitting in front of it, merged or not, so storage-level cleanup earns its keep only once duplicates outnumber what the reader can hold. Consolidation pays most on long histories read by weak models, least on short ones read by strong ones. The measurements here cover only the second regime: run at roughly fifty sessions per history it merged real duplicates and bought no accuracy, and the main experiment never triggers it at all, so consolidation contributed nothing to the structured arm’s scored numbers; whether running it would raise or lower them is unmeasured.

Experience architecture

Every store architecture above shares one assumption so basic it is easy to miss: the model that uses the memory is frozen. The store gets smarter, better ranking, better structure, better time semantics; the reader of it does not. The agentic memory line of work drops exactly that assumption, and MemHarness (paper) is its cleanest current example: hold the store simple, and train the model’s use of it instead.

The bank half looks deliberately familiar (Fig. 6). After every episode the trajectory is summarized and written into a vector store with semantic embeddings, deduplicated semantically, and periodically pruned by empirical utility, so entries that keep paying rent stay. By this post’s taxonomy that is a structured store: inspectable, swappable, nothing a reader of the sections above has not seen.

The difference is everything downstream of retrieval. Where a store architecture hands retrieved items to a frozen model and hopes its judgment suffices, the experience architecture makes that judgment the trained object. Acting is a five-stage policy: observe the current state; retrieve the top-k experiences, each paired with the source observation it was learned from; critique the retrieved experience against the current state (does this actually apply here?); reconstruct it into state-specific guidance when it does, or reject it and fall back to self-reasoning when it does not; then act. The whole pipeline is trained end-to-end with reinforcement learning (GRPO, group-relative policy optimization over grouped rollouts, with format rewards that keep the retrieval and reconstruction stages from collapsing), cold-started from a couple hundred teacher-written memory records.

A pipeline of five stages: observe the current state, retrieve top-k experiences with source context, critique whether they apply here, reconstruct them into state-specific guidance, and act in the environment. A dashed reject path skips from critique to act, labeled fall back to self-reasoning. A dashed green training bracket spans retrieve through act, labeled trained end-to-end with reinforcement learning, reward flowing back through every stage. Below, an episode bank labeled summarize, deduplicate, prune by utility supplies experiences to the retrieve stage and receives finished episodes written back from act.
Figure 6. The experience architecture (MemHarness). The episode bank is a structured store, summarized, deduplicated, and pruned by utility; the difference is that retrieval, critique, and reconstruction into state-specific guidance are stages of one policy trained end-to-end by reinforcement learning.

Why go to that expense? Because the untrained alternative is not merely weaker, it is negative: in their own ablation, handing the trained policy raw replayed episodes instead of reconstructions makes it worse (76.4 with no memory to 70.1 with raw replay). Retrieval gets the experience into view; nothing about a frozen model guarantees the experience gets used, and a policy that has learned when to trust a memory and how to rewrite it for the situation at hand is solving a problem that no amount of store engineering touches. The cost profile inverts accordingly: the store architectures pay at write or read time and bolt onto any model; the trained one pays in training compute and is inseparable from the one model it trained.

That is also why it cannot join the controlled comparison that follows: unplug its bank and you have a different trained policy, not a baseline. The honest meeting point is its home ground, the agentic benchmarks, where the final section takes the structured store to meet it.

Evaluation

Two public benchmarks carry the comparison: LongMemEval as the primary, LoCoMo as the second opinion. Each gets a subsection below, because what a benchmark measures, and what its numbers have been made to say in the wild, decides how much a score is worth.

Every result table below compares the same three arms, named the same way throughout. Each table and figure states the sample it was scored over, written out in the tables and abbreviated as n in the figures, meaning the number of questions, games, or sessions behind that number:

  • No-memory: the same agent loop with the memory layer removed. The floor that sizes what memory contributes at all, and proof that the judge cannot be gamed by refusing everything.
  • File-based: the markdown reconstruction described above. An LLM-curated index plus topic files, recalled by grep and read.
  • Structured: the hybrid described above. Dated atomic facts, embedded on write with no LLM, recalled by ranked hybrid search.

The two pure structured lineages, place-organized and entity-and-time, do not run in the main experiment; they get their own store-only head-to-head at the end of this section, where the graph vendor’s production system competes through its own published retrieval.

The controls are the point. Both arms ran the same agent loop, the same locally served open-weight model as the answerer (Qwen3.6-35B-A3B-mxfp4), the same embedder where one was needed, and the same judging pipeline: a model judge scores each answer against the gold one, and a deterministic pass then re-classifies refusals (saying “I don’t know” counts as correct only when the answer genuinely was not in the history). The judge is identical for both arms, which removes per-arm judge configuration as a factor, though a shared judge can still prefer answer styles that correlate with an arm; it is also one model family scoring its own outputs. Both concerns are flagged rather than hidden. The file-based arm is a faithful implementation of the documented approach (Claude Code’s auto-memory, described above), with a couple of deviations that make it slightly more robust than the standard, not less. Anywhere the two arms could differ for a reason other than the memory architecture, I held them equal.

One thing this is not: a measurement of any shipping product. I reimplemented the file-based architecture and drove it with a local open-weight model, so these numbers say nothing about how Claude Code, Cline, or anyone else performs in their own product, on their own model. Naming products is about where the architecture comes from, not a leaderboard of them. What is being compared is the memory architecture, with everything else held fixed.

That fixity is the whole reason to bother. Published memory numbers are notoriously hard to compare across vendors, and the LoCoMo subsection below tells the canonical story. A number is only worth anything when you know what was held constant. Here, everything but the memory architecture was.

LongMemEval

LongMemEval is a public suite for long-term conversational memory: 500 questions spanning categories that separate the easy from the hard: single-session recall, multi-session joins, knowledge updates (“what is the current value”), temporal reasoning, and abstention (knowing when the answer was never stated). Retrieval and answering both count: the system has to surface the right memory and answer from it, and an LLM judge scores the answer against the gold one. It comes in two sizes: LongMemEval-S, where each question sits over a history of roughly 47 prior sessions, and LongMemEval-M, the same questions over roughly 500-session haystacks. The main experiment runs -S; the -M numbers close this subsection, because scale is exactly what they measure. It is the primary benchmark here because its haystacks are long enough to punish weak recall and its categories name the exact failure modes the architectures should differ on.

Every headline number below is measured on the held-out questions, never the tuning split; both arms scored fractionally higher on questions they had never seen, which is the opposite of what overfitting looks like. How the 500 questions were split, what “tuning” concretely means, and every limitation a skeptic should weigh (prompt heritage, reconstruction fidelity, self-judging, and an oracle control that splits the gap descriptively into read-side and write-side halves) are collected in the appendix. The one that matters most mid-read: the file-based arm got an equal tuning budget, and two of its frozen fixes came from watching its own failures.

Accuracy

Category (held-out questions)StructuredFile-based
Temporal-reasoning (91)0.8020.407
Multi-session (97)0.6080.330
Knowledge-update (36)0.8330.528
Single-session-user (52)0.9230.673
Single-session-assistant (44)0.5680.273
Preference (18)0.6110.333
Abstention (18)0.7780.889
Overall (category-reweighted)0.7360.449
Table 1. Held-out accuracy by question type on LongMemEval-S, over the 356 non-tuning questions. The count beside each category is how many questions it holds. Structured memory leads every category except abstention.
A grouped bar chart of held-out LongMemEval-S accuracy by question type, structured memory in blue against file-based memory in orange. Structured leads in every category except abstention: temporal 80 versus 41 percent, multi-session 61 versus 33, knowledge-update 83 versus 53, single-session-user 92 versus 67, single-session-assistant 57 versus 27, preference 61 versus 33, and abstention 78 versus 89 where the file-based arm wins. Overall 73.6 versus 44.9 percent, against a no-memory floor of 9.8 percent.
Figure 7. Held-out accuracy on LongMemEval-S. Structured memory leads everywhere except abstention, and the gap is widest where memory has to do the most work: joining facts across sessions and reasoning about time.

On the held-out questions (Tab. 1, Fig. 7), the structured arm (the hybrid) scored 73.6% and file-based scored 44.9% (category-reweighted; raw 73.1% and 44.1%). The paired difference is 28.7 points, 95% confidence interval [22.1, 35.4], comfortably clear of zero. Three checks say the result is solid rather than lucky: the number barely moved from the tuning set to the held-out set for either arm (both actually ticked up, the opposite of an overfitting signature); widening the held-out set from 256 to all 356 non-tuning questions changed the gap by 0.0002; and throwing out every question where either arm’s answer was truncated by the serving layer still leaves 74.1% against 50.2%. For scale, a no-memory baseline answering the same questions with no memory at all scores 9.8%, so both architectures are doing real work; the question is how much.

The category breakdown says why, and it is not subtle. The widest gap is temporal reasoning (80% against 41%), and multi-session (61% against 33%) is close behind and clearest about the mechanism: its answers are assembled from facts mentioned in several different conversations. A literal search over a deliberately small index is the wrong tool for that. If the joining fact sits in a topic file the model never thought to grep, it is simply gone, and the model, to its credit, usually says it does not know rather than inventing an answer. Ranked retrieval over an unbounded store does not have this failure mode: the fact was saved whether or not anyone predicted it would matter, and similarity, not a filename, brings it back. Knowledge updates (83% against 53%) tell the same story from another angle.

There is exactly one category the file-based arm wins: abstention (88.9% against 77.8%), knowing that something was never said. That is not a rounding artifact, and it replicates: on the second benchmark’s adversarial questions, in the LoCoMo section below, the file-based arm beats the structured one by an even wider margin, and a no-memory baseline that refuses everything beats them both. The mechanism is the same in both places and it is worth stating plainly, because it cuts against the headline: a store that remembers less over-answers less. Ranked retrieval almost always surfaces something plausible enough to tempt an answer, while a curation-limited store often has nothing to offer and the model correctly says so. Eager retrieval needs an abstention discipline bolted on; sparse memory gets one for free.

Cost

Accuracy is half the story. The other half is what each answer costs, and here file-based memory pays twice: more tokens, for a worse answer.

A grouped bar chart of model tokens. Per question: file-based 287k in orange versus structured 19k in blue. Per correct answer: file-based 665k versus structured 27k. The structured arm additionally spends about 108k embedder tokens per question, a different and far cheaper currency, shown in the legend rather than summed.
Figure 8. Model tokens per question, and per correct answer, on LongMemEval-S. The two architectures pay in different currencies, so they are never summed: the structured arm's write path spends embedder tokens, not model tokens.

Comparing cost honestly requires separating two currencies. Both arms spend model tokens (prompt plus completion through the 35-billion-parameter model, as the serving layer reports them; hidden reasoning is not always reported, so these are floors), and those are directly comparable. The structured arm additionally spends embedder tokens (a 2-billion-parameter model producing vectors), which cost orders of magnitude less per token and have no counterpart on the other side. Summing them into one number would be meaningless, so I never do; nor does this ledger price latency, per-token rates, or infrastructure, so “cheaper” here means fewer measured model tokens, not a total cost of ownership.

Chat tokens per questionFile-basedStructured
Writing memory (LLM curation, amortized per question)246.1k0 (verified)
Answering (recall plus reasoning)40.4k19.3k
Total286.5k19.3k
Total per correct answer665k27k
Embedder tokens per question (estimated; separate currency)0107.8k
Wall-clock per ~50-session ingest~35 min~5 min
Table 2. The token ledger on LongMemEval-S, per question. Chat tokens and embedder tokens are different currencies and are never summed.

In model tokens (Tab. 2, Fig. 8), per question: file-based 287k against structured 19k. Divide by accuracy to get the cost of a correct answer, which is what you actually pay for, and it is 665k against 27k. On top of its 19k, the structured arm spends about 108k embedder tokens per question on the write path. Even charging those at par with model tokens, which wildly overstates them, it remains the cheaper architecture. The reason is the write path (Fig. 9).

Two horizontal timeline bars for ingesting one roughly 50-session history. File-based in orange is long, marked about 35 minutes and about 246k model tokens, subdivided into one LLM curation call per session. Structured in blue is short, marked about 5 minutes, embeddings only. A note says the structured write path asks no model to reason and is roughly seven times faster.
Figure 9. Ingesting one history. File-based memory reasons once per session to decide what to keep; structured memory just embeds. That is where the token bill and the wall-clock gap come from.

Curating a file is a reasoning act. For every session in a history, the model reads the current index, decides what is worth keeping, and rewrites a line. Over a full ingest that came to roughly 246k model tokens per history and about 35 minutes of wall-clock per history on my hardware. Structured memory writes by embedding, no model in the loop, which finished the same history in about 5 minutes, roughly a sevenfold speedup on the write path. The two write costs are in different currencies (one is LLM chat tokens, the other is embedding-model tokens), so I never subtract one from the other, but the direction is not close.

The read paths differ too, in a way that compounds. File-based recall is iterative: keep the index in view, grep, read a file, maybe grep again, then answer. That longer, multi-round path also turned out to be more fragile. Under a busy serving layer the file-based arm hit truncation on 20 of 144 answers against the structured arm’s 3, precisely because it asks the model to generate more, over more rounds, with more chances to be cut off. Some of that is my serving setup, but part of it is intrinsic: a longer read path has more surface to fail on.

The long haystack: LongMemEval-M

The -M variant asks the same questions over roughly ten times the history. The two store-only rows in Tab. 3 ran on the same 100-question sample, drawn once by seed before either arm ran (the drawn ids are published in the repo; the ordering of draw and runs rests on the study log), one retrieval and one reader call each under the benchmark’s official per-category judging, so their comparison is paired even though neither is paired with the main experiment:

System (LongMemEval-M)ScoreQuestions scored
Hybrid (store-only)0.750100 (pre-drawn sample)
Place-organized (MemPalace, store-only)0.600The same 100
Hybrid (full agent loop)0.632500 (complete set, different harness)
File-basedNoneNone: another ~2-3 days of runs at 10x the history
Entity-and-time (Graphiti OSS)NoneNone: ~600 single-stream GPU-days, or ~$7,000, to ingest
Table 3. LongMemEval-M, the long-haystack variant. The two store-only rows are paired on one pre-drawn sample; the agent-loop row is a different harness and sample, directional only. Two rows are unscored, each for a different reason, given below.

Long histories are the regime structure exists for, and the paired rows put a number on the claim: fifteen points, rescuing 22 questions against losing 7, exact p = 0.008 under the same paired test as the head-to-head below. The gap clears the sample’s own confidence interval, and the shape of the win matches the mechanism, with the hybrid sweeping the single-session categories (14/14 and 11/11) and pulling ahead on the multi-session and temporal content that long haystacks exist to test.

Store-only gave the reader one ranked context and outscored the full loop on -M (0.750 vs. 0.632) and the 100-question -S sample in Tab. 7 (0.80 vs. 0.72). Prompt and loop effects were not isolated, so both gaps are directional.

Graphiti OSS is unscored because ingesting the benchmark would be prohibitively expensive: it requires a reasoning call for each of the haystack’s 3.7 million messages, while an embedder takes milliseconds. At the roughly 14 seconds per message measured on this hardware, that is about 600 days of single-stream GPU time; parallel serving divides the wall-clock but not the bill, and renting a small hosted model to do the same work would have cost roughly $7,000 at list prices. I was not willing to spend either on one row of one table, so the row stays empty and the reason is published.

The file-based row is empty for a simpler reason: runtime. Fifty questions over ten times the history is another two to three days of runs, which fell outside this study’s window. Those runs were the only test of what this post’s main comparison implies about scale — that files fall further behind as histories grow — so that claim is measured at roughly 47 sessions and untested at 500, precisely where I expected the gap to be widest. Untested is not refuted, and the long-haystack rows above are a different pair: they say nothing about how files would have done. My guess is that the gap widens rather than narrows, and mostly on the write side, since an index capped at a couple of hundred lines cannot grow tenfold with the history behind it — curation drops more of what was never written down, while a ranked store simply retrieves from a larger pool. A guess is all that is, though, and the run that would settle it remains outstanding.

That is not a knock on the lineage so much as a statement of what it costs to reach the regime that matters. -M is where real assistants drift, and the paired rows above show it is where the benchmarks disagree: the flat store that is indistinguishable from the hybrid on LoCoMo falls 15 points behind here, where multi-session organization starts to pay.

LoCoMo

A single benchmark is a single opinion, so the same three arms (no memory, file-based, structured) also ran on LoCoMo, the other widely used long-term-conversation suite: 10 very long two-speaker conversations, each spanning dozens of sessions, with 1,986 questions across single-hop, multi-hop, temporal, open-domain, and adversarial (unanswerable) categories.

LoCoMo needs its story told before its numbers can be trusted, because it is the benchmark on which the field’s most public scoring fight happened. Zep reported 84% on it. mem0’s CTO filed an issue against their evaluation code arguing the real number was 58.44: the adversarial category had been counted in the numerator but excluded from the denominator, and the baseline configurations differed. Zep’s rebuttal re-ran with the error fixed and reported 75.14, while pointing back at mem0’s own reporting (whose LoCoMo figure has been cited at both 67% and 92.5% depending on the write-up). One system, one benchmark, three published numbers spanning 25 points, and the memory architecture never changed: the swing came entirely from scoring conventions, judge choice, and which categories count.

So why keep the benchmark? Because the dispute indicts the reporting, not the questions; because it is the suite the vendors actually compete on, so results on it travel; and because the fight teaches exactly this study’s premise, that a number means something only inside a fixed, published protocol. The dispute constrains the protocol here in three ways. Every score is published under both scopes, with and without adversarial, because whether to count that category is precisely the axis Zep and mem0 fought over. The analysis resamples whole conversations rather than questions, because LoCoMo’s questions cluster inside just 10 conversations and pretending otherwise makes intervals too tight. And I evaluate a disclosed, seeded, category-stratified sample of roughly 30 questions per conversation. The rest of the benchmark’s fine print (retrieval recall confused with answer accuracy in the wild, saturation critiques) lives in the appendix.

Accuracy

The run completed (Tab. 4, Fig. 10), and the result is the study’s most honest one, because the verdict depends on the scope in exactly the way the dispute predicts:

LoCoMo (300 questions, cluster CI)No memoryFile-basedStructured
All questions0.2170.3870.497
Excluding adversarial0.0170.3560.561
Table 4. LoCoMo accuracy under both scopes. The verdict depends on whether the adversarial category counts, which is the axis the vendors dispute.
A grouped bar chart of LoCoMo accuracy by question type, structured memory in blue against file-based memory in orange. Structured wins the memory categories: temporal 69 versus 31 percent, temporal-inference 52 versus 26, open-domain 66 versus 41. File-based wins single-hop 44 versus 37 and adversarial 51 versus 25. Overall 0.497 versus 0.387 on all questions, 0.561 versus 0.356 excluding adversarial; the no-memory floor of 0.217 is entirely adversarial refusals.
Figure 10. LoCoMo accuracy by question type. The structured arm dominates every memory category; the file-based arm wins single-hop, where curated one-line facts suffice, and adversarial, where having less to retrieve means less temptation to answer.

Excluding adversarial (the scope the benchmark’s own convention arguably prescribes), the structured arm wins clearly: the paired difference is +0.205 with a cluster confidence interval of [+0.063, +0.356], and it dominates the memory categories (temporal 0.694 against 0.306, open-domain 0.656 against 0.410). Include adversarial and the verdict collapses to a statistical tie (+0.110, CI [-0.007, +0.240]), because the file-based arm abstains better on unanswerable questions (0.508 against 0.246): its curation-limited store simply has less material to over-answer with, while ranked retrieval almost always surfaces something plausible enough to tempt an answer. Even the no-memory baseline “wins” adversarial outright (1.000) by refusing everything, which is why a blanket-refusal system still only scores 0.217 overall. The lesson generalizes: eager retrieval needs an abstention discipline, and a store that remembers less over-answers less. Both readings are published; neither is smoothed away. One disclosure: the file-based arm’s run predates a serving-layer retry fix, and 18 of its 300 answers died to output truncation and count as wrong under the symmetric rule; its numbers are floors.

Cost

The cost asymmetry survives the second benchmark, at a smaller scale (Tab. 5, Fig. 11). LoCoMo’s conversations are far shorter than the primary benchmark’s haystacks, so the file arm’s curation bill shrinks, but the ordering does not change: 22k model tokens per question against the structured arm’s 12k, and 58k against 23k per correct answer, with each conversation’s ingest amortized over its sampled questions. The structured write path again spends zero LLM tokens (verified against the serving ledger) plus about 0.8k embedder tokens per question in its separate currency. The gap compressing from roughly fifteenfold to roughly twofold is itself the finding: write-time curation is priced by history length, which is the primary benchmark’s cost story wearing smaller numbers.

Chat tokens per questionFile-basedStructured
Writing memory (amortized per question)4.9k0 (verified)
Answering (recall plus reasoning)17.6k11.6k
Total22.4k11.6k
Total per correct answer58k23k
Embedder tokens per question (separate currency)00.8k
Table 5. The token ledger on LoCoMo, with each conversation's ingest amortized over its sampled questions.
A grouped bar chart of model tokens on LoCoMo. Per question: file-based 22k in orange versus structured 12k in blue. Per correct answer: file-based 58k versus structured 23k. Ingest is amortized per question; the structured arm spends about 0.8k embedder tokens per question in a different currency, noted in the legend rather than summed.
Figure 11. LoCoMo model tokens per question and per correct answer, ingest amortized. Shorter histories shrink the file arm's curation bill; the ordering and the currencies stay the same.

The lineages, head-to-head

Everything above compares files against one structured design, and it leaves the lineage question open: inside the structured shape, does the graph earn its ingest bill? The head-to-head answers it in the most controlled frame available: strip every system down to its retrieval and hold everything else constant. Each store contributes exactly its top-20 results for the same 1,540 non-adversarial LoCoMo questions; one fixed reader (gpt-4o-mini) answers from that context alone, one fixed judge scores it, and every store’s row is produced by the same script. The entity-and-time lineage appears twice: as Zep’s published retrieval contexts, their production system’s real output (and a fairness note they are owed: their published 75.14 reproduces from their own artifacts; 0.7461 is the same context re-scored under this unified frame), and as their open-source engine Graphiti run end-to-end on their paper’s recipe, both embedders it names. These rows sit far above the bare-loop table above because everything about the frame differs; they are comparable to each other and to nothing else. For orientation, Tab. 6 puts the four methods side by side (pure place-organized differs from the hybrid only by dropping the temporal layer, so the hybrid bounds it closely):

MethodWrite pathRead pathTime handlingAggregationWhere measured
File-basedLLM curates markdownIndex in context + grep/readNone built inIndex + luckMain experiment
Place-organizedEmbed and file, no LLMLayered loads + ranked searchRanking heuristicsRanked-query hopeThis head-to-head
Entity-and-time (Graphiti)LLM extracts, resolves, invalidatesDistilled facts + entity summariesValidity windows in the storeEntity nodes, by constructionThis head-to-head
Hybrid (place + time)Embed and file, no LLMRanked search; associative expansion in the designDated facts; windows in the designRanked-query as measuredMain experiment and here
Table 6. The four methods side by side, and where each one is measured in this post.

Accuracy

Store (one reader and one judge throughout)LoCoMo (1,540 questions)LongMemEval-S (100 questions)
Hybrid (this study’s structured arm)0.78250.80
Place-organized (MemPalace, dense over raw turns)0.77920.60 †
Entity-and-time (Zep Cloud, published contexts)0.7461None
Entity-and-time (Graphiti OSS, two embedder configs)0.5338 / 0.52860.35
Table 7. Store-only accuracy on both benchmarks. Within each column every store is read and judged by one fixed model: `gpt-4o-mini` on LoCoMo, and the local 35B under LongMemEval's official per-category rubric. The columns are therefore comparable down, not across. † These two LongMemEval-S runs never persisted per-question contexts, so unlike every other number in this table their rows are not in the public repository; the repository's verifier lists them in its exceptions ledger.
Two bar panels under one reader and judge. Left, LoCoMo over 1,540 questions: hybrid 78.3, place-organized MemPalace 77.9, Zep Cloud 74.6, Graphiti OSS 53.4 and 52.9 with the bge-m3 embedder. Right, LongMemEval-S over a 100-question sample with the official rubric: hybrid 80, place-organized 60, Graphiti OSS 35. Blue bars are raw dated facts with ranked recall, green bars are LLM-distilled graphs; the ranking does not transfer across benchmarks.
Figure 12. Store accuracy under one reader and one judge. Raw dated facts beat LLM-distilled graphs on LoCoMo; the flat store that ties the hybrid there trails it by 20 points on LongMemEval-S. No single benchmark ranks memory systems.

Four findings (Tab. 7, Fig. 12).

  • The hybrid beats the graph vendor’s published retrieval, and the difference is real under a paired test (McNemar’s test, which scores only the questions the two systems disagree on; p < 0.01). So, separately, does the plain dense store: raw turns beat distilled facts here before any hybrid machinery is added at all.
  • The hybrid is statistically indistinguishable from the flat vector index (+0.3 points, paired CI95 [-1.8, +2.4]), which is the uncomfortable finding and belongs in the open: no detectable gain from place-plus-time on this benchmark, though the interval allows small effects either way. It is also only half the story: the same two stores, paired on LongMemEval-M’s long haystacks (Tab. 3), separate by 15 points (0.750 against 0.600, p = 0.008). The two arms differ in more than structure (fusion, reranking, recency, atomic facts against raw turns), so read that as this implementation beating that one at long histories while being indistinguishable from it at short ones: the benchmark-disagreement point again, made by one pair of systems.
  • The distilled pipelines lose to the raw-text pipelines. Both graph rows hand the reader LLM-distilled facts and entity summaries; both trail every raw-turn store, and the strongest graph row loses 3.3 points to the flat index while spending six times its context. The pre-built entity aggregates that make the lineage attractive for enumeration questions do not surface as a net win anywhere in this table; whatever they recover, the distillation loses more elsewhere. This is the single-session regression Zep itself discloses, visible benchmark-wide once the reader is held constant.
  • An LLM-at-ingest design is bounded by its extractor, and the extractor bill is real. Graphiti OSS with the vendor’s own models lands around 0.53, so much of its 21-point gap to the vendor’s cloud contexts sits outside the extraction model’s capability. Driven instead by this study’s local 35-billion-parameter model, the same engine collapses to 0.29 (a study-log run whose per-question rows are not among the published data), and the mechanism is visible at ingest: it extracts several times fewer facts per message than the cloud output implies. A store that only knows what its extractor wrote down starves quietly.

The LongMemEval-S column of Tab. 7 is the same three stores under the benchmark’s official per-category rubric on a pre-drawn 100-question sample (the hybrid’s 0.80 there is a single retrieval and a single read under a shared reader prompt, which is why it sits above the same system’s agent-loop 0.72 on this sample; Tab. 3’s discussion unpacks that ordering). Read the two columns across and the point makes itself: the flat store that ties the hybrid on LoCoMo trails it by 20 points on LongMemEval, because LoCoMo mostly rewards verbatim lookup inside a few dozen sessions while LongMemEval forces multi-session organization. The two benchmarks disagree about the same pair of systems, in opposite directions. No single benchmark ranks memory systems.

The same frame also measures the thing this post keeps insisting on, and it is worth putting a number on rather than gesturing at. Evaluating byte-identical retrieval with the local 35B as both reader and judge instead of gpt-4o-mini doing both moved the hybrid’s LoCoMo score by 6.9 points (0.7130 against 0.7825); both roles change together, so the swing belongs to the evaluation stack as a whole, not to reader quality alone. Separately, re-judging identical answers under different judge prompts moved category-level accuracy by 5 to 15 points. Set that against the architecture (Tab. 8): the hybrid and the flat index differ by 0.3 points, and both sit 3.3 to 3.6 from the hosted graph. On this benchmark, changing the stack that evaluates the memory matters more than changing which of those three stores you built. Only Graphiti OSS sits further away than the stack does, and by a lot: even the cheapest route to it, Zep Cloud to Graphiti OSS, costs 21.2 points, three times the stack’s swing. The scope matters, because the claim inverts with the haystack: on LongMemEval-M the same hybrid-versus-flat pair that differs by 0.3 here differs by 15 (Tab. 3), better than twice that swing. The evaluation stack dominates where the stores tie; the store bundle dominates where the benchmark actually stresses it.

That last gap needs care, because three different things sit behind that number and conflating them makes it unreadable:

  • The reader sits at the end and answers from whatever context it is handed. It is identical for every store, which is what makes the store comparison valid at all; the 6.9-point row swaps it together with the judge.
  • The extractor sits at the start, inside the store, and decides what ever gets written down. It is part of the store being compared, not part of the harness around it.
  • The pipeline is what the extractor runs in: how many passes it makes over each message, what it resolves, what it keeps.

So which of the three explains the 21 points between the last two rows of Tab. 7, the hosted Zep Cloud at 0.7461 and the self-hosted Graphiti OSS at 0.5338? Not the reader: it is the same model for both. Not the extraction model’s capability either, because the open engine ran with the same class of extractor the vendor’s published numbers were built with and still landed where it did. What is left is everything the hosted service does around that extractor, and this is the point where the comparison reaches the edge of what it can honestly claim.

Zep Cloud is a hosted product, and its row here is Zep’s own published context. I can measure what reaches the reader on each side, not the ingestion or ranking that produced it. The open engine’s contexts are visibly thinner, carrying fewer stored facts and much shorter entity summaries, but that is a property of the released artifacts rather than a description of anyone’s internals. One known difference does not favour them: their published ingestion reads a blip_captions key where the LoCoMo field is blip_caption (zep-papers#9), dropping image captions that my runs kept.

None of this suggests their published number is wrong. It reproduces from their own released grades, and their contexts re-scored under this study’s reader and judge give the 0.7461 in Tab. 7, within a point of their published 75.14. The 21-point gap is real and reproducible; its cause is not observable from outside. Read “the hosted pipeline” as a label for the part I could not see, not a mechanism I verified. A store can only answer from what its extractor wrote down, however good the reader in front of it, and that is why importing a number from someone else’s protocol tells you nothing.

What changedFromToPoints lost
The reader+judge stack, retrieval byte-identicalgpt-4o-mini 0.7825Qwen3.6-35B-A3B-mxfp4 0.71306.9
The store, reader unchangedHybrid 0.7825Place-organized 0.77920.3
The store, reader unchangedHybrid 0.7825Zep Cloud 0.74613.6
The store, reader unchangedPlace-organized 0.7792Zep Cloud 0.74613.3
The embedder inside one storeGraphiti OSS 0.5338Graphiti bge-m3 0.52860.5
The store, the cheapest route into the open engineZep Cloud 0.7461Graphiti OSS 0.533821.2
Table 8. What each single change costs on LoCoMo, everything else held fixed. The first row swaps the reader and the judge together, so it prices the evaluation stack rather than the reader alone; here that stack moves the score further than swapping between any two of the three stores that work, and on the long-haystack benchmark the ordering inverts ([Tab. 3](#table-3)). The last row is the cheapest of the six routes into the starved open engine, and even that costs three times the stack's swing; the dearest of the six, hybrid to the bge-m3 variant, costs 25.4. Zep Cloud and Graphiti OSS come from one vendor and are read by the same model here, so what separates them sits inside the stores rather than in the reader in front of them.

Cost

The graph lineage pays twice (Tab. 9, Fig. 13). At read time, distillation was supposed to buy density, but the graph rows hand the reader six times the context of the raw-turn stores (21.5k chars median against 4.0k and 3.5k) and scores lower with it. Graphiti OSS is leaner at 7.9k and scores lower still, so density alone is not what the hosted pipeline is buying. At write time, the raw-turn stores embed while the graphs run an LLM over every message, and that difference compounds brutally with history length. Each message costs the graph a reasoning call, or several: extract the entities and facts, resolve them against the entities already in the store, then check whether the new fact invalidates an old one. Measured on this hardware that ran about 14 seconds per message, against a few milliseconds to embed one. LongMemEval-M’s haystacks hold roughly 3.7 million messages, so the arithmetic lands at about 600 days of single-stream GPU time to ingest one run (parallelism divides the wall-clock, not the bill), against hours for the embedding-only stores, which is why the graph lineage has no long-haystack row at all.

Six hundred single-stream days is a fact about my hardware, not about physics, and it is worth saying so plainly because the hosted vendors do not wait for it: the work parallelizes almost perfectly, so a hundred concurrent workers bring the wall-clock to about six days. What no parallelism touches is the unit economics. Every message costs the graph several LLM calls where the raw-turn stores cost one embedding, and at list prices for a small hosted model that is roughly two orders of magnitude more per message: about $14 of ingest for a single long user history, against about $0.03. Graph memory is affordable; it is just priced like a product decision rather than an implementation detail, and the bill scales with everything your users ever said. Context sizes are medians over the same 1,540 questions; the ingest comparison is wall-clock on identical hardware.

StoreMedian context / questionIngest
Hybrid4.0k charsEmbedder only: ~$0.03 per long user history
Place-organized (MemPalace)3.5k charsEmbedder only: ~$0.03 per long user history
Entity-and-time (Zep Cloud)21.5k charsLLM per message: ~$14 per long user history
Entity-and-time (Graphiti OSS)7.9k charsLLM per message: ~600 single-stream GPU-days, or ~$7,000, per -M run
Table 9. What a retrieval costs in the head-to-head: context handed to the reader per question, and what ingest spends to build the store. Ingest prices are list-price estimates for a small hosted model.
A bar chart of median retrieved context per question in characters: hybrid 4.0k, place-organized MemPalace 3.5k, Zep Cloud 21.5k, Graphiti OSS 7.9k. A note adds that the raw-turn stores embed at ingest while the graphs run an LLM per message, measured at roughly 600 single-stream GPU-days per run at LongMemEval-M scale against hours for the embedding-only stores.
Figure 13. Retrieval context per question in the head-to-head. The hosted graph spends six times the context of the raw-turn stores and still scores lower; their shared other bill, an LLM over every message at ingest, is what priced the lineage out of the long-haystack benchmark.

What file-based memory is actually good at

A fair comparison has to state the other side, because file-based memory is popular for real reasons, and none of them are refuted by the numbers above.

  • It is human-readable and human-editable. Your memory is a folder of markdown files. You can open it, read it, fix a wrong fact, delete a stale one, or commit it to git. A vector store is opaque by comparison. For a tool you operate yourself, this is worth a great deal.
  • It has zero infrastructure. No embedder, no vector index, no background workers, no graph. If your agent already has file tools, memory is free to add. Structured memory is a small distributed system you have to run.
  • Its writes are distillation. Because the model decides what to keep, each memory is a considered lesson, not a raw fragment. At small scale that curation produces a genuinely tidy, high-signal store, which is exactly the regime a personal coding assistant lives in.
  • Its reads are cheap when the store is small. Everything above is the large-history regime the benchmark stresses. When the whole memory fits in the index, the read path is just the index in context, and the grep never fires. A few hundred lines of curated notes covers a lot of everyday use.

Read the accuracy numbers with that scope in mind. The benchmark deliberately lives in the hard regime: dozens of sessions, facts scattered across them, questions that force a join. That is the regime where curation forgets and a small index cannot hold enough, and it is the regime a memory product has to survive. It is not the regime a single-project assistant with fifty lines of notes lives in, and there it is not just adequate, it is the better engineering trade. The regime-dependence cuts both ways, and it is worth being honest about: on easier, factual-recall benchmarks the gap narrows sharply. Letta, a memory startup, reported 74% on LoCoMo using nothing fancier than plain files, and argued a filesystem may be most of what you need. The structured store earns its keep specifically where the questions force joins across many sessions, which is the part of the problem I find most interesting and the part a memory product cannot dodge.

Remembering what worked: the agentic benchmarks

Everything above measures one kind of remembering: what was said. An agent accumulates the other kind too, what worked: the know-how of past attempts. The natural question is whether this post’s architectures carry over, so the same structured store was put to work on the agentic benchmarks the memory-training literature uses: ALFWorld (household tasks in a text world: find the mug, heat it, put it away) and WebShop (find and buy the right product in a catalog, scored with partial credit). Memory here is an experience bank: training-split episodes distilled into atomic entries (a task pattern, the moves that worked), embedded, and retrieved top-k into the acting model’s prompt. Nothing is trained; it is the same architecture as the conversational study, wearing different content.

The bar in this realm is MemHarness, the experience architecture described earlier: the 7-billion-parameter policy whose retrieval, critique, and reconstruction were trained by reinforcement learning. Being trained rather than bolted on turns out to be the whole story. Two untrained actors ran with and without the experience bank, everything else frozen, and each benchmark gets its own subsection below, mirroring the evaluation section. Two reading notes apply to every table: MemHarness’s out-of-distribution (OOD) number is the comparable one, since the untrained rows run unseen splits; and “no memory” removes only the experience bank, the harness’s task scaffolding (playbooks, target hints, loop guards) stays in every untrained row, so the ablation isolates retrieved memory. There is no cost subsection here, deliberately: the three pay in currencies that do not share an axis (self-hosted GPU time, API dollars, training compute), and charting the two we measured would imply a comparison the third cannot join.

ALFWorld

ALFWorld is a text world of household tasks: find the mug, heat it, put it away. Six task categories, binary success per game, scored as macro SR (success rate averaged over categories, so no category dominates). The evaluation runs the 134 unseen games.

Accuracy

ActorMacro SR
Local 35B, no memory0.603
Local 35B + experience bank0.645
Frontier actor (claude-sonnet-5), no memory0.959
Frontier actor + experience bank0.973
MemHarness (GRPO-trained 7B)0.852 / 0.859 OOD
Table 10. ALFWorld macro success rate by actor, over 134 unseen games.
A bar chart of ALFWorld macro success rate over 134 unseen games. The 35B scores 60.3 percent without memory and 64.5 percent with the experience bank. The frontier actor scores 95.9 without memory and 97.3 with the bank. MemHarness's out-of-distribution row is 85.9. Gray bars are no-memory with scaffolds kept, blue bars add the experience bank, green is the trained policy.
Figure 14. ALFWorld success rate by actor. The weak actor gains 4.2 points from retrieved experience, though not significantly; at frontier quality the benchmark saturates and memory rescued exactly two games.

The ablation runs at both actor tiers, and the deltas line up as the headroom pattern predicts: the weak actor gains 4.2 points from the experience bank, the frontier actor 1.4. Only the direction is claimable, though. The weak actor’s gain rescued 16 games and cost 10, which an exact paired test puts at p = 0.164, inconclusive under the pre-set threshold, so ALFWorld corroborates the pattern without carrying it; the significant weak-actor evidence is WebShop’s alone. One detail inside that null is worth keeping: five of six categories move positive with memory, while the category the 35B fails by looping is unmoved to three decimals. Retrieved experience does not repair a policy-level failure mode.

At frontier quality the benchmark saturates instead (Tab. 10, Fig. 14): the tasks yield entirely to strong reasoning (ten-step solves, four of six categories perfect), memory rescued exactly 2 games and hurt none (p = 0.5), and the untrained frontier baseline exceeds MemHarness’s number. That last fact is not claimed as a beat: it is actor class plus harness scaffolding, not a method comparison. The right reading is that ALFWorld’s bar is procedural competence, find the object, use the appliance, with a ceiling any sufficiently strong actor reaches, and there are two routes to that ceiling: MemHarness trained the competence into a 7B; this study rented it from a frontier model. Memory is rounding error on both routes (ours +1.4 points at p = 0.5, theirs +2.2, and their own ablation shows raw replay hurts their trained policy), so lining the results up gives an ordering that is actor class all the way down: frontier, then trained 7B, then scaffolded 35B, then a frontier model on their plain scaffold-free harness (their strongest closed-model row, 62.1). Memory has no headroom left to buy here, the agentic twin of the head-to-head’s “hybrid ties a flat index” finding: the actor dominates, memory works the margin.

WebShop

WebShop is product search against a 1,000-item catalog with a purchase at the end: 500 test sessions, a 15-step budget. Two metrics bracket it: score grants partial credit for a near-miss purchase, and SR counts only perfect ones. The small catalog often contains no exact match for the instruction, which caps attainable reward for every actor.

Accuracy

ActorScoreSR
Local 35B, no memory63.50.376
Local 35B + experience bank66.00.418
Frontier actor (claude-sonnet-5), no memory65.10.444
Frontier actor + experience bank65.20.450
MemHarness (GRPO-trained 7B)87.40.756
Table 11. WebShop score and strict success rate by actor, over 500 test sessions.
A bar chart of WebShop strict success rate over 500 sessions. The 35B scores 37.6 without memory and 41.8 with the experience bank, the agentic benchmarks' only significant memory-ablation effect. The frontier actor scores 44.4 and 45.0. MemHarness's trained policy stands alone at 75.6. Gray bars are no-memory with scaffolds kept, blue bars add the experience bank, green is the trained policy.
Figure 15. WebShop success rate by actor. The weak actor gains 4.2 points from retrieved experience, the frontier actor gains noise, and only the trained policy reaches the bar.

WebShop delivers the agentic benchmarks’ only significant memory-ablation effect, and their clearest boundary (Tab. 11, Fig. 15). The weak actor gains 4.2 points of success rate from the bank (paired McNemar, p = 0.022), exactly where theory puts it: far from its ceiling, in a domain where episode know-how (query phrasing, option discipline, the scoring rules) transfers between tasks. The frontier actor gains +0.6 points of success rate (p = 0.8), landing at nearly the same total as the 35B; the trained policy’s 0.756 shows that what binds the untrained arms is not the catalog alone but what untrained interaction with the hidden rubric extracts. Note what that ceiling does to actor class: the same actor swap that buys 31 points of success rate on ALFWorld buys +1.6 score here, because WebShop’s reward is shaped by the catalog and its partial-credit mechanics, not by actor smarts. The deeper difference between the two benchmarks is what each one hides. ALFWorld states its goal in the observation, so success yields to reasoning, and the one frontier actor tested gained nothing detectable from the bank there (0.959 against 0.973, p = 0.5). WebShop grades with a rubric the agent never sees, weighing attributes, options, and price into partial credit over a catalog that often has no exact match, and no amount of reasoning over the observation reveals how that grader will score a near-miss. In these experiments nothing taught it except training against the reward signal itself, and retrieval never sees the reward: a bank stores what the agent did, not what the grader thought of it. That is why only training reaches the bar: every training-free arm lands at a score of 63 to 66 against MemHarness’s 87.4, and their number comes from reinforcement learning against the environment’s own reward, which teaches the policy the reward’s mechanics, when to settle for a partial match, when to stop browsing, what an option is worth. Neither prompting nor a stronger actor replicates that, and none of the stores tested here closes the gap from the outside.

That claim can be probed from the inside too, with one hard scope limit stated up front: the probe runs on my port of their frozen 7B actor, and that port falls well short of their published baselines, so it can speak about this port, not about their published system. Hold the port fixed on WebShop (full catalog, 500 sessions) and swap what its memory holds. Its own released 7,859-episode bank, injected through its own wire format and retrieval semantics, scores 69.5 with a 0.306 success rate against the no-memory 71.0 and 0.300 (p = 0.69). The same bank under a different retrieval semantics, situation-match instead of memory-text match, scores 69.1 and 0.298. On strict success the three arms are statistically indistinguishable; on partial-credit score both memory arms sit nominally below the no-memory baseline (by 1.5 and 1.8 points, the latter’s paired interval excluding zero), so if anything the bank costs this port a little. What that establishes: the tested injections did not help this port, so the bank does not carry its value in a form that survives being bolted on from outside. What it cannot establish: that bank content or retrieval plays no role in the published system, or that the training is the cause. The training remains the leading explanation because their own ablation points the same way from the trained side, with raw replay hurting their trained policy, the same null as our frontier arms.

Lay the results beside each other and one pattern organises the realm: memory paid only where the actor had headroom. Two actor tiers on two tasks cannot establish a law, and the weak-versus-frontier difference in memory benefit is itself not significant; but every observation lines up the same way. A weak actor far from ceiling gains real points from retrieved experience; a frontier actor gains nothing detectable, having already reached what untrained interaction with the task seems to extract (the trained policy’s higher bar shows the task itself is not saturated); a policy trained for the task is actively hurt by raw replay. This is the consolidation null from earlier in the post seen from the other side: there a capable reader absorbed the store’s disorder and left tidying nothing to buy, here a capable actor absorbs the task and leaves memory nothing to buy. Training buys its bar at the price of narrowness, too: served frozen outside its own harness, the released MemHarness model is acutely sensitive to exact prompt format, the specialization reinforcement learning produces, where a frontier actor’s robustness is precisely the thing you rent. That places every retrieval-shaped system in this post, files, stores, temporal graphs, and hybrids alike, on one side of a line: bolt-on memory, model-agnostic, paid for at write and read time, its value floating on the gap between the actor and the task. MemHarness sits on the other side: memory as trained behavior, paid for in training compute, inseparable from its actor. The conversational benchmarks reward the first kind everywhere; the agentic benchmarks reward it only while the actor is weak; past that line the question stops being “which store” and becomes “whose weights”.

One more disclosure belongs with the bar itself, because it cuts against the comparison. MemHarness’s numbers above are quoted from its paper. Running their released model on my own serving stack, under a faithful port of their harness and prompts, does not reach them: 0.581 macro on ALFWorld against their 0.830 without memory, and 71.0 score with a 0.300 success rate on WebShop against their 87.4 and 0.756. The shortfall has the same signature on both benchmarks: the approach reproduces and the precision does not, exact option matches on WebShop and multi-step thermal sequences on ALFWorld, a shape consistent with serving numerics and 8-bit quantization of a sharply peaked policy rather than with anything about memory, though that attribution is untested (the separating run, bf16 against 8-bit, was not made). I report it because it makes the comparison’s frame explicit. Their published bar stands as published; my arms are measured on my stack; and the distance between those two statements is the same cross-stack caution this post applies to every other number it does not own.

Provenance, disclosed: WebShop’s official dataset is org-locked, so the runs used the community mirror of the same files (1,000-product setting); all frozen arms are single runs, and the memory ablations are paired per-episode. The frontier arms cost about $22 of API spend on ALFWorld and $34 on WebShop, the latter including two voided protocol iterations.

Takeaways

  • The store architectures are bets about where memory’s cost sits, and each is right somewhere. File-based memory bets on the model’s judgment and a filesystem, pays in model tokens at write time and literal search at read time, and buys transparency and simplicity: the right bet when memory is small, human-owned, and secondary to the task. Structured memory bets on an embedder and a ranker, pays in infrastructure, and is built for recall that holds up as history grows; the long-haystack pair here is consistent with that bet, though no scaling curve was measured.
  • When memory is the task, structure wins on both axes at once. Under a fixed model on a hard benchmark, the structured store beat files by 28.7 points on held-out questions (95% CI [22.1, 35.4]) at a fraction of the measured model tokens per correct answer.
  • Sparse memory abstains for free. File-based memory wins the questions whose right answer is “I don’t know”, on both benchmarks: remembering less means over-answering less. Build the structured kind and you must budget for an abstention discipline.
  • Raw dated facts beat LLM-distilled graphs, and cost less twice over. Inside the structured family, a good ranker over raw facts beat the graph lineage on the benchmark the graph is sold on, while the hosted graph spent six times the reader context to score lower. Whether place-plus-time beats a flat ranked query depends on where you ask: no detectable advantage on LoCoMo, a significant one on LongMemEval-M’s long haystacks, and no scaling curve connecting the two, which differ in more than history length.
  • Reasoning at ingest is a product decision, not an implementation detail. A graph store spends several model calls on every message a user ever sends, where a raw-turn store spends one embedding: roughly two orders of magnitude more, about $14 to ingest one long history against about $0.03. It parallelizes, so it is a bill rather than a wall, but the bill scales with everything your users ever said. It is also why this study has no graph row on the long-haystack benchmark: that one row would have cost about 600 single-stream GPU-days of compute, or about $7,000 of hosted inference, to fill.
  • Consolidation is the third path, and the measured result is a null. Both store architectures can run a background pass that reorganizes what is already stored, promoting what gets used or merging what repeats. Built here, it merged real duplicates and bought no accuracy at the scale tested. The design logic says it should pay once the mess outgrows what the reader can hold; that remains a hypothesis, since no consolidation-positive regime was measured.
  • The ruler can outweigh the architecture, and which one dominates depends on the benchmark. Swapping the reader-and-judge stack moved a score by 6.9 points on byte-identical retrieval, more than the gaps between the three stores that work where they tie (0.3 to 3.6 points); on the long haystack the same store pair separates by 15. No single benchmark ranks these systems, and no number means anything without its protocol attached.
  • Retrieved memory paid only where the actor had headroom. The agentic benchmarks draw the sharpest boundary in this post, as an observed pattern on two actor tiers and two tasks rather than a law: real points under a weak actor, no detectable effect under a frontier one, harm under a policy trained for the task. Where the task yields to reasoning, a frontier actor reaches the trained bar with no memory at all; where the reward has a structure only practice teaches, training stands alone, and it buys that bar at the price of narrowness. Below that line the architectures in this post are the game; at the line, the game becomes training.

Both headline numbers came from the same model answering the same questions. The only thing that changed was the shape of what it remembered with.

Appendix: methods and caveats

The story is complete without this section. What follows is the fine print: how the questions were split, every limitation I know about, and the caveats each number carries. Nothing here overturns a result, but it tells you how far each one can be trusted.

How the questions were split, and what “tuning” means

The 500 LongMemEval questions were split once, before any runs: a seeded, stratified 144-question tuning set, a 256-question holdout, and 100 left in reserve. Tuning-set numbers are provisional and never the headline; the holdout is scored exactly once per configuration. “Tuning” means prompts and configuration only, the model’s weights never move: the shared answering discipline (a six-round tool budget, an output cap, a truncation-rescue step, a facts-then-dates-then-verify format), the structured arm’s retrieval depth (top-12) and question-blind recency preload, and the file arm’s index budget (200 lines or 25 KB) and recall tools. The file-based arm got an equal tuning budget, and two of its frozen settings came from watching its own failures: the same truncation rescue the other arm has, and a guard against index-wiping writes. The holdout then judged both arms with everything frozen.

Limitations

  • The shared answering prompt has a heritage. Its discipline was developed in earlier work whose read path resembled the structured arm’s. Equal tuning budget in this study is not equal ancestry; a file-native prompt built from scratch might serve that arm better, and I did not build one.
  • The file-based arm is a reconstruction, deliberately. Its curation instructions are a faithful-as-documented rewrite of an unpublished original, every mechanism decision traced to a cited public source in the released spec. I chose not to validate against the shipping CLI: a closed-product run is a snapshot of whichever model version shipped that week, unreproducible by design. The fidelity burden is met by the traceable spec, the oracle control below, and a published envelope check (save rates, index shapes, read patterns) that anyone with the real tool can run to falsify the reconstruction.
  • One model family judges itself, and an independent judge has now audited part of it. In the main experiment the judge is identical across arms and finished with a deterministic refusal pass, but it shares a model family with the arms it scores. For the store head-to-head, that concern has been tested: a frontier judge from a different vendor re-scored every arm’s published responses on a frozen 100-row sample. It grades uniformly stricter (4 to 7 points on every arm, agreement 0.91 to 0.96, Cohen’s kappa 0.82 to 0.89, with a 0.05 agreement spread that bounds agreement but cannot rule out directionally different errors per arm), and every ranking survives, with the hybrid’s win over the graph vendor significant on a tenth of the data (p = 0.024). The supported claim is rankings preserved on that frozen sample. The main experiment’s own judge remains unaudited.
  • The holdout was widened once, and the verdict stayed on the blind set. Mid-study I extended the held-out set from 256 to all 356 non-tuning questions; the added questions had never been run or tuned on, but one arm’s solo holdout score had been seen, which is partial peeking. An independent review called it, so the verdict was locked on the blind 256. The tables in this post report all 356, because that is the set whose per-question rows are published, and widening changed the gap by 0.0002, so the two agree to the fourth decimal. The commit history proves the ordering.
  • Truncation hit the arms unequally (20 of 144 file-based answers against 3, under a busy serving layer). The frozen rule counts both as wrong symmetrically, and the gap survives excluding every truncated row.
  • Absolute numbers reflect a minimal harness. Both arms run a deliberately minimal shared loop because mechanism isolation is the point. A richer loop can help or hurt; for calibration, one production configuration of the structured mechanism reaches the mid-0.80s on this benchmark’s held-out questions.
  • The oracle control splits the gap descriptively, not causally. Answering with the file arm’s entire memory directory in context and no tools scores 57.1% held-out, between the file arm’s 44.9% and the structured arm’s 73.6%: in aggregate, 12.2 points of the gap sit on the read side (saved but not found) and 16.5 on the write side (never written down). Per question the interventions are non-monotonic (the oracle also changes how the reader sees the store, and it loses questions the file arm won), so this is an aggregate split between arms, not an identification of where each point was lost. On preference questions the oracle beats the structured arm (72.2% against 61.1%), consistent with a search miss; on abstention it scores exactly what the file arm scores, which suggests over-answering tracks eager retrieval rather than context volume.
  • The comparison is measured at one history length. Both arms ran at roughly 47 sessions per question. The 500-session variant is another two to three days of runs at ten times the history, outside this study’s window, so the prediction that files fall further behind as histories grow (Tab. 3) is untested rather than confirmed. The long-haystack rows that do exist compare two structured stores, not files against structure.
  • Wall-clock is indicative, not controlled; token counts are the load-independent cost metric.
  • Reproducibility has a scope. The baseline, file arm, judge, and analysis run against any OpenAI-compatible endpoint; the structured arm calls a memory service, and its raw per-question rows are published for inspection either way in a40-labs/memory. The protocol, including every amendment and its timing, was recorded in the study’s private repository before the scored runs; the public repository carries the artifacts and an explicit ledger of what it cannot substantiate, not a timestamped registration.

Reading LoCoMo

Retrieval recall is not answer accuracy, and LoCoMo numbers in the wild mix the two: a store can be scored on whether the right item merely surfaces in its top-k, or the whole system on whether it answers correctly end-to-end. The gap is structural; this study’s store surfaces the right session about 95% of the time on LongMemEval while its end-to-end accuracy sits at 0.73, the answering step consuming the rest. MemPalace publishes only retrieval recall on LoCoMo, with an explicit no-QA disclaimer, while the QA numbers people quote (Zep’s disputed 84 / 75.14 / 58.44, mem0’s ~67) are LLM-judged answer accuracy from entirely different systems; putting one next to the other is comparing different sports. Beyond that, the benchmark is contested ground with no agreed state of the art and no clean third-party reproduction of the leaders, and the research community has argued it is close to saturated. Its questions cluster inside 10 conversations, so honest confidence intervals must resample conversations, not questions. And its adversarial category inverts the incentive, rewarding refusal and punishing exactly the eager retrieval that helps everywhere else, which is why every LoCoMo score in this study is published under both scopes. One disclosure: the file-based arm’s LoCoMo run predates a serving-layer retry fix, and 18 of its 300 answers died to output truncation and count as wrong; its numbers are floors.

Head-to-head boundaries

Every head-to-head row is a single run, and identical reruns at temperature 0 drifted by 0.3 to 0.4 points, so the last decimal is noise. Graphiti-OSS is a best-effort parity configuration of the vendor’s open-source engine, not their hosted product. The hybrid’s retrieval was verified against a call ledger to confirm its reranker actually ran on every row, because that component fails open (a degraded run returns a full, silently unranked result set; 295 early rows failed exactly that check and were quarantined and re-run). What is published, stated precisely: per-question verdicts, hit counts, and context sizes for every head-to-head arm, with the shared judge prompt, in a40-labs/memory, where a verifier re-tallies every score and re-derives every statistic. The retrieved contexts, answers, and grades themselves are not republished: Zep Cloud’s contexts are their data (their repository has them), and the full bundles for the other arms live in the study archive. The published artifacts support re-tallying and re-deriving, not independent re-judging.

A side note for Obsidian users

Many people wire an Obsidian vault (markdown notes joined by [[wikilinks]]) into an agent as its memory, usually over MCP; Basic Memory is the clearest example. By this post’s taxonomy that is the file-based kind: storage the model curates, read back by text search. What the vault adds is an explicit link graph, but authored at write time by hand or by the model (one more thing curation has to get right) and walked deterministically rather than ranked: a graph doing a retriever’s job through foresight. The vault crosses toward the structured kind only when an embedding index is bolted on (Smart Connections, Obsidian Copilot), which swaps the grep for exactly the ranked read path the structured store uses while the storage stays plain markdown. The honest picture is a spectrum: a plain vault sits with the file arm, an embedded vault sits closer to the structured one, and the write-side curation cost this post measured is paid the whole way across, right up until you stop asking a model to decide what to keep.