实战复盘 · research-share

基于 Matt Pocock Skills 的
AI 原生开发最佳实践

一个真实仓库、五天、五十个提交的全部做法。不含技能原文校订,不含判定徽章,不含「原文该怎么改」——只有能直接照搬的动作,以及每个动作在实战里换来了什么。

周期
5 天
提交
50 +15,061 / −2,596
工单
12 全部关闭
测试
168 3.5 秒全绿
领域文档
5 ADR + 24 术语
人机交互
179 条人类指令
00

先记住一句话

人负责把仓库变成一份智能体可执行的工程规范,智能体负责在这个规范内高速执行;技能体系是两者之间的协议。

这句话有三个直接推论,它们撑起了后面全部内容:

  1. 仓库不是代码仓库,是上下文仓库。智能体每次开工都是从零建立心智模型,仓库里写清楚的东西它才不会再问你第二遍。
  2. 规范越硬,授权可以越大。这个项目里人对智能体的高频回复是「都按推荐的来」——之所以敢批量接受推荐,是因为规范、工单、验收标准都在仓库里,跑偏了评审会抓。
  3. 流程的产出物是护栏,不是文档。每个阶段结束都要留下一个能约束下一次运行的东西:一行 CLAUDE.md、一条 lint 规则、一条测试、一篇 ADR。
01

三条心法

1.1 上下文即产能

智能体的产出质量上限,取决于它进入仓库时多快建立正确的心智模型。同一句「加个文档分享功能」,在没有任何上下文的仓库里会产出平庸的猜测;在一个有术语表、ADR 和坑清单的仓库里会产出符合既有隔离模型的方案。

所以准备阶段的投入回报率最高,而它发生在一行代码之前。

1.2 规划与实现必须换窗口

规划(追问 → Spec → 拆票)要在一个未压缩的上下文里连续完成,因为后面所有执行都依赖这条推理链。而实现要在一张工单一个全新上下文里做,因为工单体自含全部验收标准,不需要历史记忆。

这两件事混在一个窗口里,就会出现「越写到后面越糊涂」的典型症状:上下文里塞满了早先的调试噪声,模型开始用记忆代替读代码。

1.3 经验要落成护栏,不能落成记忆

一次痛苦的调试如果只换来「下次注意」,那它下次一定复发。这个项目的判断标准很硬:

没有测试,这次修的 bug 会重新活在测试真空里。

同样的逻辑适用于流程本身——评审发现的机械性违规,要变成 linter 规则或 pre-commit 钩子;判断题才写进标准文档。默认建检查,而不是写规矩。

02

准备:让智能体第一次进仓库就拿到正确方法论

目标不是「开始写」,而是让智能体第一次进入仓库时就拿到正确的工程方法论与事实。这个阶段有四个提交前的动作。

2.1 装方法论:插件 + setup 锚定

技能不是一段提示词,是一整套互相衔接的工程方法论:怎么把想法问穿、怎么写规格、怎么拆工单、怎么做 TDD、怎么评审、怎么沉淀领域知识。

装完之后必须跑一次 /setup-matt-pocock-skills。它做四件事:

产物作用
CLAUDE.md 里的 ## Agent skills 区块所有技能的入口,没有它技能不知道去哪读配置
docs/agents/issue-tracker.md工单系统对接:本仓库用 GitHub Issues,全部操作走 gh CLI
docs/agents/triage-labels.md五个标签的映射表(条件产物:只在装了 triage 技能时才生成)
docs/agents/domain.md领域文档消费规则:探索前必读哪些、命名必须用术语表的词、与 ADR 冲突必须显式声明

后三件的意义:技能是通用的,配置把通用方法论锚定到本仓库的事实上。此后每个会话、每个子智能体共享同一套工单语言、标签语言和术语语言。

工单系统不必是 GitHub——GitLab、本地 markdown 文件(.scratch/)、甚至自由文本描述都行。个人项目没有远程仓库照样能跑全套流程。

可直接手改。这三份配置生成后就是普通文档,把标签换成团队习惯的叫法、改改 CLI 命令都可以,只有换 issue tracker 时才需要重跑 setup。

2.2 分清两种技能:哪些要你亲手敲,哪些会自己跑起来

新手最容易误解的一点:把全部技能当成斜杠命令,以为智能体会自动使用。事实上有条贯穿全局的规则——技能分两类,触发方式完全不同。

类型谁能启动成员
用户触发
user-invoked
只有人亲手敲。其他技能无权调用,包括在文本里点名setup、ask-matt、grill-with-docs、to-spec、to-tickets、implement、implement-spec、triage、wayfinder、retro、handoff、improve-codebase-architecture
模型触发
model-invoked
智能体可自主调用,人也能手动敲tdd、code-review、codebase-design、domain-modeling、grilling、diagnosing-bugs、research、pr、writing-for-agents

更细一层的边界:用户触发技能可以调用模型触发技能,但永远不能调用另一个用户触发技能。所以当某步的前提是一个用户触发技能时,正确写法是「告诉用户去跑它」,而不是让技能去 call 它。

这条规则解释了实践里两个看起来像「魔法」的现象:

  • /implement 内部自动串起 TDD 与评审,不是框架能力,是技能文本在指挥智能体(Call the Skill tool with "tdd")。
  • grilling 的决策会当场落进 GLOSSARY,因为 /grill-with-docs 的全部定义就是一句话:先后调用 grilling 和 domain-modeling。写文档是 domain-modeling 干的活。

还有一个常被忽略的边界:读 GLOSSARY 查词汇 ≠ 使用 domain-modeling 技能。只有主动的「挑战术语、补边界情景、写 ADR、就地更新术语表」才算。

实操含义

主流程上每一步都得你自己敲,智能体不会替你启动 /to-spec 或 /implement。而 tdd、code-review、grilling 这些会被上层自动调用,一般不用操心——除非它该调却没调,那时你要能说出被漏掉的是哪一个。

2.3 仓库即上下文:四层「带路」结构

这个仓库把「让代码库自己能带路」做到了四层。每层的分工是硬边界,越界的部分会在评审时被抓住。

层文件写什么绝不写什么
仓库指南CLAUDE.md常用命令、架构要点、只有线上才暴露的坑、部署约束代码能推断出来的目录结构
领域语言GLOSSARY.md概念是什么、不是什么、与邻近概念的分界interface 签名、实现决策、待办草稿
决策档案docs/adr/决策、被拒方案及理由、刻意接受的代价—
技能配置docs/agents/工单/标签/领域文档的消费规则—

CLAUDE.md 的判据:只写代码推断不出来的东西。这个项目的「容易踩的坑(线上才暴露)」专栏是最有含金量的部分,全是看代码看不出来的事实:

  • 不要用 Authorization: Bearer,平台边缘代理会吃掉这个头,线上 401——Agent API 用 X-Agent-Token;
  • 文档型成果的请求体不能含 <script 或内联事件属性,边缘 WAF 直接 403 拦截页,请求到不了应用;
  • og:image 必须是绝对 URL 且来自显式配置的 SITE_URL,不能拼请求 Host 头(反代后是内网地址);
  • 服务端 page_view 埋点刻意不带 session_id,否则会撞掉客户端那条的 3 秒去抖;
  • 演示模式是刻意的静默降级,所以「接口通了」必须验数据条数,不能只信返回码。

这几条每一条都对应一次踩坑。注意它们的形式:不是「要小心 X」,而是「X 为什么在这里不成立,替代方案是什么」。前者是口号,后者是可执行约束。

一个反直觉的补充:CLAUDE.md 要极其克制,多数情况下它应该只承担导航指针的角色——指向 GLOSSARY.md、docs/adr/、docs/analytics.md。为什么?

  • CLAUDE.md 会推进每一个智能体的上下文窗口,写得越厚,每次开工的固定成本越高;
  • 它同时是实现侧读的。而标准应该压在评审侧——评审智能体只拿一个 diff,上下文压力最小,最有余力逐条核对规范。

所以分工是:CLAUDE.md 给方向(指针为主),CODING_STANDARDS.md 给尺子(评审期读)。

GLOSSARY 的写法:每条只写三样——这个概念是什么、不是什么、与邻近概念的分界在哪。技能原文是明文禁令:GLOSSARY 必须完全不含实现细节,它不是规格、不是草稿纸、不是实现决策的存放处。

为什么这条重要:签名写进词条后,代码一改文档就过期,而评审的 Standards 轴恰恰拿 GLOSSARY 当规范逐条核对——过期词条会把评审带进沟里。签名属于代码本身和 ADR。

双向效果:人写文档给智能体读,智能体的产出也受文档约束。评审时 Standards 轴拿着这些文件逐条核对,「文档」从给人看的说明变成了给智能体执行的规范。这个项目的一次评审抓到 CLAUDE.md 模块清单漏登记 constants.js,就是按硬违规修复的。

单一事实来源要当场上收。智能体学到「发布必须由运行时执行」这个事实后,人的第一反应是追问「这个维护到 README 中了吗」——学到的教训当场回流,而不是留在会话记录里等它蒸发。

03

规划:先把想法问穿

三个步骤在同一个未压缩的上下文里完成:判断 → 契约 → 切片。此时追问的思考链还在窗口里,是后面所有执行的前提。

3.1 追问:无情的访谈,每问都带推荐答案

/grill-with-docs 是这个项目使用频率第三的技能(17 次)。形态是「无情的访谈」:智能体不急着给方案,而是按设计树逐层追问,每问都带一个推荐答案,用户回「是」即接受。

这个设计同时解决了两个问题:把人从「想全所有细节」里解放出来,又保留了每个关键决策的拍板权。

Spec #2 的三轮 14 问覆盖了:文档定位与录入方式 → 托管呈现、安全隔离、存储模型、大小上限 → 幂等语义、演示样例、埋点口径、是否立 ADR。用户不懂 CSP 时直接反问「我对这个技术不了解」,智能体解释威胁模型后再拍板——追问也是教学。

四个必须记住的行为准则:

准则含义
事实归智能体,决策归人需要仓库里的事实(「数据库什么版本」)应派子智能体去查,而不是反过来问人。被人索要自己能查的事实,回答「自己查。」
未确认不动手技能自带收尾条件:用户确认达成共识之前不许行动。这是内建行为,不需要你喊停
高价值问题是顺序决策不是「要不要做」,而是「先做哪个」
追问结束 ≠ 可以开工决策落盘、实现另起炉灶

关于顺序决策,这个项目有两次典型收益:

  • 架构评审后的实施顺序定成「2→3→1,先补测试防线,再动结构」;
  • Spec #3 的落地顺序被反转:事实核查子智能体发现数据面 publish 依赖门控填充的登录态,顺序从「常量→数据面→门控」改为「常量→门控→数据面」。这个反转如果漏掉,第一张票就会建在还不存在的地基上。

3.2 Spec 即契约:七段,一段都不能少

/to-spec 把 grilling 的结论发布为 issue。模板是七段:

Problem Statement        # 用户视角的真实动机,不是功能描述
Solution                 # 用户视角的解法
User Stories             # 极长的编号列表,As a <actor>, I want <feature>, so that <benefit>
Implementation Decisions # 模块、接口改动、schema、API 契约、具体交互(不写文件路径与代码)
Testing Decisions        # 什么算好测试、测哪些模块、既有测试的 prior art
Out of Scope             # 这次不做什么
Further Notes            # 补充说明

四条硬规则:

  1. 不采访,只综合。技能原文:Do NOT interview the user; just synthesize. 如果 /to-spec 开始采访你,说明 grilling 没做完,顺序反了。
  2. 先定测试 seam 再写 Spec。步骤 2 就是画出要测的 seam 并与用户确认,且要求「用尽可能高的 seam,能复用就不新增,理想数量是一个」。
  3. 不写文件路径与代码片段,理由是「它们很快会过期」。唯一例外:原型产出的、比散文更精确编码了某个决策的片段(状态机、schema、类型形状)。
  4. 发布即打 ready-for-agent,不再走 triage。

实战质量标尺——Spec #2 的实际内容:

  • Problem Statement 写真实动机而非功能描述:「录入者手上有本地的 HTML 文档……但没有地方托管」;
  • User Stories 20 条,覆盖六类角色:录入者、读者、智能体、管理员、演示模式访客、站长/平台维护者;每条都是可验收句式;
  • Implementation Decisions 细到「doc_html 不进列表查询(Postgres TOAST 下也不付序列化成本)」这种实现级约束;
  • Testing Decisions 在写代码前就定好测试哲学:「只经 interface 测外部行为,不测实现细节」「唯一 seam 沿用既有做法,不新增」。

纯重构的 Spec 也要写用户故事,写的是「什么都不许变」。Spec #3 里第 16–22 条整组是「行为不变」故事:「作为录入者,我用『+ 分享』录入时,文档超限与含脚本的预检提示与之前一致」。这一组后来成了评审 Spec 轴的核对依据。

Out of Scope 是日后最有用的一段。它是评审判断「范围蔓延」的尺子——漏了它,评审就失去了说「这超出了规格」的依据。

3.3 拆票:曳光弹、阻塞边,以及不存在的那道标签闸门

/to-tickets 的输出不是任务清单,而是一组曳光弹工单:每张票纵贯全部层(schema → 存储 → 路由 → 渲染 → 测试),交付一个端到端可验证的行为切片。

Spec #2 的拆法:#3 是「读者侧最小贯通」地基票(含迁移、派生、路由、渲染分支),#4 录入模态 / #5 Agent API / #6 admin+demo 三张并行票,全部建成 #2 的原生 sub-issue,并用 GitHub 原生依赖边声明阻塞关系。

工单是任务图,不是步骤列表。图上有阻塞边,就永远存在一个 frontier(可抓取的票的边界)——这是后面并行调度的基础。

每张票的固定三段(以 #3 为例):

## Parent
Spec:#2

## What to build
(含地基工作清单与明确的不变量:「链接型成果的列表、详情、OG 封面、分享海报完全不变」)

## Acceptance criteria
- [ ] 迁移幂等可反复执行;CHECK 强约束……
- [ ] 请求托管地址时 page_view 计数为零;请求详情页时恰为一次
- [ ] node --test 全绿

验收标准要可机械核对。「页面看起来正常」不是验收标准;「请求托管地址时 page_view 计数为零;请求详情页时恰为一次」是。

「红线」写法值得专门学。ticket #12 里有一句:对外行为完全不变,fit 循环耗尽时返回字号偏小的现状用表征测试钉住,修复另起 commit 单独评审。

已知的 quirk 不顺手修——这是拆票阶段最容易被破坏的纪律。最终仓库里确实是两个 commit:一个表征测试 + 抽出,行为不变;一个修 quirk,口径翻转。重构与修 bug 分离评审,评审者才能把注意力放在「行为是否真的没变」上。

标签闸门不存在。/to-tickets 产出的票「天生就是智能体可以直接抓取的」(原文:agent-grabbable by construction),发布时自动打 ready-for-agent。不存在「等标签打完才许动工」这一道闸。

拆票粒度是人的决策。智能体提 6 票方案,人按回滚与评审粒度收窄为 4 票——「还是 4/5/6 合并回『数据面一票』吧」。这类判断没有规则可循,只能人做。

分支策略要不对称:

工作类型分支理由
Spec 级工作集成分支 spec/N-xxx + 每票一个 ticket/N-xxx + worktree 隔离多票并行、需要统一收口点
Spec 外小任务直提 main分支开销只花在 spec 级工作上,不为流程而流程

favicon 统一、按钮配色、CLAUDE.md 更新这类改动全部直接提交 main。

04

执行:一票一个干净窗口

每张票从全新上下文开工,票体自含全部验收标准。TDD 与评审不是两个额外步骤,是 implement 的组成部分。

4.1 测试打在缝上

/implement 是执行主力(46 次)。TDD 由它内部自动驱动,节奏是逐垂直切片的红绿循环:「切片 1:list() 物化派生字段——先写失败测试。红。写最小实现。绿。」

最硬的一条规则是 seam 必须事先约定:

Test only at pre-agreed seams. Before writing any test, write down the seams under test and confirm them with the user. No test is written at an unconfirmed seam.

写任何测试之前,先把要测的 seam 写下来并和用户确认;未确认的 seam 上不许写测试。理由是「你不可能测完所有东西」——提前约定 seam,测试精力才会落在关键路径与复杂逻辑上,而不是每个边缘用例。

对应的提问句式:「这张票的测试打在哪些 seam 上?」这个问题本应由智能体主动问你(implement 原文就是 at pre-agreed seams),它不问,你来问。

三条反模式,评审时按这个识别:

反模式症状判据
implementation-coupled重构就碎,行为没变测试却红了mock 内部协作者、测私有方法、走旁路验证(查数据库代替走 interface)
tautological断言永远通过用和被测代码相同的方式重算期望值(expect(add(a,b)).toBe(a+b))
horizontal slicing先写全部测试再写全部实现验证的是想象的行为,测的是形状不是行为

期望值必须来自独立的事实来源:已知正确的字面量、算过的例子、规格。

还有一条边界:重构不属于红绿循环,它属于评审阶段。

这个项目的三条测试选型(是选型,不是规定,可以换):

  • interface 即测试面:测试只打在预约定的缝上,不碰私有实现;
  • 零框架依赖:node:test 内置 runner,无 Jest/Vitest;
  • 真实流而非 mock 对象:路由测试用 listen(0) + 真实 fetch,因为 readJsonBody 需要真实流。

第三条尤其值得学:该用真东西的地方别用 mock。一旦被测代码的语义依赖真实流的行为,mock 掉的不是依赖,是被测对象本身。

4.2 两个高价值技巧:表征测试与不变量断言

这两个技巧是这个项目里最值得复用的方法论,都与「测试的价值不在覆盖率,而在它能否阻止下一次回归」有关。

技巧一:表征测试(characterization tests)

IIFE 里的遗留逻辑无法直接测,怎么办?先写 21 条测试钉住现状行为——包括已知的 quirk——抽出重构后测试一行不改。在这类重构里,「没变化恰恰是通过了」。

这也是它容易被人误解的地方。这个项目收尾时人直接问:「分析,我看了海报图和之前没变化吧,到底要干什么?」——得到的答案是:这次的目标就是零行为变化,把那块逻辑从 DOM/Canvas 里剥出来变成可测模块,为的是下一次改动不再靠肉眼验收。

修 quirk 时再把测试口径翻转到修复后行为,测试与 GLOSSARY 同步改。表征测试 → 重构 → 翻转口径,三步走完,遗留逻辑就变成了有护栏的模块。

技巧二:不变量从注释变成断言

SSR 埋点不带 session_id、串行落库、永远 204、20 条截断——这些原本只有注释保护的不变量,全部变成了会失败的测试。

判据很朴素:如果一个不变量只靠注释维持,它迟早会被一次「顺手优化」推翻。

浏览器侧的 seam 设计也值得抄:预设最小 window + 顶层 import + fake-cloud 适配器。

fake-cloud 不是简单桩,而是一个带完整控制面的仿真:能断言 select 列清单与 payload 形状(reads/writes 记录)、注入 res.error 测错误翻译、注入整条链 reject 测网络失败,还能用 silentBlock 模拟 RLS 静默拦截(写 0 行不报错)。

最后这个是真实环境里最阴险的失败模式——错误的写入不报错,只是没生效。现在它成了一条可重复的测试路径。浏览器数据面 21 个测试全部经此缝直贴 interface。

4.3 双轴评审:Standards 与 Spec 互不污染

每次实现后必跑 /code-review。两个子智能体并行派出、互不污染,报告不合并、不重排。

第一件事是钉住 fixed point。评审对象是一段 diff,不是整个仓库:

git diff <fixed-point>...HEAD     # 三点,对比 merge-base
git log <fixed-point>..HEAD --oneline

固定点可以是 commit SHA、分支名、tag、main、HEAD~5。用户没给,技能会停下来问;坏 ref 或空 diff 会在这里失败,而不是等两个并行子智能体跑完才发现。

手动复跑时一句话就够:「/code-review,fixed point 是 main」。

轴对照什么这个项目的实获
Standards仓库里所有记录「代码该怎么写」的文件 + Fowler 坏味道基线store interface 回吐 siteUrl(Middle Man 残留)、render 用 it.no.slice(3) 反向解析物化字段(推导回漏)、CLAUDE.md 模块清单漏登记 constants.js
Spec工单验收标准逐条核对 + 查 scope creepPATCH 空值放行(契约漏洞,最严重项)、详情页缺「查看原文」按钮、GLOSSARY 术语超前于代码

Standards 轴的清单不是那几份领域文档。它搜索仓库里所有「记录代码该怎么写」的文件,CODING_STANDARDS.md 与 CONTRIBUTING.md 存在时必须在列;在此之上还有一套固定的 Fowler 坏味道基线(Mysterious Name、Duplicated Code、Feature Envy、Data Clumps、Primitive Obsession、Repeated Switches……),仓库什么都没写也照样生效。

两条约束:仓库成文标准 > 坏味道基线(文档认可的做法要压掉 smell 告警);坏味道永远是判断题,不算硬违规。

发现分三级处置(第三级是项目自加的台账习惯,很好用):

级别处置
硬违规必修,修完才准合并
判断题列给人定夺
知悉即可记入台账

台账真的有用。一次评审标注「quick-share 用 padStart 自行推导编号,与公共身份单点派生有张力,未来评审留意」——两周后的 ticket #9/#11 会话里这个嗅觉被正式收口成一次重构。

评审还会抓到「规格之外」的发现。冒烟测试对真实云环境跑出了平台边缘 WAF 拦截含 <script 请求体的事实——它不属于任何一张票,但改变了写入面的前提。这类发现的处置方式见 5.2:真实环境的约束必须逆流回 ADR。

4.4 多子智能体编排:探索、并行实现、合并

/implement-spec 展示了成熟的多智能体模式。五个要点:

探索子智能体 产出代码地图(仓库外留档) 地基票 #3 端到端最小贯通 实现者 #4 worktree + TDD 实现者 #5 worktree + TDD 实现者 #6 worktree + TDD merger 子智能体 统一合并,报告前先合回 tip 集成分支整体评审 spec/N-xxx 一次 code-review 冲突在实现侧消化,不在合并侧解决。
任务图按 frontier 推进:地基票解锁并行票 → worktree 隔离实现 → merger 收口 → 集成分支整体双轴评审。
  1. 探索子智能体先行:产出代码地图(各 ticket 涉及的文件清单、「materialize 是派生单点」等关键发现),存到仓库外的目录,供后续所有实现者共享。实现者因此不必重复探索。
  2. frontier 驱动调度:地基票 #3 先跑,它解锁后 #4/#5/#6 并行。每完成一张票就重算 frontier,能起几个起几个。
  3. 每个实现者一个 worktree:在 .claude/worktrees/ticket-N 里独立调 TDD 技能实现。开工前确认自己的 worktree 基于集成分支,不对就 reset 上去。
  4. 报告前先把集成分支最新 tip 合回自己的分支。这条是设计核心:冲突在实现侧消化,不留给合并者。
  5. merger 子智能体统一合并,信息格式统一。
  6. 子智能体间稀疏通信:靠 context pointer(探索报告路径、spec 编号、commit)传递上下文,不互相倒垃圾。

第 4 条的直接结果是:在 implement-spec 流程里,合并本该是无冲突的 fast-forward。如果 merger 频繁撞冲突,说明实现者漏了「先合回 tip」这一步——该修流程,而不是改 git merge --no-ff。

人也在这个循环里。看这句真实指令:

检查探索子智能体是否完成(/tmp/research-share-spec2/exploration.md 是否存在);若完成则启动 ticket #3 的实现子智能体(implement-spec 工作流,集成分支 spec/2-doc-items)。

注意措辞:人把工作流术语(frontier、集成分支、实现子智能体、探索报告路径)当操作语言用,手动驱动编排循环。人是指挥,不是旁观者——在自动化程度最高的环节,人反而要盯的是「哪张票该起来了」。

关于 PR:implement-spec 的目标产物是集成分支本身。只有当 issue tracker 以 PR 闭环、或用户主动要求时,才开草稿 PR(且要在第一次合并之后开,因为空分支开不了 PR)。

4.5 一票一窗口

每张票的完整节奏:

/clear → /implement #N → (内部 tdd 红绿循环)→ (内部 code-review 双轴)
        → 合并 → 关闭工单 → /retro

票体自含验收标准,所以新窗口不需要任何记忆。这条纪律的收益在长任务里最明显:第 12 张票开始时,上下文只包含第 12 张票。

05

收口:把经验变成护栏

合并只是终点线,不是终点。决定第二个项目更快的是两件事:复盘产出的自动化检查,与持续演化的领域文档。

5.1 复盘:不是感想清单,是环境改造清单

/retro 的对象是一个会话(默认当前会话;/clear 之后才指向历史日志),产物是智能体环境的改进。这个项目跑了 7 次,其中一次派 4 个子智能体逐条解析约 25MB 历史会话日志——复盘本身也是多智能体工作流。

七个固定类别,每一类都对应一种「下次能省多少事」:

类别触发条件典型产出
Navigation找一个信息花了很久加一个导航指针
Automated checks智能体犯了检查能抓到的错lint 规则、pre-commit、CI job
Coding standards评审没抓到的错分类后决定写检查还是写标准
Global AGENTS.mdsteering 文件过大把指令搬去标准或检查
Tool economy有昂贵的工具调用精简 CLI/MCP
No-opssteering 文件里的空转指令删掉
Information access关键信息拿不到tee 日志、只读访问第三方服务
最值得抄的一条

机械性违规 → 确定性检查(linter 规则、pre-commit 钩子、CI 任务);判断题 → 写进 CODING_STANDARDS.md。原文的态度很硬:默认建检查,而不是写规矩;标准文件只留给真正的判断题(跨文件一致性、「与周围风格相符」这种任何护栏都替代不了的)。

而且——仓库连一道护栏都没有,本身就是一条发现。没 lint 的仓库是一个长期错过的机会,不是中性的默认状态。

使用时机:一次构建结束后(尤其是不顺的一次),在 /clear 之前直接敲 /retro。它先读写作规范,再读会话记录,按严重度给候选。

期望的产物长这样:「给仓库加一条 lint 规则」「给 CLAUDE.md 加一个导航指针」「把这 30 行 steering 删掉」。不是「下次要加强沟通」。

5.2 领域文档持续沉淀

domain-modeling 的纪律贯穿全程。三条实操规则:

规则一:ADR 只在三条件齐备时立

难逆转 + 无上下文会惊讶 + 真实权衡。5 篇全部满足:CSP sandbox 隔离(安全模型)、登录态只存浏览器(架构形态)、任命权收归初始管理员(权限模型)、条目存储(模块边界)、浏览器三模块深化。

每篇都含完整的 Considered Options——被拒方案与理由同等重要,它们是未来评审「不重复提议被否决方案」的依据。ADR-0004 里「为什么不用独立域名」「为什么只靠 iframe sandbox 不行」写得比结论还长,这是对的。

规则二:ADR 是活文档,修订要留痕

ADR-0004 有两次修订,都是现实逆流回文档:

  • 第一次:线上冒烟发现平台 WAF 拦截含脚本请求体,「不做消毒、JS 照跑」的写入前提在 API 通道上不成立,写入面收缩为无脚本静态 HTML;
  • 第二次:产品决策变化(详情页去 iframe),隔离从双保险收口为 CSP 单保险,并论证「这没有削弱实际防护」。

两次都是由一句人类指令启动的:「更新 ADR-0004 记录这个真实约束」。

修订与「冲突必须显式声明」是同一件事的两面:产出与既有 ADR 冲突时,不许静默覆盖,要在提交与文档里说清改了什么、为什么改。

规则三:GLOSSARY 术语先行、逐票核对

grilling 阶段就新增词条(术语先行),但每票评审都要核对「术语与代码一致」。

  • #9 评审发现「登录态门控」预写语义与票面矛盾,随即修正;
  • #10 评审发现「浏览器数据面」超前于代码,标注过渡态;
  • #11 收尾票的验收标准里专门有一条「GLOSSARY 三术语与代码核对一致」。

术语表不是一次性产物,是与代码同步演化的活文档。而「超前于代码」是一个真实且高频的风险:术语先写、代码后到,中间那段时间它会把评审带偏,所以必须显式标注过渡态。

06

常备武器:不在流水线上,但决定流水线的质量

主流程只用了技能体系的一半。以下这些几乎每个项目都会遇到。

6.1 bug 诊断:先造一条「会变红的命令」

这是最该补上、也最容易被跳过的一个。这个项目修过真 bug(详情页 404、海报 fit quirk),但诊断纪律没有成为默认动作——这是最大的遗憾。

纪律一句话:先造一条会变红的命令,再谈原因。

If you have a tight pass/fail signal for the bug, you will find the cause... If you don't have one, no amount of staring at code will save you.

所谓紧反馈环:一个几秒内跑完、这个 bug 在就红、修了就绿的命令。

六阶段:造反馈环 → 复现并最小化 → 列 3 到 5 个可证伪的假设 → 逐一探查 → 先写回归测试再修 → 清理调试痕迹。

反馈环的构造顺序也给了,从便宜到贵:失败测试 → curl/HTTP 脚本 → CLI + fixture 对比快照 → headless 浏览器 → 回放抓到的 trace → 一次性最小 harness → property/fuzz → bisect 自动化 → 新旧版本差分 → 人工脚本(最后手段)。

造好之后还要把反馈环当产品打磨:更快、信号更锐(断言具体症状,而不是「没崩」)、更确定(锁时间、固定随机种子、隔离文件系统、冻结网络)。

修完建议接一句 /retro:什么能防止这个 bug?

6.2 原型:不是用后即焚,而且有两个分支

设计存疑时不动 main,在一次性分支上快速出多个变体。两次典型:

  • 公开页版式(prototype/display-styles):A「暗夜档案」/ B「杂志特稿」两版同屏对比,?variant= 切换 + 底部胶囊条 + 方向键。选 B 后「折叠」回 main,原型分支留档不进主干。
  • 快速分享入口(proto/quick-share-entry):两轮对比——第一轮「入口放在哪」,第二轮「发布后如何一步分享」。结论与落选理由全部写进 issue #1 的变体对照表。

关键认知:原型的价值在于被比较和被否决。落选方案与理由留档,是因为三个月后一定有人问「为什么不用悬浮球」——issue 里那张表格就是答案。

技能原文有一句必须记住:throwaway 是对写法的约束,不是销毁的承诺。验证过的决策折回真代码,原型本身 commit 到 prototype/<name> 分支留档,并在实现 issue 上留指针。「用后即焚」这个说法是误导。

两个分支别混:

你的困惑产出
「这个逻辑/状态模型对不对?」一个双击就能打开的单 HTML 文件,带自由操作按钮和分步 walkthrough,非开发人员也能上手点
「这东西该长什么样?」同一路由上多个风格迥异的 UI 变体,URL 参数切换

共同规则:不写测试、不做打磨、默认无持久化、一条命令起跑。

所以卡住时先问自己卡在哪:逻辑想不通,还是样子定不了?然后明说:「/prototype,问题是〈状态模型在 X 情况下对不对〉。」问题越具体,原型越有用。

6.3 架构扫描:产物是一份 HTML 报告,grilling 是内置的

Spec #3 的起点不是需求,而是扫描:浏览器侧约 2860 行代码是全仓改动最密的地方却几乎零测试。评审出 5 个深化候选,人选「候选 1 + 2 + 5」,随后 grilling 定顺序、拆票落地。

扫描 → 人选 → 追问,这个节奏是对的。

技能行为:生成一份自包含 HTML 报告(写到系统临时目录并自动打开),每个候选有 before/after 可视化图、推荐强度徽章(Strong / Worth exploring / Speculative)和一个 Top recommendation。

选定候选后,技能自己进入 grilling 循环,并内联调用 domain-modeling 落术语和 ADR。这三件事不是你要串起来的动作。

自查方法:如果它没给你 HTML 报告而只是发了一坨文字,说明它没按技能执行,可以要求重跑。

6.4 深模块词汇:人与智能体讨论架构的通用语言

codebase-design 提供一套共享词汇:module、interface、depth、seam、adapter、leverage、locality,外加两个判定工具——「删除测试」(删掉这个 module,多少知识跟着消失?)与「interface 即测试面」。

三种操作在这个仓库里反复出现,每一种都有可验证的收益:

深化(deepening):把散落的职责收进 interface 后面

起点是 server.js 一个 1181 行的大杂烩。第一轮架构评审后,一个 commit 拆出 render / track / agent-api / http 四个模块(+1280/−967),server.js 只剩 182 行装配层。

随后「条目存储」收编数据访问与身份派生——因为「miss 怎么办」的策略曾在两个路由里出现两种不一致实现,导致「后台写入后新条目首访详情页必 404」这个真 bug。职责散落不只是不好看,它会直接生产 bug。

收窄(narrowing):interface 只做最小并集

demo-cloud 从 55 行收窄到 13 行,只实现 seam 实际消费的子集;浏览器数据面的方法集是「现有调用点去重后的最小并集」,按领域语义命名(publish 而非 insert)。

ADR-0005 明确拒绝了「按 SDK 形状命名透传」:浅封装只搬不解耦。

出 IIFE:浏览器纯逻辑变成可测模块

把两个 IIFE 里锁着的纯逻辑抽成挂 window 命名空间的新模块,原文件退为「接线壳」——只剩页面守卫、adapter 装配注入、DOM 事件接线。存储/时钟/随机源/发送通道全部经参数注入,Node 测试因此第一次触达浏览器侧算法。

关键洞察

词汇统一之后,架构讨论的成本骤降。人在 issue、commit、会话里说「深化」「收窄」「接线壳」「seam」,智能体一字不差地理解;反过来智能体报告里的「Middle Man 残留」「推导回漏」,人也立刻能定位问题性质。

与 GLOSSARY 的分工不要混:GLOSSARY 定义「业务领域的词」(条目、托管页、登录态门控),随产品演化;codebase-design 定义「讨论结构的词」(深度、seam、leverage),是整套技能体系的常量——所以它不需要写进仓库文档,装上技能就有了。

6.5 其余五个

技能什么时候用关键动作
/triage别人往你仓库提了 raw 的 issue状态机 needs-triage → needs-info / ready-for-agent / ready-for-human / wontfix,每个 issue 同时挂一个分类(bug/enhancement)和一个状态;评论必须带 AI 生成声明。自己拆的票不要过 triage
/wayfinder大到看不清全貌在 tracker 上建「决策地图」,每张票解决一个决策(不是交付物),推进到路线清晰后交接给 /to-spec。小而明确的功能别用它,它慢而重
pr智能体写 PR 时自动用三段式:Summary(一张让改动一目了然的图)、Evidence(before/after 对照)、Merge Danger(单向门还是双向门 + 爆炸半径)。评审别人写的 PR 时,这三段就是验收标准
handoff跨会话/目录/人把当前会话浓缩成交接文档。四种场景:新 harness、新目录、给同事、阶段中途分叉侧任务。原型工作流常靠它桥接:/handoff 出去 → 新会话 /prototype → /handoff 带结论回来
research需要一手资料结论派后台智能体对官方文档/源码/规范查证,结论写成带引用的 Markdown 留在仓库。研究成果是 /grill-with-docs 的输入材料
别混两种来源

「自己拆的活」与「外面来的信」必须分开。混用会导致两种后果:自己拆的票被要求走 triage 流程(浪费),外部 issue 被直接当工单开工(失控)。

07

上下文卫生:smart zone 与阶段边界

模型有一个 smart zone——约 150k tokens(顶尖模型)。窗口内它还能敏锐推理,超出后质量下降。

三条规则:

  1. 规划三步(grill → spec → 拆票)保持在同一个未压缩的窗口里;
  2. 接近 smart zone 就在阶段边界 /compact,别硬撑;
  3. 每张工单 /clear 之后开新窗口。

阶段边界有五个选项,选择顺序值得记:

选项什么时候用
Continue(默认)下一阶段需要这一阶段作为 primary source。先问「能不能在这个会话继续」
/clear后面用不到这里的上下文
/handoff要换目录或换人
子智能体范围清晰的小任务
/compact保底

grilling → implementation 是标准的「不该继续」:实现想要的是逐字的推理链,不是它的摘要。反过来,grilling → spec → 拆票 必须继续,因为它们共用同一棵树。

08

人的角色:极简指令、高度授权、亲自验收

技能决定流程的形状,人决定流程的方向。这一节是整份实践里最不该改的部分。

约 179 条人类指令呈现高度一致的风格:

模式实例频度
批量授权「都按(你)推荐的来」「按推荐的来」等变体,共 9 次最高频
编号式拍板「候选 1 + 2 + 5」「候选 1+2」「先做候选 1」高频
收尾指令「git commit」×6、「关闭 #10」「合并到 main 并推送」高频
短句硬约束「首页有『分享』按钮,详情页也应该有。复用首页分享按钮的组件和逻辑,不要新写一份。」中频
事实追问「为什么之前实现 issue 时都没有创建 PR」「为什么出现 Tool interrupted」中频

最关键的一条:人会读代码验收。

我看了一下代码,你没有实现刚才的功能,只是修改了注释。

这次抓包逼着智能体起真实服务器端到端自证。AI 原生开发里,「信任但验证」不是口号,是日常动作。

人还承担「工作流教师」的角色。ticket #12 收尾时智能体自发建了仓库史上第一个 PR(PR #13),人没有默默接受,而是追问:「为什么这里创建了 PR #13?要先合并 PR #13 才能关闭 #12?PR 与 issue 是什么关系?」——弄懂之后,PR 工作流才被纳入团队惯例。

必须区分两类「人的动作」:

必须由人做本不该由人兜
拆票粒度、上线决策、读代码、「为什么」的追问、只有你知道的业务决策防止智能体「没确认就动手」(grilling 内建)、提醒它「先定 seam」(tdd 与 implement 内建)

右边这列如果频繁需要你出手,说明技能没装好或没被正确调用,该修配置,而不是把人训练成监工。

一句话总结人的定位:人是编辑,不是作者。编辑不写段落,但决定写什么、砍什么、以及每一句是否站得住。

09

反模式清单

从这套实践的反面看,什么会毁掉整条流水线:

症状根因对策
智能体反复问仓库里已有的信息上下文四层缺失或过期补 CLAUDE.md / GLOSSARY / ADR,而不是反复解释
术语表越写越像规格,评审老是被带偏把 interface 签名、实现决策写进 GLOSSARY词条只写「是什么/不是什么/分界」;签名归代码与 ADR
一个会话干到最后越来越糊涂规划与实现混在同一窗口阶段边界 /clear,一票一窗口
测试很多,一重构全红测试耦合实现细节只测 interface;seam 事先约定
测试永远绿,bug 照旧断言用和代码相同的方式重算期望值期望值来自独立事实来源
评审只挑格式,抓不到契约漏洞只有一条轴,或没有 fixed point双轴并行;固定点先钉住;Standards 用成文标准 + 坏味道基线
合并老是撞冲突实现者没有先合回集成分支 tip修流程,不是加 --no-ff
同一个 bug 修三次没有回归测试先造会变红的命令;修复必须带回归测试
复盘产出「下次注意」没有区分机械性违规与判断题机械性 → 确定性检查;判断题 → CODING_STANDARDS.md
顺手把 quirk 一起修了重构与修 bug 没分离表征测试先钉现状,修复另起 commit 单独评审
所有工单都等「打完标签」才动工把 triage 当成开工闸门自己拆的票发布即动工;triage 只处理外部 issue
CLAUDE.md 越写越长把所有规范都堆在会被每个智能体读到的文件里CLAUDE.md 只留导航指针 + 推断不出的事实;标准压到评审侧
10

适用边界:这套实践是有土壤的

它在特定条件上长成:单人维护者 + 全栈小应用 + 零框架零构建 + 测试成本低。移植前自查四项:

  1. 维护者愿意当「编辑」而不是「作者」。指令风格、验收习惯、「为什么」的追问,都是主动技能,不是装上插件就有。
  2. 仓库本身简单。单进程、无构建、模块边界清晰,智能体一次能看全。大型多包仓库要先做到「仓库即上下文」——多 context 的 GLOSSARY-MAP.md 布局就是为此准备的。
  3. 反馈环足够快。168 个测试 3.5 秒跑完、preflight 一键自检,红绿循环和双轴评审的开销才低到「每次都做」。反馈环慢的项目,先投资测试基建,否则诊断技能的第一阶段就卡住。
  4. 技能版本跟得上。implement-spec、pr、retro 是 1.3.0 才加入的,版本太旧会缺技能。技能会随版本迭代,标签、模板、阶段边界都可能变。

最后一条原则,比这份文档里任何一句都重要:

技能原文只有几千字,就在插件的 SKILL.md 里。任何指南(包括本文)与 SKILL.md 冲突时,以 SKILL.md 为准。

这不是免责声明,是使用方法。当你读到一段「最佳实践」觉得别扭时,最快的验证方式是打开对应技能的 SKILL.md——顺带还能分清哪些是规定、哪些只是某个项目的习惯。

11

启动清单

照着敲就行。前提:一个 git 仓库(有没有代码都行)和 Claude Code。

#动作命令 / 检查点
0安装插件并确认版本claude plugin install mattpocock-skills@claude-plugins-official
1仓库根目录跑 setup,全程接受推荐/setup-matt-pocock-skills。完事检查:CLAUDE.md 有 ## Agent skills 区块,docs/agents/ 下有 issue-tracker.md 与 domain.md。没 GitHub 就选本地 markdown
2写一份「智能体导向」的 CLAUDE.md常用命令、架构要点、只有线上才暴露的坑、部署约束。不写代码能推断的东西。GLOSSARY 只写术语
3想法先被追问,别先动手/grill-with-docs 我想做〈一句话想法〉。每问带推荐答案,回「是」即接受;它问你能查的事实,让它自己查
4多会话工程:发 spec,再拆票/to-spec 然后 /to-tickets。检查七段齐全(重点看 Out of Scope);嫌票碎就说「4/5/6 合并成一票」。小工程跳过这步
5可选:让技能先摸一遍架构/improve-codebase-architecture。等 HTML 报告,选一个候选,直接回答追问
6/clear,每张票一个全新会话实现/implement #3。开工先对齐测试 seam
7手动复跑评审要给固定点/code-review,fixed point 是 main
8合并、关闭工单,收工前复盘/retro。期待 lint 规则、导航指针、CI 护栏这类具体产物
9出 bug 别硬修/diagnosing-bugs 〈症状〉。先要一条「会变红的命令」,修复必须带回归测试
?不确定用哪个技能/ask-matt 我现在〈处境〉,该用哪个技能?
人保留三件事

拍板、验收、追问。推荐答案可以批量接受;拆票粒度、上线决策由人定;代码要自己读,「为什么」要自己问。

—

附:可核实的东西

  • 项目:wang-junjian/research-share — 50 个 commit、12 个 issue(全部 CLOSED)、5 篇 ADR、24 条术语、168 个测试
  • 技能体系:mattpocock/skills v1.3.1,20 个工程技能 + 7 个生产力技能
  • 关键规则出处:skills/engineering/to-spec/SKILL.md(七段模板)、tdd/SKILL.md(pre-agreed seams)、code-review/SKILL.md(fixed point、坏味道基线)、implement-spec/SKILL.md(frontier、先合回 tip)、retro/SKILL.md(七类改进、机械性 → 确定性检查)、.agents/invocation.md(两种技能与调用边界)
  • 会话证据:~/.claude/projects/-Users-junjian-GitHub-wang-junjian-research-share/*.jsonl(30 份,69MB,约 179 条人类指令;本文引语均为原文)

本文只保留实战做法与可复用判断,不包含对技能原文的逐条校订。