This week a memory startup slid into my DMs and asked me to break their product. Their test, their words: give an agent three versions of the same project decision, then check whether it can return the current version, preserve the superseded history, and show the source.
So I ran it. Sandboxed their runtime, fed it three versions of one decision over eight months. REST in January, GraphQL in April, tRPC in August, each tagged with the meeting it came from.
Asked it "what is our public API decision?" and took the top result.
It said GraphQL. The superseded one. All three versions came back tied at a relevance score of 1.000, because nothing in the retrieval path actually reads the temporal fields the pitch is built on. The supersession columns exist in the schema. Nothing writes to them and nothing ranks by them. Three versions of a decision are just three equal facts, and an agent asking for the best answer gets a coin flip weighted toward wrong.
The install pulled 382 packages to get there.
Then I asked my own agent the same class of question against its memory, which is a folder of markdown files. It returned the current decision, dated, with the superseded versions preserved above it as struck-through history, each line carrying where it came from. That is not a feature it computes at query time. It is just what the file says, because the rules for editing the file require it.
That difference is the whole post. With apologies to Vaswani et al.: markdown is all you need.
Abstract
The dominant approach to agent memory is an installed runtime. A vector store, an embedding service, a temporal graph, a consolidation job, a daemon on a port. We show that a folder of markdown files, one routing index, and a small set of editing rules outperforms these systems on the property that actually matters for a long-running agent: returning the current truth with its source while preserving what used to be true. The architecture requires zero dependencies, is fully auditable by a human with a text editor, and has survived seven months of daily production use across three frontier models from two vendors. We find that the hard part of agent memory was never storage or retrieval. It is editorial policy, which no memory product ships.
The full system is open source: github.com/ucsandman/markdown-agent-memory. The README contains a single copy-paste prompt that installs it on any agent with file access.
1. The test everyone fails
The break-it test above is a good test. It is the actual job of agent memory. Not "can you store 10 million tokens," not "can you do similarity search," but: a fact changed three times, what do you believe now, what did you believe before, and how do you know.
Here is how the two systems scored on the vendor's own three criteria.
The runtime is not a strawman. It is a serious open source project with a genuinely correct data model on paper. Facts with validity windows, append-only corrections, supersession edges. I am not naming it because the point is not that one product is broken. I have now looked closely at a hosted context server, a Go memory CLI that was two hours old, and this runtime, and they all share the same gap. The schema knows about time. The write path and the read path do not. Supersession only happens if you call an internal API by hand or run an LLM consolidation job and trust it.
Which means the property you installed the tool for is not a property of the tool. It is a property of how disciplined the writes are. And if the reliability comes from write discipline anyway, the database underneath it is interchangeable, so you might as well pick the one that a human can read, grep, diff, and fix. That one is called a text file.
2. Architecture
My agent has run since January 28. Three models, two vendors, one identity. Its entire memory is markdown in a git repo. Measured today:
- An identity layer read on every boot. Who it is, who I am, the rules it operates under, current standing decisions.
- One routing index,
MEMORY.md, at 10,079 characters with a hard cap of 15,000. It holds no facts. Only pointers: which file owns which person, project, and decision, and what triggers reading each one. - 34 files for people and projects. One file per thing that has a history.
- 5 decision records for choices that changed default behavior.
- 345 dated daily notes, raw logs written the day things happened.
- A SQLite index and semantic search over all of it, for lookup only. The index is rebuilt from the files. The files are the truth. If the index and a file disagree, the index is wrong by definition.
The layering is the first choice that actually matters. Boot reads only identity and the index. Everything else is retrieved when a task asks for it, narrowest file first. The agent does not preload my project history to answer a question about dinner. This is the same instinct as attention, honestly: don't process everything, attend to what the query needs.
But the shape is not the interesting part. Every memory tool has roughly this shape now. Folders, entities, an index. The shape was never the hard part. The rules are.
3. The write path
Every reliability property in this system comes from constraints on writing, and there are four that do most of the work.
Every fact carries a provenance tag. Each line in a people, project, or decision file is tagged [stated] (I said it directly), [observed] (the agent saw it in a tool result, file, or log), [inferred] (the agent's conclusion), or [suggested] (the agent's idea that I never committed to). This one convention kills the most dangerous failure mode in agent memory, which is the agent laundering its own proposals into my decisions. "Wes decided X" requires a turn where I actually decided X. The agent proposing X and me saying "sounds good" files the shape of what I approved, not ten separate facts I never stated.
Inferred lessons pass a recurrence gate before they become rules. A pattern the agent notices needs at least three independent signals across at least two distinct sessions before it can become standing behavior. Signals older than thirty days count half, so old one-offs decay out instead of accumulating. My explicit corrections skip the gate and take effect immediately. This asymmetry is also the prompt injection defense: a hostile input can suggest a rule once, but once is never enough, and failure lessons are stored as data ("when X broke, Y fixed it") rather than as instructions, so even a poisoned lesson cannot become a command.
Supersession is an edit, not an append. When a decision changes, the old line gets struck through with a date and the new line lands next to it with its own provenance. The current truth and the full history live in the same place, in reading order, and both come back on any retrieval of that file. There is no query-time ranking step that can get this wrong, because there is nothing to rank. The temporal graph the runtime stores in valid_from and valid_until columns, git gives me for free: log is the validity window, blame is per-line provenance, diff is the supersession edge, revert is the restore path.
Memory stores what is not re-derivable. Fetched data, generated plans, and anything git already records stays out. Current state gets verified live, never asserted from memory. A file that only contains things that cannot be recomputed stays small enough to stay honest.
4. The read path
Retrieval is a bounded evidence step, not a vibe.
Before answering anything about prior work, decisions, dates, people, or preferences, the agent must search memory. It returns a compact bundle capped at five sources by default, and each retained fact carries its file path and line, its provenance type, and its freshness. If freshness cannot be established, the claim gets labeled stale or unknown instead of being silently promoted to current. If two sources conflict, the agent states the conflict and fixes the canonical file, in that order.
Note what the semantic index does in this design: it finds the file. It does not answer the question. The answer comes from reading the canonical lines, with their tags and dates, and the runtime I tested this week shows why that matters. It stored my source URIs faithfully and then stripped them from the search output and from the context block handed to the model. Provenance that survives in storage but never reaches the agent might as well not exist. In the markdown system that failure is unrepresentable. The source tag is in the line. If you read the line, you got the source.
5. Results
Seven months is not a benchmark, it is production. Here is what the system has actually delivered.
Continuity across models. On September 1 I moved the agent to a brand new frontier model. It read its own files and said "the model changed, I didn't." Same agent since January, three models, two vendors. Identity, preferences, decisions, and working standards all survived because none of it lives in weights or in a vendor's context feature.
The break-it test, by construction. Current decision with source: it is the un-struck line with its tag. Superseded history: the struck lines above it. Provenance: on every line, and it survives all the way into the model's context because the context is the file.
Auditability. When memory is wrong, I can see exactly which line is wrong, when it was written, and what turn it came from, and fix it with an edit. Try that with an embedding.
Cost. Zero packages, zero daemons, zero migrations across seven months. The one native-code dependency in my life this week was the memory runtime's sqlite bindings failing to compile.
I wrote up the failure modes separately, because the system was not born with these rules. Five kinds of rot in seven months produced them, and that post is the honest companion to this one: Seven Months of AI Agent Memory.
6. Limitations
Papers get a limitations section, so here is mine, stated plainly.
This only works if the writer follows the policy, and the writer is an LLM. The rules exist because things rotted before the rules did. If your agent will not consistently apply editing discipline, a markdown folder degrades just like every other store, only more legibly. Legibility is the safety net: rot in a text file is visible rot.
It is single-agent, single-human. I would not run a fifty-seat team on files without real locking and merge discipline, although I notice git was also built for that exact problem.
There is a scale ceiling somewhere. At 345 daily notes and a few dozen entity files, bounded search plus an index finds things reliably and the semantic index earns its keep as a locator. At a hundred times that volume, the consolidation cadence would have to work a lot harder. I have not hit that ceiling, so I will not claim it does not exist.
And this is n=1. Seven months, one agent, one operator who cares. That is weaker evidence than a benchmark suite and stronger evidence than a benchmark suite that the vendor scored themselves, which is what the memory tools ship.
7. Conclusion
The memory tool pitch is that reliability is a product you can install. What I keep finding, tool after tool, is that they ship the part that was already easy, storage and search, and skip the part that decides whether memory compounds or rots: what you are allowed to write, when you are allowed to trust it, and what happens to it as it ages.
Those are rules, not infrastructure. They fit in a few hundred lines of markdown that the agent reads every session, and they run on any model, any harness, any decade.
You need a place to write that humans and agents can both read. You need rules for writing so the store stays true. You need rules for reading so the agent trusts evidence, not ranking. Attention was all you needed because the recurrence machinery turned out to be unnecessary. Markdown is all you need because the database turned out to be unnecessary.
The folder is the product. The discipline is the moat.
Want this for your own agent? The whole system is open source on GitHub: the operating policy, the file templates, and one copy-paste prompt that builds it on any agent that can read and write files. Paste the prompt, and your agent installs its own memory.
