Lesson 0011 · Engineering · 只有人能启动(user-invoked)· 流程课

implement:主流程的施工段,从票到 commit

想象这个场景:需求文档(spec)已经发到了工单系统,to-tickets 把活拆成了几张 端到端的工作票,每张票都标清楚了谁挡着谁。你挑了一张没有任何挡路者的票, 新开一个干净的会话,把这张票带进去,敲下 /implement。 接下来发生的事,全部写在一个只有五行正文的文件里:照着票把活干完、能用 /tdd 就用 /tdd、按固定节奏跑验证、收尾跑 /code-review、把成果 commit 到当前分支。 这节课把这五行逐句拆开:每一句在调用谁、会改仓库里的什么、 上游必须给它准备好什么、行为不对时该去改哪个文件的哪一段。

1. 它在整个系统里站在哪

0001 把 22 个已发布 skill 分成三层:配置层(跑一次性的初始设置)、编排层 (你手动启动的完整流程,内部拼装纪律层的基本功)、纪律层(被反复调用的基本功)。 implement编排层,而且是主流程(main flow: 一个想法从进门到交付的那条默认路径)上的施工段。 它的人读文档把位置写得很死:主链是 grill-with-docs → to-spec → to-tickets → implement → code-review, implement 是「靠近末尾的构建步骤,就在 review 之前」。

文档里还有一句定性格言,值得背下来:「It is the hands, not the head」 ——它是手,不是脑。规格(spec)已经定稿、接缝(seam,第 5 节细讲)已经约好, implement 负责执行那个计划,而不是重新打开它。 「决定做什么」这件事在上游已经想完了;implement 发现自己在想「到底该不该做这个」, 说明上游欠了债,该退回去补,而不是在施工段现场决策。

同时它也是 0001 讲过的设计规矩「入口薄、纪律厚」的教科书例子: implement 的正文故意只有五行(和 grill-megrill-with-docs 同一类写法),真正厚的纪律全部住在它调用的 tddcode-review 里。想改行为时, 先打开被它调用的那个厚文件——这条原则会贯穿本课第 11 节的微调表。

地图:0001 系统地图(三层分法、主流程、「入口薄、纪律厚」)· 定位置:docs/engineering/implement.md(主链引文、「hands not the head」)· 上游的一课:0003 grilling

2. 调用方式:为什么只能你来敲

implement 是 user-invoked 的:只有人能启动它,AI 不会、也不被允许自己伸手。 这不是一句口头约定,而是两道写在文件里的锁:

人读文档把话说得很直白:「You invoke this by typing /implement — the agent won't reach for it on its own.」(你敲 /implement 来启动它; agent 不会自己去够它。)

为什么要上两道锁 implement 是整条主流程里真实副作用最重的一站:它写业务代码、写测试, 最后还在你的当前分支上制造 git commit。开工时机本质上是人的判断—— 这张票是不是已经没人挡着了(frontier,第 4 节)、当前会话上下文干不干净(第 9 节)、 你想不想现在就动代码——这些都不该由模型看着气氛决定。 对比一下:tddcode-review 是 model-invoked (人和 AI 都能启动),所以 implement 的正文可以用一句自然语言把它们拉进来干活, 而它自己则被锁在「只听得懂人话」的位置上。

典型的启动姿势(来自 ask-matt 的主流程描述):多会话构建时,每张票 各开一个新会话,把那张票带进去再敲 /implement; 需求小到一张票装得下时,也可以在 grill / spec 之后直接在同一个会话里敲。 两种姿势的区别只在上下文,不在 skill 本身——五行正文一视同仁。

两道锁:skills/engineering/implement/SKILL.md 的 frontmatter · skills/engineering/implement/agents/openai.yaml · 「agent won't reach for it」:docs/engineering/implement.md 的 When to reach for it 一节 · 启动姿势:ask-matt/SKILL.md 主流程第 3 步

3. 五行正文,逐句解剖

implement/SKILL.md 去掉 frontmatter 之后,全部正文就是五行。 它短到可以整段背下来,但每一行都挂着一套厚纪律。逐句解剖:

# 原文 它在说什么 背后挂着的厚文件
1 Implement the work described by the user in the spec or tickets. 工作来源只有两类:一份 spec,或一组票。「described by the user」是重点——做什么已经由你定好了,implement 不重新决定做什么 输入由 to-spec / to-tickets / triage 在上游造好(第 4 节)
2 Use /tdd where possible, at pre-agreed seams. 用自然语言调用 tdd 来写;测试只落在事先约定好的接缝上(第 5、6 节) tdd/SKILL.md 全文 + tests.md + mocking.md
3 Run typechecking regularly, single test files regularly, and the full test suite once at the end. 三档验证节奏:类型检查常跑、单个测试文件常跑、全量测试套件只在收尾跑一次(第 7 节) 无(这是 implement 自己的节奏规定)
4 Once done, use /code-review to review the work. 干完之后,调用 code-review 审查这堆改动——审查发生在 commit 之前(第 8 节) code-review/SKILL.md 的双轴子代理流程
5 Commit your work to the current branch. 把成果提交到当前分支。这是 implement 唯一的落地动作(第 8 节)

两个读原文时才注意得到的细节:

五行原文:skills/engineering/implement/SKILL.md(全文 15 行,含 frontmatter)· 「one red-green slice at a time」:ask-matt/SKILL.md 主流程第 3 步

4. 开工条件:什么算可以 implement 的输入

第 1 行说输入是「a spec or set of tickets」。在整条系统里,能合法喂给 implement 的东西有四条来路,外加一个例外:

来路 喂给 implement 的是什么 出处
to-spec 一份发到工单系统的 spec。需求小到一张票装得下时,可以跳过 to-tickets,让 implement 直接对着 spec 干 0001 的弹性表:「to-spec 之后甚至可以跳过 to-tickets」
to-tickets 一组 tracer-bullet 票(曳光弹式的垂直切片:每张票都是窄而完整、端到端可验证的一刀),每张票声明自己的 blocking edges(阻塞边:哪些票必须先完成它才能开工)。implement 只拿 frontier(前沿:所有阻塞者都已完成的票) to-tickets/SKILL.md 结尾:「Work the frontier one ticket at a time with /implement」
triage 分拣完、被标成 agent-ready(可以直接交给 agent 做)的外来 issue——别人报的 bug、提的需求 ask-matt 的 on-ramp 一节:triage「produces agent-ready issues, which /implement later picks up」
wayfinder(例外) 决策地图上的雾散了,但默认直接 implement——先回 to-spec 把决策折叠成可施工的计划;只有当活真的小,才允许直接进 implement ask-matt:「go straight to /implement only when the effort turned out genuinely small」

反过来说,下面几种状态不该/implement

它不会替你把关输入 注意一个作者级的细节:implement 的五行正文里没有任何「先检查输入合不合法」的句子—— 没有「先确认这是 frontier 票」,也没有「先确认 spec 里有接缝」。 把关发生在上游和路由层:to-tickets 规定了 frontier 的拿票顺序, ask-matt 规定了什么状态该走哪条 flow,而「现在该不该敲 /implement」最终是人的决定 (第 2 节的两道锁把启动权留给了你)。 所以「implement 对着一张还被人挡着的票干了一下午」这种事故,改的不是 implement 的正文, 而是你的开工习惯或上游的拆票。

四种输入:to-tickets/SKILL.md(frontier、blocking edges、结尾一行)· ask-matt/SKILL.md(triage 的 on-ramp、wayfinder 的交接)· 跳过 tickets 的情形:0001 系统地图的弹性组合一节

5. 接缝从哪来:pre-agreed 的含义

第 2 行的后半句「at pre-agreed seams」是整个 implement 的承重墙。先回顾定义 (0005 已经精确定义过):seam(接缝)是不用改那处代码、就能改变行为的位置, 也就是模块接口所在的位置——测试就落在接缝上,永远不捅进内部。 「pre-agreed」(事先约好的)意味着:接缝不是 implement 在施工中途发明的, 而是上游定好、被带进来的

这条约定链跨了三个 skill,值得逐环看:

  1. to-spec 画接缝草图。它的第 2 步:在写 spec 正文之前, 先勾出要在这个功能上测试的接缝——优先复用已有接缝、能用多高的接缝就用多高的 (越靠外的接口越耐用)、新接缝越少越好(理想数量是一个), 然后和你确认这些接缝符合预期。接缝从此就是 spec 的一部分。
  2. tdd 守住接缝。它的纪律写得很硬:「Test only at pre-agreed seams」 ——写任何测试之前,先把要测的接缝写下来并跟你确认; 没有确认过的接缝,一个测试也不写。接缝还决定了测试投入的落点: 你不可能什么都测,事先约接缝就是让测试火力落在关键路径和复杂逻辑上。
  3. implement 只管使用。人读文档的原话:「It doesn't invent seams mid-build; it uses the ones already picked.」(它不在构建中途发明接缝; 它使用已经选好的那些。)并且解释了为什么这能让实现保持诚实: 测试瞄准的是耐用的东西,所以接缝底下的代码可以挪动, 而测试不用跟着挪。
接缝这套词的权威出处不在本课 seam、interface、adapter 这套模块形状词汇的单一权威出处是 codebase-design(0005 讲透了)。implement 自己不定义这些词, 它通过 tdd 踩在那块词汇地板上——tdd 的「接缝就是测试的落点」和 codebase-design 的「接口就是测试面」是同一件事的两种说法。 所以「接缝到底该画在哪」这种争论,去 0005 找词汇和原则,别在 implement 的会话里现场发明。

画接缝:to-spec/SKILL.md 第 2 步 · 守接缝:tdd/SKILL.md 的 Seams 一节 · 「doesn't invent seams mid-build」:docs/engineering/implement.md 的 Pre-agreed seams 一节 · 词汇出处:Lesson 0005 codebase-design

6. 内部循环:prose 调用 tdd

第 2 行的「Use /tdd」是一个 prose 调用(散文调用): skill 之间的依赖用一句自然语言表达(「Run the /tdd skill」这类写法), 而不是用文件路径深链——0001 讲过这条仓库级的依赖规则。 它能成立,是因为 tdd 是 model-invoked 的:agent 读到这句话,就会把 tdd/SKILL.md 的全文加载进来,按它的纪律干活。 所以 implement 在施工期的真实行为,= 五行正文 + tdd 全文。 后者才是「厚」的部分。

implement 从 tdd 那里继承来的施工纪律,一次循环长这样:

一个红绿循环(red-green cycle)
  │
  ├─ Red:在约定好的那条接缝上,先写一个会失败的测试
  │        (测试通过公共接口观察行为,不碰内部实现)
  │
  ├─ Green:只写刚好够让它通过的最小实现
  │        (不预判未来的测试,不加投机性的功能)
  │
  └─ 下一个切片(slice):一条接缝、一个测试、一个最小实现,循环往复
           每个测试都是一颗曳光弹(tracer bullet),根据上一轮学到的东西调整

tdd 还有两个 sibling 文件,implement 间接继承:tests.md (好测试与坏测试的对照样例——好测试测「用户能用有效购物车结账」这种行为, 坏测试测「checkout 调用了 paymentService.process」这种内部细节)和 mocking.md(只在系统边界 mock:外部 API、数据库、时间、文件系统; 不 mock 自己的类和内部协作者)。这些纪律的全文都在 tdd 目录里, 所以「测试写得不对」永远去改那边,而不是改 implement 的第 2 行—— 第 11 节的微调表还会回到这个分工。

继承的纪律:tdd/SKILL.md(Rules of the loop、Seams、Anti-patterns)· 样例与 mock 边界:tdd/tests.mdtdd/mocking.md · prose 调用规则:0001 系统地图的依赖规则一节

7. 验证节奏:typecheck 常跑、单文件常跑、全量一次

第 3 行是 implement 正文里唯一一条转包给别人的规定: 「Run typechecking regularly, single test files regularly, and the full test suite once at the end.」三档验证,各跑各的频率:

验证档位 频率 它给你什么信号
Typechecking(类型检查) regularly(经常) 最便宜的全仓库信号:类型错了立刻知道,不用等任何测试跑完
Single test files(单个测试文件) regularly(经常) 当前切片相关的那几个测试文件,随红绿循环反复跑——循环的反馈必须便宜,才能保持 tight(紧)
Full test suite(全量测试套件) once at the end(收尾时一次) 最贵的信号,留到最后当整体验收:整张票合在一起、和仓库其余部分放在一起,是不是仍然全绿

人读文档用一句话概括了这个设计意图:「it keeps the loop tight」——让循环保持紧。 施工期的每一秒都在红绿循环里,反馈越便宜,循环转得越快; 全量套件跑得慢,塞进循环里只会把循环拖垮,所以它只在收尾出现一次。

两个作者级的读法:

三档原文:implement/SKILL.md 第 3 行 · 「keeps the loop tight」:docs/engineering/implement.md 的 Pre-agreed seams 一节末尾

8. 收尾:code-review 双轴审查,然后 commit

第 4、5 两行是 implement 的闭幕式,顺序固定:先审查,后提交。 ask-matt 的描述把这个顺序钉死了:implement「closes out by running /code-review, a two-axis review (Standards + Spec) of the diff, before committing」 (收尾时运行 code-review——对 diff 做 Standards + Spec 双轴审查——然后再提交)。

8.1 第 4 行:code-review 审什么

code-review 也是 model-invoked 的,所以第 4 行又是一个 prose 调用。 它对「当前分支上的这堆改动相对一个固定起点的 diff」做两条互相独立的轴:

两条轴由两个并行的子代理分别跑,互不污染上下文,然后并排报告、 故意不合并排名——因为「符合所有规范但做错了东西」和「做对了东西但破坏了约定」 是两种不同的事故,不能让一条轴掩盖另一条。 对 implement 来说,Spec 轴的 spec 来源天然就是你开工时带进去的那张票或那份 spec—— 第 4 行把「做没做对」的终审权交给了它。 code-review 默认只产报告、不改代码;按报告修不修、怎么修, 是报告出来之后的事(0013 会讲透这条 skill)。

8.2 第 5 行:commit 到哪、不做什么

「Commit your work to the current branch.」——落地动作只有一个: 在当前分支上制造 commit。注意三个「没写」: 没写新建分支(所以开工前人在哪个分支,commit 就落在哪), 没写发 PR,没写合并。0001 的副作用表里,implement 的「下一步」一栏写的是 「拿下一张没被挡住的票继续 implement;或人工合并、发 PR」——合并和发 PR 是 的事,不是这个 skill 的动作。

闭幕式在整条链里的位置 docs 给的主链是 grill-with-docs → to-spec → to-tickets → implement → code-review, 链上 code-review 写在 implement 后面,但别误读成两个独立步骤—— 第 4 行表明 review 是 implement 闭幕式的内部一环: 全量测试过一次 → code-review 双轴审查 → 按报告处理 → commit。 tdd 那句「重构属于 review 阶段」也在这里闭环:红绿循环里忍住没做的整理, review 报告会替你点名。闭幕式走完了,这张票才算完。

双轴与子代理:code-review/SKILL.md(Why two axes、Process)· 顺序与「人工合并、发 PR」:ask-matt/SKILL.md 主流程第 3 步、0001 系统地图的副作用表 · 主链引文:docs/engineering/implement.md 的 Where it fits 一节

9. 会话卫生:一张票,一个干净会话

implement 是主流程上上下文纪律最苛刻的一站。ask-matt 专门有一节 「Context hygiene」(上下文卫生)讲这件事,规则分两半:

为什么票与票之间要清空?两个来自一手材料的理由:

  1. 票就是为「一个干净窗口」设计的。to-tickets 的切片规则写明: 每张票的大小要「fit in a single fresh context window」(装得进一个全新的上下文窗口)。 票是自含的——标题、要交付的端到端行为、验收标准、被谁挡着——所以新会话只需要这张票, 不需要前面所有的闲聊。
  2. 旧上下文是有成本的。ask-matt 给出「smart zone」的概念: 大约 120k token 以内模型推理依然锋利的区间。一个会话逼近这个区间时, 正确的动作是 /handoff(把对话压缩成一个 markdown 文件, 新开会话引用它继续),而不是在变钝的窗口里硬撑——0006 会专讲这座跨会话的桥。

例外也写在 ask-matt 里:需求小到一个会话能做完时(主流程第 3 步的 No 分支), 可以在 grill / spec 之后「right here, in the same context window」直接敲 /implement——因为这种情况没有票与票的边界,卫生规则不适用。 判断标准不是「过了多久」,而是「是不是要开始下一张票」。

卫生规则:ask-matt/SKILL.md 的 Context hygiene 一节 · 票的尺寸规则:to-tickets/SKILL.md 的 vertical-slice-rules · 跨会话的桥:Lesson 0006 handoff

10. 依赖关系图:谁喂它、它拉谁、谁接它

                    上游(喂给它输入)
 grill-with-docs → to-spec ──spec──────────────┐
                       │                       │
                    to-tickets ──frontier 票───┤
                                               ▼
 triage ──agent-ready 的外来 issue ──────►  implement ──► commit(当前分支)
                                               │  │
 wayfinder ──(仅活真的小)────────────────────┘  │ prose 调用
                                                  ▼
                                    tdd(施工纪律:红绿循环、守接缝)
                                       │  读但不写:CONTEXT.md / ADR
                                       │  词汇地板:codebase-design
                                                  ▼
                                    code-review(Standards + Spec 双轴,只产报告)
                                                  ▼
                            下一张 frontier 票(新会话)/ 人工合并、发 PR
方向 Skill / 文件 关系
喂它 to-spec 产出 spec,并在第 2 步约好测试接缝——implement 第 1、2 行的两个前提都由它造
喂它 to-tickets 把 spec 拆成带 blocking edges 的票,发布到工单系统;结尾指定「Work the frontier one ticket at a time with /implement」
喂它 triage 分拣外来 issue,产出 agent-ready 的 issue 交给 implement;注意:to-tickets 拆出来的票不要再过 triage
喂它(例外) wayfinder 默认交接给 to-spec;只有活真的小才直接进 implement
它拉进来 tdd 第 2 行 prose 调用;红绿循环、接缝纪律、好测试标准全文在 tdd 目录
它拉进来 code-review 第 4 行 prose 调用;双轴审查,commit 之前跑
词汇地板 codebase-design seam / interface 这套词的权威出处;implement 经 tdd 踩在这块地板上,自己不定义词
读但不写 CONTEXT.md / ADR 经 tdd 的规矩:命名对齐领域语言、尊重动到的区域里的决策记录
前置假设 setup-matt-pocock-skills implement 自己不查配置,但它的上游(to-spec / to-tickets / triage)都假定 setup 跑过、工单系统已配置——输入是沿着这条链传下来的

全图:0001 系统地图 · 路由:ask-matt/SKILL.md · 相邻课:0009 to-spec · 0010 to-tickets · 0012 tdd · 0013 code-review · 0014 triage · 0016 wayfinder

11. 副作用清单与微调入口

11.1 它会改什么、不会改什么

对象 会不会动 说明
业务代码 写 / 改 第 1 行的本职:把 spec 或票描述的活干出来
测试文件 写 / 改 经 tdd 写在约定好的接缝上;红绿循环一次一个切片
git 制造 commit 第 5 行:落在当前分支上;0001 的副作用表也把 commit 列为 implement 的标志性产物
工单系统(issue tracker) 正文没写 五行正文没有任何「改票状态 / 勾验收标准 / 写评论」的句子——别默认它会做;想要就是你的微调(见 11.2)
分支 / PR 正文没写 不开新分支、不发 PR;0001 把「人工合并、发 PR」列在 implement 之后的「下一步」,那是人的动作
CONTEXT.md / ADR 只读不写 tdd 要求读它们对齐语言;写它们是 domain-modeling / grill-with-docs 那条线的事
HTML 报告 不产 那是 improve-codebase-architecture 的产物,跟 implement 无关

11.2 行为不对时,去改哪个文件的哪一段

总原则还是 0001 那条:入口薄、纪律厚——implement 正文只有五行, 想改行为先想清楚「这个行为到底住在哪个文件里」。症状对号入座:

症状 先查 / 先改 不要误改
没跑 review 就直接 commit 了 implement/SKILL.md 第 4 行原文还在不在;并确认 agent 当时真的加载了这个 skill(0001 已经把这条列为典型症状) code-review 的子代理提示词(那是审得深不深的问题,不是跑没跑的问题)
测试写在了没约定的接缝上,或施工中途发明新接缝 第 2 行的「at pre-agreed seams」+ tdd/SKILL.md 的 Seams 一节;再往上查 to-spec 第 2 步有没有真的画接缝、和你确认 implement 的第 1 行(输入来源没错,错的是接缝纪律)
一下午没跑过类型检查,或每改一行就全量跑一遍 implement/SKILL.md 第 3 行的节奏句——这是五行里唯一归 implement 自己管的规定 tdd 的红绿循环细则(循环纪律没错,错的是验证节奏)
红绿循环里夹带重构,越改越大 tdd/SKILL.md 的「Refactoring is not part of the loop」 implement 的第 2 行(它只是把 tdd 拉进来,循环规矩在 tdd 那边)
测试在 mock 自己的类、断言内部细节 tdd/tests.md 的对照样例 + tdd/mocking.md 的边界清单 code-review 的坏味基线(review 能抓,但纪律源头在 tdd)
review 审得太浅 / 双轴被合并排名了 code-review/SKILL.md 的 Process 和 Why two axes implement 的第 4 行(它只负责「要跑」,审法在 code-review 那边)
commit 落到了错误的分支,或你想要分支策略 / 自动发 PR implement/SKILL.md 第 5 行——正文就是唯一规定,想加策略就改这里(先想清楚:这是给所有项目用的共享 skill) git 配置或 CI(症状在 skill 行为层,不在工具层)
希望它做完顺手把票勾掉 / 改票状态 正文没写这件事——在 implement/SKILL.md 加一行就是你的定制;注意本地票和远程 tracker 的写法不同,可参考 to-tickets 对两种形态的区分 to-tickets 的票模板(模板没错,是 implement 的动作清单里没有这条)
AI 自作主张启动了 implement 两道锁是否被改过:SKILL.md frontmatter 的 disable-model-invocationagents/openai.yamlallow_implicit_invocation description 字段的措辞(它是给人看的说明,不是锁本身)
反过来:你想让模型能隐式启动它 改上述两处锁——但先想清楚:implement 会制造 commit,启动权交出去意味着模型可以自己决定什么时候动你的分支 plugin.json(它本来就已发布,发布状态没错)

微调总原则:0001 系统地图的设计规矩与典型症状 · 被调用的厚文件:tdd/SKILL.mdcode-review/SKILL.md · 薄入口本体:implement/SKILL.md

12. 检索练习

先别往回翻表,凭记忆答。选项的长度刻意对齐,不会从版式泄题。答错的题号回到对应小节核对原文。

自测(立即反馈)

1. implement 的启动方式是?
2. 「pre-agreed seams」的接缝在哪一步被定下来?
3. 按 implement 的验证节奏,全量测试套件跑几次?
4. 多会话构建中,两张票之间的上下文该怎么处理?
5. implement 的正文用 prose 调用了哪两个 model-invoked skill?
6. implement 闭幕式(收尾)的固定顺序是?
7. 想改「测试该怎么写」的纪律(mock 边界、红绿规则),该编辑哪里?
8. 按一手材料,implement 明文规定的持久副作用是?
额外提取练习(无选项) 合上本页,默写 implement 的五行正文(顺序也算分:输入 → tdd → 验证节奏 → review → commit), 再给每一行写一句「它调用了谁 / 改错了去哪修」。 然后回答:你的当前项目如果现在敲 /implement,合法输入在哪—— 是一份 spec、一组 frontier 票,还是根本还不该敲?

13. 下一课与一手材料

本课主一手材料(请打开原文读,不要只背本页摘要):

推荐首先精读:implement/SKILL.md 本身—— 它是全仓库「入口薄、纪律厚」最极端的样本,15 行里藏着整套主流程的闭幕式。

速查页(本课同步): reference/implement.html

导航: 上一课 0010 to-tickets(票是怎么拆出来、怎么发布到工单系统的)。 总览仍回 0001 系统地图

建议下一课(0012): 0012 tdd——implement 第 2 行拉进来的那台发动机。 本课你只看到了「红绿循环、守接缝、重构留给 review」的轮廓; 下一课把 tdd 的全文、tests.md 的好/坏测试样例、mocking.md 的边界纪律讲透。 之后 0013 code-review 接着讲闭幕式上的双轴审查。

老师就在会话里。 对本课任何一处有疑问——比如「where possible」的例外边界、frontier 票和人肉的先后顺序、 全量测试到底该在 code-review 前还是后、两道锁改了会有什么连锁反应——直接在对话里问。 回答会回到 implement/SKILL.mdtdd/SKILL.mdcode-review/SKILL.mdask-matt/SKILL.md 的原文,不会临场编造。 做完检索练习后,回复「练习结果 / 哪里卡住 / 开 0012 或先补 0010」,我们安排下一课。