为什么仓库必须成为 Agent 的唯一事实源

不在仓库里的信息对 Agent 等于不存在,知识必须沉淀为文件而非散在工具里。

Module C · 第 2 讲

立靶:把项目知识散在 Slack 会怎样

设想这样一个团队:架构决策记在 Slack 某个频道,需求散在工单系统的几十张卡片里,部署踩过的坑写在某篇协作文档的评论区,谁负责哪块靠群里口头对齐。人类成员靠「我记得在哪条消息里看过」勉强运转。

现在让一个 Agent 接手同样的任务。它的表现会突然变得很差:明明上周群里讨论过的约定它完全不知道;它会重复犯三天前有人在工单评论里记下的坑;它对「现在做到哪了」的判断完全错误,因为它读不到那些散落的上下文。

根因只有一句话:不在仓库里的信息,对 Agent 来说等于不存在。

人类有一套隐性的信息检索网络——记忆、人脉、「问一下那个谁」。Agent 没有。它的信息输入只有三个确定的来源,除此之外的一切都是盲区。这一讲要讲清楚:为什么仓库必须成为 Agent 唯一的事实源,以及如何用工程手段把这件事落到实处。

框架:Agent 只有三个信息来源

walkinglabs 的 Harness Engineering 框架把 Agent 的全部信息输入收敛为三个、且只有三个来源:

信息来源内容谁来维护特点
系统提示(System Prompt)角色、纪律、全局约束Harness 设计者每次会话固定注入,容量有限
仓库文件(Repo Files)代码、文档、状态、决策、进度团队 + Agent可无限扩展,可版本化,是主战场
工具输出(Tool Output)命令执行结果、读取的文件内容运行时产生临时性,会话结束即蒸发

关键推论:系统提示容量有限、工具输出会蒸发,因此一切需要长期存在的知识,都必须落进仓库文件。 Slack、协作文档、工单系统里的内容,无论对人类多重要,对 Agent 都处在三个来源之外,等于不存在。

围绕这个事实,框架给出四条把知识沉淀进仓库的原则:

原则含义反面(违反后果)
知识靠近代码决策、约定写在它影响的代码旁边知识与代码漂移,Agent 改完代码不知道破坏了哪条约定
标准化入口有一个固定的着陆页(AGENTS.md / 本项目的 STATUS.md),新会话第一个读它Agent 不知道从哪开始,每次都要重新摸索
最小但完备只写必要信息,但必要信息一条不缺信息过载淹没要点,或缺一环导致判断错误
与代码同步知识随代码一起更新、一起提交文档说一套、代码做一套,Agent 被误导

配套的状态管理用 ACID 四性约束(借数据库事务的隐喻):

性质在 Agent 仓库里的含义
原子性 Atomicity一个完整动作对应一次 commit,要么全成要么不留半成品
一致性 Consistency有可执行的验证谓词(verify),状态变更前后仓库始终处于合法态
隔离性 Isolation并发会话/分支隔离,避免互相覆盖产生竞争
持久性 Durability状态用 git 持久化,不依赖任何单次会话的内存

验证这套体系是否到位,有一个极简判据——全新会话测试:开一个全新的 Agent 会话,不给任何口头补充,只让它读仓库文件,看它能否回答「这是什么项目、现在做到哪、下一步该做什么、有哪些坑不能踩」。答得上来,说明事实源在仓库里;答不上来,说明知识还散在仓库之外。

case:把抽象原则落进一套真实文件

下面用本课程站点项目自身的工程实践,把上面每条原则对应到一个真实文件。这个项目本身就是用这套方法论搭建的,可以当作活样本。

标准化入口 = STATUS.md,每次 session 第一个读的文件。 文件开头第一行就写明它的契约:「每次 session 第一个读的文件。收尾必更新本文件。」它包含三块刚好够用的信息:一句话状态(今天做完了什么、剩什么)、下次入口(具体到「先读本文件,再读 PROGRESS,跑哪个 init 脚本,当前应做哪个切片」)、踩坑清单。一个全新会话读完这一个文件,就知道自己站在哪、该往哪走。

项目的 CLAUDE.md 把入会顺序写成了硬规矩:先读 STATUS.md,再读需求/方案/架构/切片三件套,开工前跑 init 脚本确认环境。这等于把「全新会话测试」制度化了:每个会话都被强制当成全新会话对待,不允许依赖上一轮的记忆。

单一事实源 = features.json。 「现在有哪些任务、各自什么状态、谁阻塞谁」这类信息最容易散落和漂移。项目把它收敛进结构化文件 features.json:每个 feature 有确定的状态机 pending → in_progress → failing → passing,并写死一条铁律——

verify 真跑通才能改 passing;草稿写完只到 in_progress。

这就是 ACID 里「一致性」的落地:状态不是 Agent 拍脑袋说改就改,而是必须由一个可执行的验证谓词通过才允许跃迁。features.json 还为每个 feature 填了三段式关联 related / affected / out_of_scope,明确写出「这件事牵动哪些文件、影响什么、明确不做什么」——这是「知识靠近代码」的延伸,让任何会话(尤其隔离出去的子 agent)能在不通读全仓库的情况下秒判哪些该读、哪些不读。

进度持久化 = M1/PROGRESS.md,把进度从 LLM 记忆迁到确定性文件。 「做到哪了」最危险的存法就是存在 Agent 的对话记忆里——会话一结束就蒸发,正对应工具输出不具备的「持久性」。项目把进度写进 PROGRESS.md:顶部一张表标明当前活跃 feature 和切片,中间是倒序的 Session Log,底部还有「如果…就…」的决策预案。文件末尾那个「增量流水(待整理)」区由一个自动化钩子在每轮追加,并约定下次启动先合并再清空——连「还没来得及整理的进度」都不放过。

可操作做法

  1. 建一个标准化着陆页(AGENTS.md 或 STATUS.md),放仓库根。第一行写明契约(「每次会话第一个读 / 收尾必更新」)。内容只放三样:一句话现状、下次入口、踩坑清单。
  2. 把入会顺序写进 CLAUDE.md:强制每个会话先读着陆页,再读需求方案文档。让「全新会话测试」成为默认流程。
  3. 任务状态收进一个结构化单一事实源,给每个任务配可执行的 verify。立铁律:verify 没跑通,状态不许标完成;verify 为空不准开工。
  4. 进度写进确定性文件,不留在记忆里。每个会话收尾追加日志:做了什么、坑在哪、核查结论。能用钩子自动追加更好。
  5. 知识靠近代码、与代码同步:决策写在它影响的代码旁边,随代码一起提交。每次 commit 保持原子。
  6. 定期做全新会话测试:开一个干净会话只喂文件,问它项目现状和下一步。答不上来的地方就是漏洞,补进文件。
  7. 把吃 context 的脏活隔离出去:让子 agent 在独立上下文读散落材料、只回结论,主线始终基于仓库里的确定性文件工作。

收口

Agent 不会「问一下那个谁」,也不会「翻翻上周的群消息」。它的世界只有系统提示、仓库文件和工具输出这三样,其中只有仓库文件能长期承载知识。

凡是希望 Agent 长期知道的事,就必须写进仓库;写不进仓库的知识,迟早会变成 Agent 看不见的坑。