Volume 3 · Chapter 35

AI 协同:仓库如何与 agent 一起写代码

前 34 章读的都是「dsh 是什么」。这一章换个方向:这个仓库本身是怎么被写出来的。它的 6600+ 文件里有一套完整的 agent 协同基建——分层指令、1182 篇决策记录、14 个可复用工作流、55 个把文档规则变成编译错误的校验门。这套东西不是产品能力,但它解释了为什么一个 agent 深度参与的项目还能保持结构。

(前情) 23 页:skill 运行时是怎么加载的(产品能力) → 本章:仓库自己怎么用这套机制(工程实践) → (闭环) AGENTS.md → 模型上下文 → 改代码 → 校验门 → Agent Note

示例本次示例:一次典型的 agent 改动

示例轨迹 35-1 · 从「改一行代码」到「合入」的完整链路
# ① agent 会话开始
#   agent-instructions 插件向上找 .git 定项目根 → 收集 AGENTS.md 链
#   → 作为 user/message 注入 inbox(08 页 preStep 的第一步)
#   根 AGENTS.md 175 行 = 「每次会话都要在上下文里的常备命令」
#
# ② agent 读代码 → 改 packages/core/agent-loop/src/agent.ts
#   packages/AGENTS.md(28 行)补充该子树的额外规则
#
# ③ 判定「这次改动是不是 non-trivial」
#   → 是 → 必须同时写一篇 Agent Note(.agents/notes/README.md 的硬规则)
#
# ④ 提交前:dsh-pre-push-checks skill 选最小的检查集
#   → 不跑全量测试(CI 负责穷尽性)
#
# ⑤ 推送 → CI 跑 55 个 verify-* 门
#   → verify-agent-note-format 检查笔记的段落骨架
#   → verify-doc-budgets 检查文档有没有超字数
#   → verify-md-links 检查相对链接
#
# ⑥ 合入。决策留在 .agents/notes/implemented/ 里,供后来者查「为什么」
来源:本章 §1-§5;文件路径与行号均来自仓库真实文件
示例轨迹 35-2 · 这套基建的规模(真实统计)
# AGENTS.md 层级文件:22 个(根 + 各子树)
# Agent Notes:1182 篇英文正本
#   implemented/  487   proposed/ 39   rejected/ 14   archived/ 640
#   按月份:2026-06 = 68,2026-07 = 385,2026-08 = 372,2026-09 = 159
# 可复用 skill:14 个(.agents/skills/*/SKILL.md)
# 校验脚本:257 个(scripts/*.ts),其中 verify-* 门 55 个
# 文档门聚合(doc-sync):约 35 个 leaf gate
#
# 换算:平均每天新增 ~10 篇决策记录。
来源:本章 §2-§4 的实测统计(find / ls / grep 得到)

§1分层指令:AGENTS.md 与它的符号链接

仓库的 agent 指令放在 AGENTS.md,按目录分层,共 22 个。切分依据写在根文件自己的规则里:

The launcher parses only what it owns… Root AGENTS.md = Standing orders: rules an agent needs in context in every session, one to three lines each, linking its home.
层级文件行数职责
根AGENTS.md175常备命令:仓库布局、命令、约定、防御模式。每条规则 1-3 行 + 一个指向「家」的链接
包树packages/AGENTS.md28该子树专属:插件导出形态、可选服务、REAL-composition 测试要求、Service Definition 设计规则
文档树docs/AGENTS.md76文档标准:分层分类法、写作规则、字数预算、slop 清单
笔记树.agents/notes/AGENTS.md7新笔记触发 supersession 检查
其余.github/ vendor/ scripts/ snapshots/ benchmarks/ website/3-19各自子树的补充规则

核心设计:一个事实只有一个家。docs/AGENTS.md 的分层表把这条规则写成了表格——每个 tier 明确「该放什么」和 「不该放什么」。根 AGENTS.md 不放故事、不放示例、不放情景化流程;这些都属于「→ 链接到它的家」。一个字面意义上的 single source of truth。

CLAUDE.md 是符号链接

如果你用 Claude Code 打开这个仓库,它会读 CLAUDE.md——但那个文件只有 9 个字节,内容是 AGENTS.md。git 视角下它是一个符号链接(mode 120000):

$ git ls-files -s CLAUDE.md packages/CLAUDE.md
120000 47dc3e3d86... 0	CLAUDE.md
120000 47dc3e3d86... 0	packages/CLAUDE.md

$ cat CLAUDE.md
AGENTS.md

根 AGENTS.md 的第 171 行把这条规则写明了:「CLAUDE.md symlinks AGENTS.md at root and packages/; edit the real file.」——不要编辑符号链接,编辑真身。这样同一份指令同时服务 Claude Code(读 CLAUDE.md)和其他遵循 AGENTS.md 约定的 agent,不存在两份需要同步的副本。这是「一个事实一个家」在工具兼容层面的应用。

§2Agent Notes:决策记录体系

这是整个协同基建里最有分量的一块。1182 篇英文正本(另有等量的 .zh.md 中文对照与 sidecar),放在 .agents/notes/。

两条轴:生命周期 × 类别

规则文件 .agents/notes/README.md 把它们编码进路径:{lifecycle}/{class}/yyyy-mm-dd-topic-title.md。

生命周期含义篇数
proposed/已评审但尚未实现(或只实现了一部分)的提案39
implemented/决策已落地。必须与代码保持同步——代码移动文件、改名、改变默认值时,笔记在同一次变更里更新事实487
rejected/考虑过并否决。只在其理由能阻止一个诱人的错误时保留14
archived/冻结的历史快照。永不编辑,也永远不作为当前行为的权威640

类别是闭集,定义在 scripts/agent-note-tree.ts:

scripts/agent-note-tree.ts闭集定义11-19
11/** The closed set of active Agent Note lifecycles (top-level folders under .agents/notes/). */
12const AGENT_NOTE_LIFECYCLES = ['proposed', 'implemented', 'rejected'] as const
14/**
15 * The closed set of Agent Note classes (nested folder under each lifecycle). Adding a
16 * class is a deliberate act: extend this list AND the README's Classification
17 * section. The gate rejects any folder not listed here.
18 */
19export const AGENT_NOTE_CLASSES = ['feature', 'bug-fix', 'simplification', 'architecture', 'process', 'testing'] as const六类,加一类需同时改 README
19

「加一类是一个刻意的动作」:注释明确要求同时改这个常量和 README 的分类章节。architecture 与 process 的分界被特别说明——前者关于「我们发布的源码」,后者关于「围绕代码的工具与流程」。refactor 被刻意排除:它与 simplification 重叠,而后者的判据「可观测行为变了吗」已经覆盖了它。

段落骨架是强制的

每篇笔记的骨架由 scripts/verify-agent-note-format.ts(94 行)强制执行。这份门本身就是「把文档规则变成编译错误」的典范:

scripts/verify-agent-note-format.ts格式门12-36
12/** The date these format rules took effect; the grandfather comment is valid only before it. */
13const FORMAT_ADOPTED = '2026-07-05'
15/** The exact comment a pre-format Agent Note carries in place of `## Alternatives considered`. */
16const GRANDFATHER = '<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) -->'
18/** The retired debt marker that flagged pre-format bodies; banned so it cannot creep back. */
19const LEGACY_MARKERS = ['XXX: legacy ADR/RFC body format', ...]
21/** Status-line grammar per lifecycle folder. */
22const STATUS: Record<string, RegExp> = {
23  proposed: /^Status: proposed$/,
24  implemented: /^Status: implemented$/,
25  rejected: /^Status: rejected — .+$/,   // 唯一带内容的状态
26}
28/** Required `##` headings per lifecycle, beyond the universal `## Problem` opener. */
29const REQUIRED: Record<string, string[]> = {
30  proposed: ['## Proposal', '## Acceptance criteria', '## Risks'],
31  implemented: ['## Decision', '## Consequences'],
32  rejected: ['## Proposal'],
33}
35/** Headings banned in `implemented/` — proposal-era spec-speak per the slop checklist. */
36const BANNED_IMPLEMENTED = /^## (?:Proposal\b|Plan\b|Migration plan\b|Acceptance criteria\b)/i实现后不许再用「计划」语气
13

FORMAT_ADOPTED = '2026-07-05':格式规则生效日。此前的笔记可以携带「豁免注释」,此后的不行(第 82 行断言)。规则变更自带时间边界,老笔记不用回填。

22-26

状态行语法按生命周期分别定义。rejected 是唯一要求带内容的(rejected — <一句话原因>)——因为「为什么否决」正是读者来看的东西。

29-33

骨架随生命周期不同:提案有 ## Proposal/## Acceptance criteria/## Risks(未来时态合理);已实现是 ## Decision/## Consequences(现在时描述已发布的事实)。

36

禁止清单:implemented/ 里不许出现 ## Proposal、## Plan、## Migration plan、## Acceptance criteria——这些是「规格语言」,决策落地后它们就过时了。门会强制你把内容折进 Decision/Consequences。

Alternatives considered 是必填的

README 里的原话:「A decision recorded without what it beat invites re-litigation — the failure Agent Notes exist to prevent.」

每一篇笔记都必须有 ## Alternatives considered 段。格式门第 78-82 行检查它是否存在——唯一豁免是 2026-07-05 之前的老笔记,且必须携带一个精确的注释字符串(不是随便写一句「理由见别处」)。替代方案只记录,不许发明。

归档是单向的

archived/ 树(640 篇)被永久冻结:不许编辑、翻译、重排版、更新、移动或删除。scripts/verify-archived-agent-notes.ts 强制一套追加式的内容清单(append-only frozen-content manifest)——归档时的哈希被记录下来,之后任何改动都会被发现。

归档本身有明确判据(README 的 Archiving 章节):当已发布的决策已经完成、且其理由不太可能指导未来工作时。反面清单同样明确——如果「替代方案、所有权边界、否定性保证、持久或线上语义、安全规则、重新引入的条件」中任何一项仍然有用,就保持活跃。工具是 dsh-archive-agent-notes skill,README 特意强调:不要用字数、年龄或配额来判据。

§3Skill:可复用的工作流

.agents/skills/ 下有 14 个 skill。它们不是产品文档——按 docs/AGENTS.md 的分层表,skill 这个 tier 的职责是「可复用的工作流与专门的决策标准」,明确不放产品与运行时契约(那些属于 docs 或源码)。

一个 skill 长什么样

每个 skill 是一个目录,核心是 SKILL.md,带 YAML frontmatter。以 dsh-pre-push-checks 为例(136 行):

.agents/skills/dsh-pre-push-checks/SKILL.mdfrontmatter + 正文结构1-14
1---
2name: dsh-pre-push-checks
3description: Use before pushing, force-pushing, marking ready for review, or claiming checks pass on a deepseek-harness branch, and immediately after gh stack sync publishes rewritten branches, to select the smallest tests and checks that cover the outgoing or just-published diff without reflexively running the full repository suite.「何时用」写在 description 里
4---
6# DSH Pre-Push Checks
10## Inspect the outgoing change
27## Select relevant evidence
52### Focus unit coverage on the affected source
75## Full local rehearsal
79## Protect history-rewriting pushes
96## Handle failures
107## Push procedure
2-4

frontmatter 只有两个字段(全部 14 个 skill 都是如此,只有一个例外见下)。加载器要求两者都存在,缺失就忽略该文件。

3

description 就是触发器。注意写法:不是「这个 skill 做什么」,而是「Use before pushing, force-pushing, marking ready for review, or claiming checks pass…」——从 agent 的决策时机出发描述何时该调用它。这是 skill 能被正确自动触发的关键。

10-107

正文是从「检查什么」到「怎么推」的完整流程。结构在所有 skill 里一致:先给判据,再给动作。文档门 verify-skill-invocation-metadata 检查这个元数据格式。

14 个 skill 的全貌

skill行数用途
dsh-doc131文档的创建/重构/审查/审计/迁移。带 5 个 references + 7 个 templates
dsh-find-simplifications157找非显然的简化候选、移除冗余、合并被取代的 Agent Note
dsh-pre-push-checks136推送前选最小的检查集,不反射性地跑全量测试
dsh-ci-test-reliability131设计/诊断在 CI 上会不确定失败的测试。带 references/
dsh-merging-stacked-prs127把依赖栈(A ← B ← C)落到 master
dsh-speed-up-perf92性能调查:先建逼真基准,再证明回归,最后删工作
dsh-prose-standard81编辑判断标准。明确自称「guidance, not a script」。带 references/examples.md(169 行)
dsh-translate-docs74双语文档工作流。只能手动触发(见下)
dsh-archive-agent-notes68Agent Note 的归档与 supersession 检查(§2 用到)
dsh-code-review52审查 PR,让审查者熟悉这个代码库特有的标准
dsh-trim-cot-leakage45猎捕「泄漏的推理记录」。带 2 个 references(275 + 52 行)
agent-experience130.1.7 新增:设计 agent 工具、skill、上下文加载与多步工作流时,让信息可被发现、让上下文用得省
dsh-client-ui-ux620.1.7 新增:客户端 UI 改动的设计与审查——视觉 token 纪律、先复用再加新、反馈面(toast vs 就地提示)的选择
record-browser-gif172把 Web UI 交互录成 GIF。带可执行脚本 scripts/encode_gif.py(337 行)+ 测试

形态差异值得注意:多数 skill 是纯 Markdown 流程,但 dsh-doc 配了模板库、record-browser-gif 配了 Python 编码脚本。skill 可以携带任意辅助资源——加载器只认 SKILL.md,目录里的其他文件由 skill 自己引用。

别和 packages/skill/ 混淆:那个目录是 skill 的运行时实现(skill / skill-filesystem / tool-skill / skill-office 等,见 23 页),是产品代码;.agents/skills/ 是这个仓库自己用的工作流,是工程实践。两者同名但不同层——前者的 skill-filesystem 加载的正是后者。

唯一带额外 frontmatter 的 skill

dsh-translate-docs 的 frontmatter 是 6 行而不是 4 行:

.agents/skills/dsh-translate-docs/SKILL.md调用策略1-6
1---
2name: dsh-translate-docs
3description: Manually run the extended DeepSeek Harness bilingual-document workflow, ...
4disable-model-invocation: true模型不能自己调用它
5user-invocable: true只有用户能调用
6---
4-5

这两个字段控制「谁能调用」。加载器把任意 frontmatter 解析成 SkillInvocationPolicy,而 catalog 渲染时用 filter(isModelInvocable) 过滤——所以 disable-model-invocation: true 的 skill 根本不会出现在模型的 <available_skills> 清单里。它只能由用户显式调用。

4

为什么这个 skill 需要这道闸?因为它做的是大批量双语文件改写——根 AGENTS.md 明确写着「only explicit user invocation may run dsh-translate-docs」。自动触发会让模型在无关的改动里顺手重写几十个翻译文件。

.claude/skills 也是符号链接

§1 提到 CLAUDE.md → AGENTS.md 的符号链接。同一招在这里又用了一次:

$ git ls-files -s .claude/skills
120000 2b7a412b8f... 0	.claude/skills

$ cat .claude/skills
../.agents/skills

Claude Code 从 .claude/skills/ 发现 skill,而这个仓库把整个目录链接到 .agents/skills/。同一份 skill 定义同时服务两个工具,不存在副本。这是「一个事实一个家」第三次出现(前两次是 CLAUDE.md 和文档分层)。

.agents/skills/.gitignore 只有一行:*/agents/openai.yaml——按工具约定忽略其他 agent 的本地元数据,但这恰恰说明目录本身是共享的。

本章讲的是仓库自己的 skill;skill 作为产品能力的加载机制在 23 页。两者的连接点很有意思——加载这些 SKILL.md 的正是 dsh 自己的 skill-filesystem 插件。仓库既是这套机制的使用者,也是它的实现者。§5 会看完整的加载链路。

§4把文档规则变成校验门

这是整套基建里最工程化的一环。scripts/ 下有 257 个 TypeScript 脚本,其中 55 个是 verify-* 门。文档相关的约 35 个聚合在 pnpm run doc-sync 里。

文档标准的关键条目

docs/AGENTS.md(76 行)定义标准,其中几条被门直接执行:

规则执行它的门
每段必须是一个物理行(用编辑器软换行,不要硬折行)verify-md-wrap
相对 Markdown 链接必须指向存在的文件verify-md-links
正文里不许出现真实 commit id 或不被允许的组织 URLverify-repository-references
文档字数不得超过预算清单verify-doc-budgets
围栏 ts 代码块必须能编译;粘贴的类型声明要登记防漂移doc-typecheck / verify-type-equiv
中英对照必须逐段对齐verify-translation-pairing
包 README 必须有 Summary / Model Experience / Known Limitations 段verify-package-readme-summaries 等三个门
Agent Note 的路径、状态行、段落骨架verify-agent-note-classification / -format / archived-agent-notes
skill 的调用元数据格式verify-skill-invocation-metadata

字数预算是硬约束

scripts/doc-budgets.manifest.json 是一份很短的清单——它只约束「常备文档」:

scripts/doc-budgets.manifest.json字数上限1-9
1{
2  "AGENTS.md": 1950,
3  "docs/AGENTS.md": 1320,
4  "docs/architecture.md": 2400,
5  "docs/cordis-primer.md": 600,
6  "docs/defensive-patterns.md": 550,
7  "docs/testing.md": 1350,
8  "packages/AGENTS.md": 750,
9  "packages/README.md": 994
10}

门红了怎么办?docs/AGENTS.md 给的是一套有序的处置流程(第 52-58 行),顺序本身表达优先级:

  1. Relocate——内容属于别的 tier,搬过去,必要时留一行链接
  2. Condense——内容确实该在这,但可以更短
  3. Raise——只有文字确实需要空间时才提高上限,且要在 PR 里论证

为什么是硬约束而不是「建议」?因为这些文档是常驻上下文——根 AGENTS.md 每次会话都会被注入(§5)。一个无限膨胀的指令文件会挤掉真正的工作内容。上限 1950 词不是审美偏好,是上下文预算。文件里还写着:「A too-low ceiling is a budget bug」——上限过低同样是 bug,说明这条预算被当成压缩目标而不是护栏了。

slop 清单:可执行的编辑标准

docs/AGENTS.md 的第 60-72 行是一份「slop 清单」——不是模糊的「写得好一点」,而是九条可检查的病症:

  • 重复的规则:搜一个有辨识度的短语;只留一个家,其余改成链接
  • 历史出现在不该出现的 tier:陈述当前事实 + 链接历史所有者
  • 实现状态标注(「implemented!」「future: …」):状态会腐烂,仓库布局和 manifest 才是权威
  • 手工重述的目录:源码或生成器才是权威
  • 推理记录:逐步实现叙述、显然分支的证明、测试走查、被否决的本地替代方案
  • 段落墙:一段塞了好几条规则和插入语
  • 强调膨胀:处处加粗 = 什么都不突出
  • implemented/ 笔记里的规格语言:「should」、迁移计划、验收清单

dsh-doc skill 把这份清单当作审计流程来跑。

§5闭环:指令如何进入模型

前面四节讲的是「仓库里有什么」。这一节讲这些东西怎么真正到达模型——答案就在 dsh 自己的代码里。有两条独立的注入链路:一条送 AGENTS.md,一条送 skill 目录。

链路 A:AGENTS.md → 上下文

负责的插件是 packages/context/agent-instructions(360 行)。模块注释一句话说清职责:

Workspace instruction loader for AGENTS.md-compatible files.
…tool touches project nested, changed, and removed instructions into the inbox.
packages/context/agent-instructions/src/config.ts文件名候选与根标记11-14
11const DEFAULT_PROJECT_ROOT_MARKERS = ['.git'] as const
12const DEFAULT_INSTRUCTION_FILE_CANDIDATES = ['AGENTS.md', 'CLAUDE.md'] as const同一目录里两个都读
13const DEFAULT_LOCAL_INSTRUCTION_FILE_CANDIDATES = ['AGENTS.local.md', 'CLAUDE.local.md'] as const
14const DEFAULT_MAX_SOURCE_BYTES = 1_048_576
11

向上找 .git 定项目根——从会话的 cwd 往上走,遇到 .git 就停下。这是「哪个 AGENTS.md 链适用于我」的判据。

12-13

AGENTS.md 与 CLAUDE.md 并列在候选列表里,同一目录两个都存在就都读(按目录内 trim 后的内容去重,重复的折叠到靠前的候选)。.local.md 变体作为覆盖层在基础文件之后加载。这就解释了为什么仓库用符号链接而不是复制——加载器本来就认这两个名字。

它的 README 把完整行为讲清楚了,其中三条对理解协同很关键:

  • 首次请求时加载适用的链;
  • 不持续监听外部编辑——而是成功的文件系统操作(read/write/edit)发现新出现的嵌套文件、或让后续的修改/删除变得可见;session resume 时重新对齐基线;
  • 字节预算限制注入内容:更宽泛的文件先被省略,最具体的文件才会被截断;空链不添加任何东西。

注意第二条的词表耦合:插件监视的工具名是硬编码的——FILE_TOUCH_TOOL_NAMES = new Set(['read', 'write', 'edit'])(index.ts:74)。仓库里改工具名会让这条链路失效,而这类耦合不写在文档里,只能从代码读出来。

链路 B:skill 目录 → <available_skills>

skill 的发现与注入走另一条链,实现也在仓库自己的代码里(这正是 23 页的主题)。解析 .agents/skills/ 的那一行在:

packages/skill/skill-filesystem/src/index.ts项目 skill 根目录250-251
250        { path: join(projectRoot, '.dsh/skills'), source: 'project-dsh', rank: PROJECT_DSH_RANK, projectRoot },
251        { path: join(projectRoot, '.agents/skills'), source: 'project-agents', rank: PROJECT_AGENTS_RANK, projectRoot },本仓库的 12 个 skill 从这里被发现
250-251

findProjectRoot 用同一个 .git 判据找项目根,然后拼出两个候选目录。优先级常量定义在同文件 36-40 行:PROJECT_DSH=100 < PROJECT_AGENTS=200 < CUSTOM=300 < USER_DSH=400 < USER_AGENTS=500——数字小的赢。所以项目内的 skill 会遮蔽用户级同名的。

发现之后,每个 SKILL.md 被解析(parseSkillFile,index.ts:797):frontmatter 缺 name 或 description 就忽略整个文件,正文作为 content。然后 tool-skill 把它们送进模型:

packages/skill/tool-skill/src/index.ts注入 <available_skills>226-227
226    const skills = snapshot.skills.filter(isModelInvocable)不可模型调用的被滤掉
227    const entries = catalogSourceEntries(skills, catalogDescriptionMaxLength)

这段跑在 agent/pre-step 监听器里(index.ts:213),产出的是一个 <available_skills> 块作为 user message。模型看到的是 skill 的名称与 description,不是正文——它要按 description 匹配,然后显式调用 skill 工具才拿到内容。这正是 description 为什么要写成「何时用」的原因。

闭环

把两条链连起来:

仓库根 AGENTS.md(175 行常备命令)
  → agent-instructions 插件首次请求时读入
  → 作为 user/message 注入 session inbox(08 页 preStep 的 claim)
  → 进入模型上下文

.agents/skills/*/SKILL.md(12 个)
  → skill-filesystem 扫描 .agents/skills/(source: 'project-agents')
  → tool-skill 在 agent/pre-step 渲染 <available_skills> 块
  → 模型按 description 匹配 → 调 skill 工具读正文

  → agent 按指令改代码
  → 推送前跑 dsh-pre-push-checks skill 选检查集
  → CI 跑 55 个 verify-* 门
  → non-trivial 改动必须附一篇 Agent Note
  → 决策沉淀回 .agents/notes/,供下一个 agent 查「为什么」

仓库用 dsh 的机制管理 dsh 自己的开发。这不是比喻——agent-instructions 与 skill-filesystem 都是随 dsh-base 默认启用的插件。你在读的这套指令注入链路,就是你在用的那套。

还有个细节值得注意:packages/AGENTS.md 里有一条规则专门管这件事——「Write model-facing contracts from the model's perspective」。它要求 prompt、tool schema、结果、诊断里只出现任务相关的概念,不带 UI、传输层或实现词汇。而 agent-instructions 注入的正是「模型可见文本」,所以这套指令文件本身也要遵守那条规则。规则递归地适用于写规则的文件。

§6这套做法的取舍

把 1028 篇决策记录、12 个 skill、55 个校验门当作一个设计来读,它选择的是什么?

选择得到付出
决策写进仓库(Agent Notes),不留在 PR 讨论里理由可检索、可交叉引用、随代码一起演化;不依赖 GitHub 的可访问性每篇都要维护中英对照与 sidecar;实现变更时必须同步更新
「替代方案」必填阻止重新litigation——后人不必再问「当初为什么不用 X」写一篇笔记的成本显著上升
归档永久冻结 + 哈希清单历史不可篡改,审计可信归档判据必须谨慎;错误归档无法挽回
文档规则由门执行(而非 review 时人工判断)标准一致、不依赖审查者的记忆;agent 能自己发现违规257 个脚本本身需要维护;规则改动的成本更高
字数预算是硬上限常驻上下文不膨胀——这直接决定 agent 每次会话能用多少 token 干活内容必须搬家或精简,不能「先加上回头再整理」
指令用符号链接而非复制一个事实一个家;Claude Code 与其他 agent 共享同一份Windows 上符号链接需要额外权限(仓库仍提交为 mode 120000)

贯穿始终的一条原则:把「纪律」变成「可执行的断言」。这与前 34 章反复出现的 fail-loud、模型可见 ⟺ 已记录、invariant 断言是同一种思路——只不过这里被断言的不是运行时行为,而是协作过程本身。

根 AGENTS.md 第 165 行把这条写成了要求:「Wire mechanically checkable invariants into an executed top-level gate and prove each changed acceptance path rejects an invalid case.」——凡是能机械检查的不变量,都要接进一个真正会跑的门,并且证明每条改动过的验收路径能拒绝一个非法输入。

给读者的一句话:如果你在自己的项目里想引入 AI 协同,这套体系里最值得先拿走的不是 1028 篇笔记的规模,而是三个小东西——① AGENTS.md 分层 + 符号链接共享(成本最低,收益立刻);② ## Alternatives considered 必填(一篇笔记就能看出差别);③ 把一条你最常重复的 review 意见写成 verify-* 脚本(从此不再需要重复它)。