When a fact changes between sessions, a vector store hands back the stale version. A file overwrites one address — and reads the current truth.
Lecture → code · Run it · Why vector goes stale
Session 1: "we deploy to Heroku." Session 2: "actually, we moved to Fly.io." Then you ask, next week, "where do we deploy in production?"
A vector memory is append-only + retrieval-by-similarity: it stored both notes, they have near-identical embeddings, and the wordy session-1 note shares more of the query's tokens — so it hands back Heroku, a fact that was already overwritten. It has no notion of supersedes; to a similarity search, yesterday's fact and last month's fact look equally relevant.
File memory is addressed by identity, not similarity: one fact lives at one
slug. The update overwrote that file in place, so the stale value is physically
gone from the live field — and recall("deploy-target") reads Fly.io, plus a
file:line provenance pointer you can open.
No vector DB. No embeddings service. No keys. No network. Pure Python stdlib.
Built to distill one talk:
Paul Iusztin (Decoding AI) & Louis-François Bouchard (Towards AI) — "Turn 10,994 Notes Into Memory", AI Engineer
"forget the infrastructure you think you need — vector databases, knowledge graphs, semantic search. I want a system just based on files." — 19:37
Full timestamped map + every borrowed idea in LECTURE.md.
git clone https://github.com/Archive228/file-memory-vs-vector
cd file-memory-vs-vector
./run.sh # the demo (writes memory_store/ then queries it)
./run.sh --test # 11 testsThe trap is a contract, not a lucky seed. src/embed.py is a bag-of-words
cosine. Session 1's episodic note ("we deploy the app to Heroku for production…")
shares the query's heavy tokens (deploy, app, production) several times over;
session 2's terse correction shares only deploy. So the retriever ranks the old
note first and extracts the overwritten value. Both notes coexist forever —
append-only stores don't delete. You can read the math in src/embed.py and the
frozen outcome in tests/test_demo.py.
File memory wins for a structural reason a vector store can't fix: one fact, one
address. update_note rewrites memory_store/semantic/deploy-target.md in
place — the stale value survives only in the changelog body, never in the field a
lookup reads. And you can open the file and see (or fix) exactly what the agent
knows.
query ──┬──► vector.retrieve(all episodes) ──► most-similar chunk ──► stale value
└──► memory.recall(slug) ──► open one file ──► current value + file:line
| file | what it is |
|---|---|
src/memory.py |
file memory: markdown + YAML frontmatter, write_note / update_note (overwrite in place) / recall / provenance |
src/vector.py |
the baseline: ingest every episodic log, rank by cosine — no update semantics |
src/embed.py |
local stdlib bag-of-words embedding + cosine (reused from the sibling repo) |
src/corpus.py |
the hand-authored trap: the query, the fact, its two sessions |
src/demo.py |
runs the two sessions, then the side-by-side query |
- File memory needs an update to have a canonical address. The win is on facts that change or get corrected; for pure append-and-retrieve of unstructured text, vector search is fine (and easier).
- The embedding is a bag-of-words, not a trained model. A better embedding improves paraphrase matching — but not the temporal problem: an append-only store still can't tell a superseded fact from a current one.
- Real systems keep both. The talk's own point is that Markdown is the source of truth and any index (SQLite / vector) is a rebuildable accelerator, not the memory itself.
Own code throughout; ideas borrowed and credited:
- Video: Paul Iusztin & Louis-François Bouchard, Turn 10,994 Notes Into Memory — memory as plain files, "forget the infra you think you need."
- Rewritable truth + append-only changelog (a fact can't change without a trace): mindmuxai/brain.md (Apache-2.0).
- Conformance in code, not prompts; append-only log: thecodacus/understory (Apache-2.0).
- Folder-by-memory-type + closeout ritual: mcncarl/agent-memory-vault (MIT).
- Zero-dep, zero-keys, deterministic markdown memory: seojoonkim/memkraft (MIT).
embed.py+ zero-dep offline contract: sibling repos graph-vs-vector-provenance / verifier-gate (MIT).
MIT — see LICENSE. All code here is original; nothing is vendored.
Built from a real lecture, mapped to it in LECTURE.md — not a rehash of a rehash.
If it made the idea click, ⭐ it.