# No .md files until Series B
**作者**: Vasilije
**日期**: 2026-05-20T18:55:15.000Z
**来源**: [https://x.com/tricalt/status/2057173322924806651](https://x.com/tricalt/status/2057173322924806651)
---

A few weeks ago I was talking with a founder of an SF startup building vertical agents. They had one customer in production, and the agent's memory for that single customer was already 1,000+ markdown files. Cracked engineers, shipping fast, but they hadn't really thought about how to scale the architecture as the company grew. No blame; we have all been there. You write hacky code to hit PMF, then you rewrite it properly.
Long story short, after a couple more customers the workarounds started piling up. A YAML schema for permissions. A script to enforce it at retrieval. A merge resolver for when two agents wrote to the same file. A Postgres table for traces. A graph of cross-references between files, maintained by hand. Each one made sense on its own, and together they had quietly become the system slowing down every change to the actual product.
So they redesigned the whole memory layer, this time to build a moat around their workflows.
I have seen plenty of founders end up on this same path.
If you are building agents you expect to run in production, across teams, across time, you will hit it too. And if you are already there, you have probably started patching around it without realizing what you are rebuilding.
I have had this conversation enough times to know how it goes. Here are the five questions I get most often, and the answers I usually hear back.
Q1. How do you do permissions with memory.md?
A1: One .md file per topic, each with filesystem ACLs.
Permissions in real systems aren't per-topic. They're per-entity and per-attribute. User A can see customer X's contact info but not their contract terms. You'd need a file per (entity, sensitivity-level) pair. That combinatorially explodes.
A2: Encode permissions as frontmatter metadata, filter at retrieval.
Now your retrieval layer parses, respects, and enforces ACLs before the LLM sees content. That's an access-control system embedded in a file store. Get it wrong once and you have leaked data into an LLM context window. And even worse, "sleep" refinement merges content across files. Now your refiner needs to understand permissions too, or it cross-contaminates sensitive content into shared summaries.
A3: Separate memory store per permission boundary.
You have lost the cross-cutting reasoning that made memory valuable. The agent can't answer "across everything I'm allowed to see, what patterns emerge?" because you have physically partitioned the knowledge.
Q2. How do multiple agents interact with memory.md?
A1: File locking: only one agent writes at a time.
You have serialized your entire memory layer. Latency scales with agent count. And locks don't solve semantic conflicts: when two agents write about the same customer, you don't get a merge. You get the last write winning, or two contradictory paragraphs sitting next to each other.
A2: Append-only logs per agent, with a periodic merge job (basically claude’s “dreams”at scale).
Merge is now fully non-deterministic. And even if you trust the LLM to merge correctly, how do you version it? Which merge produced which memory? What did it overwrite?
A3: One shared md, let the LLM resolve conflicts at read time.
If the LLM resolves conflicts at read time, you don't have a memory. You have a log and an LLM guessing what to believe. Every query pays the cost of re-deriving the truth from scratch, and every query can derive it differently.
Q3. How do you handle temporal queries?
A1: Timestamp every entry.
A timestamp tells you when a note was written, and not when the fact was true in the world. A customer telling you in March about an October renewal, and in June pushing it to December, gives you two notes with two written-at timestamps and no way to know which renewal date was current on any given day.
A2: Use Auto Dream to maintain a "current state" section and an "archive" section.
You have built a snapshot system that quietly corrupts itself. Every merge pass, the LLM has to guess which old note each new note replaces, with nothing telling it that "customer's renewal" and "their renewal date" are the same thing. It will guess wrong. You won't know when. And the archive is too unstructured to go back and check what you used to believe.
A3: Include all dates in the .md and let the LLM reason temporally.
You have turned a storage problem into an inference problem. Every time-based question now costs a model call, returns a different answer each run, and has no ground truth to test against.
Q4. How do you include traces in your memory so they can be used to self-improve your agents later?
A1: Append a "lessons learned" section after each session.
Lessons accumulate, and md has no notion of which ones are still valid. After a hundred sessions you have a hundred lessons. Some might be contradicting each other, or some might have code paths that you have deleted.They all sit at the same retrieval priority, and the agent has no signal for which to weigh. You have built a write-only log and called it learning.
A2: Use Auto Dream to distill traces into rules.
Distillation is one-directional. Once a rule is written, you can't query "which traces produced this rule, and what were the outcomes when it got executed?". The traces that would answer that have been compressed away. You have made inference cheaper and evaluation impossible.
A3: Keep raw traces in a separate store and the distilled rules in md.
You now have two memory systems with no link between them. The rule in md can't point back to the traces that produced it. The traces can't be queried for "which produced rules that are still active." You're back to needing a relational or graph model.
Q5.. How are you going to find the right information across thousands of md files?
A1: Chunk and embed, retrieve top-k.
You have built a vector store on top of a file store, and retrieval ignores the file structure entirely. Chunks lose entity context too; a paragraph about "their pricing" comes back without telling you whose. Top-k optimizes for semantic similarity, not for the entity the query is actually about.
A2: Add metadata filtering (tags for entity, topic, date)
Now you are maintaining a schema md doesn't enforce. Tags drift, taxonomies fight reality, one mis-tagged file silently degrades retrieval forever. You have built a database without the constraints that make databases trustworthy.
A3: Build a graph-based navigation system across thousands of md files.
At this point you are building a graph database where the storage layer happens to be markdown files. You will need an index (md isn't queryable), a way to keep that index in sync as files change (md doesn't emit events), typed edges (links in md are just strings), and a query engine on top. Every one of those is something graph databases and memory layer providers already solve. You have reinvented the system and made the storage layer worse on purpose.
Using .md files for memory is not wrong or bad, do not take me wrong. It is just a key-value store with LLM-driven compaction, and for one user, one agent, one timeline, that is probably fine. But the moment your system grows along any of those axes, you need something else.
And, trust me, we have only scratched the surface above. What about provenance? How do you separate short-term from long-term memory without losing the link between them? What happens when the shape of what you remember changes six months in? How do you actually delete something, when Dream has already absorbed and rephrased it into a dozen summaries? How do you do multi-hop reasoning over notes that don't know they are connected? Each one is its own a post :)
These are all the questions we had in mind when designing cognee.
Check us out here:
https://github.com/topoteretes/cognee ⭐
https://www.cognee.ai/
Join us on Discord for support and discussion:
## 相关链接
- [Vasilije](https://x.com/tricalt)
- [@tricalt](https://x.com/tricalt)
- [22K](https://x.com/tricalt/status/2057173322924806651/analytics)
- [cognee](https://www.cognee.ai/)
- [https://github.com/topoteretes/cognee](https://github.com/topoteretes/cognee)
- [https://www.cognee.ai/](https://www.cognee.ai/)
- [Join us on Discord](https://discord.gg/cqF6RhDYWz)
- [Upgrade to Premium](https://x.com/i/premium_sign_up)
- [2:55 AM · May 21, 2026](https://x.com/tricalt/status/2057173322924806651)
- [22.5K Views](https://x.com/tricalt/status/2057173322924806651/analytics)
- [View quotes](https://x.com/tricalt/status/2057173322924806651/quotes)
---
*导出时间: 2026/5/21 10:26:39*
---
## 中文翻译
# B 轮融资前别再用 .md 文件了
**作者**: Vasilije
**日期**: 2026-05-20T18:55:15.000Z
**来源**: [https://x.com/tricalt/status/2057173322924806651](https://x.com/tricalt/status/2057173322924806651)
---

几周前,我与一位旧金山初创公司的创始人交谈,他们正在构建垂直领域的 Agent。他们有一个客户在生产环境中运行,而仅这一个客户的 Agent 记忆就已经产生了 1000 多个 markdown 文件。他们有顶级工程师,发货速度很快,但并没有真正思考过随着公司增长如何扩展架构。这无可厚非;我们都有过这种经历。你为了达到产品市场匹配(PMF)而编写拼凑的代码,然后再正确地重写它。
长话短说,在又多了几个客户之后,变通方案开始堆积。用于权限的 YAML 模式、在检索时强制执行它的脚本、当两个 Agent 写入同一文件时的合并解析器、用于追踪的 Postgres 表、手动维护的文件间交叉引用图。每一个单独看来都很有道理,但它们在不知不觉中共同成为了减缓实际产品每次迭代的系统。
所以他们重新设计了整个记忆层,这次是为了围绕他们的工作流程建立护城河。
我见过很多创始人最终都走上了同样的道路。
如果你正在构建预计在生产环境中长期跨团队运行的 Agent,你也会遇到这个问题。如果你已经身处其中,你可能已经开始打补丁修补它,而并没有意识到你正在重建什么。
我已经进行过足够多次这样的对话,知道事情是如何发展的。以下是我最常听到的五个问题,以及我通常听到的回答。
**Q1. 你如何使用 memory.md 来处理权限?**
A1:每个主题一个 .md 文件,每个文件都有文件系统 ACL。
真实系统中的权限不是按主题划分的。它们是按实体和按属性划分的。用户 A 可以查看客户 X 的联系信息,但不能查看其合同条款。你需要为每个(实体,敏感度级别)配对创建一个文件。这会导致组合爆炸。
A2:将权限编码为前置元数据,在检索时进行过滤。
现在你的检索层必须在 LLM 看到内容之前解析、遵守和执行 ACL。这是一个嵌入在文件存储中的访问控制系统。只要弄错一次,你就会将数据泄露到 LLM 上下文窗口中。更糟糕的是,“休眠”精炼会合并跨文件的内容。现在你的精炼器也需要理解权限,否则它会将敏感内容交叉污染到共享摘要中。
A3:每个权限边界分别建立记忆存储。
你已经失去了让记忆变得有价值的交叉推理能力。Agent 无法回答“在我被允许查看的所有内容中,出现了哪些模式?”,因为你已经在物理上分割了知识。
**Q2. 多个 Agent 如何与 memory.md 交互?**
A1:文件锁定:一次只有一个 Agent 写入。
你已经将整个记忆层串行化了。延迟随 Agent 数量扩展。而且锁无法解决语义冲突:当两个 Agent 写入同一个客户时,你得不到合并。你会得到“最后写入胜出”,或者是两个矛盾的段落并排存在。
A2:每个 Agent 仅追加日志,并带有定期合并作业(基本上就是大规模的 Claude “梦境”)。
合并现在完全是不确定的。即使你信任 LLM 能正确合并,你该如何版本控制?哪次合并产生了哪段记忆?它覆盖了什么?
A3:一个共享的 md,让 LLM 在读取时解决冲突。
如果 LLM 在读取时解决冲突,你就没有记忆。你只有一个日志和一个 LLM 在猜测该相信什么。每次查询都要从头重新推导真相的成本,而且每次查询推导的结果可能都不一样。
**Q3. 你如何处理时间查询?**
A1:给每个条目加上时间戳。
时间戳告诉你笔记是什么时候写的,而不是事实在世界上是什么时候为真的。一个客户在 3 月告诉你 10 月续约,而在 6 月将其推迟到 12 月,这给了你两个带有“写入时间”时间戳的笔记,无法知道在任何给定哪一天哪个续约日期是当前的。
A2:使用 Auto Dream 维护一个“当前状态”部分和一个“存档”部分。
你构建了一个会悄无声息地自我损坏的快照系统。每次合并 pass,LLM 都必须猜测哪条旧笔记被哪条新笔记取代,而没有任何东西告诉它“客户的续约”和“他们的续约日期”是一回事。它会猜错。你不会知道是什么时候猜错的。而且存档太无结构了,无法回溯检查你以前相信的是什么。
A3:在 .md 中包含所有日期,让 LLM 进行时间推理。
你把一个存储问题变成了一个推理问题。现在每个基于时间的问题都要消耗一次模型调用,每次运行返回不同的答案,并且没有基本事实可以用来测试。
**Q4. 你如何将 traces 包含在你的记忆中,以便以后用来改进你的 Agent?**
A1:每次会话后附加一个“经验教训”部分。
经验会积累,而 md 没有概念哪些仍然有效。在一百次会话后,你有一百条经验。有些可能相互矛盾,或者有些可能包含你已经删除的代码路径。它们都处于相同的检索优先级,Agent 没有信号该重视哪一个。你构建了一个只写日志并称之为学习。
A2:使用 Auto Dream 将 traces 蒸馏成规则。
蒸馏是单向的。一旦写入规则,你就无法查询“是哪些 traces 产生了这条规则,以及执行它时的结果如何?”。能够回答那个问题的 traces 已经被压缩掉了。你让推理变便宜了,却让评估变得不可能。
A3:将原始 traces 保存在单独的存储中,将蒸馏规则保存在 md 中。
你现在有两个记忆系统,它们之间没有联系。md 中的规则无法指回产生它的 traces。无法查询 traces 来看“哪些产生的规则仍然是活跃的”。你又回到了需要关系或图模型的地步。
**Q5. 你将如何在数千个 md 文件中找到正确的信息?**
A1:分块和嵌入,检索 top-k。
你在文件存储之上构建了一个向量存储,而检索完全忽略了文件结构。分块也会丢失实体上下文;关于“他们的定价”的段落返回时没有告诉你这是谁的。Top-k 优化的是语义相似度,而不是查询实际关于的实体。
A2:添加元数据过滤(实体、主题、日期的标签)
现在你要维护一个 md 不强制执行的 schema。标签会漂移,分类法与现实冲突,一个错误标记的文件会永远悄无声息地降低检索质量。你构建了一个没有约束的数据库,而约束正是数据库值得信任的原因。
A3:在数千个 md 文件之上构建一个基于图形的导航系统。
在这一点上,你正在构建一个图数据库,只是其存储层恰好是 markdown 文件。你需要一个索引(md 不可查询)、一种在文件更改时保持索引同步的方法(md 不发出事件)、类型化边(md 中的链接只是字符串),以及顶部的查询引擎。这其中的每一个都是图数据库和记忆层提供商已经解决的问题。你重新发明了这个系统,并故意让存储层变得更糟。
使用 .md 文件作为记忆并没有错或不好,别误会我。它只是一个由 LLM 驱动的压缩键值存储,对于一个用户、一个 Agent、一条时间线,这可能没问题。但是一旦你的系统沿着其中任何一个轴增长,你就需要别的东西。
而且,相信我,我们上面只是触及了皮毛。数据溯源呢?如何在不丢失它们之间联系的情况下将短期记忆与长期记忆分开?当你所记住的内容的形状在六个月后发生变化时会发生什么?你如何真正删除某些东西,当 Dream 已经吸收并将其重写为十几个摘要?你如何对不知道它们彼此相连的笔记进行多跳推理?每一个都可以单独写一篇文章 :)
这些就是我们在设计 cognee 时考虑的所有问题。
在这里查看我们:
https://github.com/topoteretes/cognee ⭐
https://www.cognee.ai/
加入我们的 Discord 获取支持和讨论:
## 相关链接
- [Vasilije](https://x.com/tricalt)
- [@tricalt](https://x.com/tricalt)
- [22K](https://x.com/tricalt/status/2057173322924806651/analytics)
- [cognee](https://www.cognee.ai/)
- [https://github.com/topoteretes/cognee](https://github.com/topoteretes/cognee)
- [https://www.cognee.ai/](https://www.cognee.ai/)
- [Join us on Discord](https://discord.gg/cqF6RhDYWz)
- [Upgrade to Premium](https://x.com/i/premium_sign_up)
- [2:55 AM · May 21, 2026](https://x.com/tricalt/status/2057173322924806651)
- [22.5K Views](https://x.com/tricalt/status/2057173322924806651/analytics)
- [View quotes](https://x.com/tricalt/status/2057173322924806651/quotes)
---
*导出时间: 2026/5/21 10:26:39*