想象这个场景:需求文档(spec)已经发到了工单系统,to-tickets 把活拆成了几张
端到端的工作票,每张票都标清楚了谁挡着谁。你挑了一张没有任何挡路者的票,
新开一个干净的会话,把这张票带进去,敲下 /implement。
接下来发生的事,全部写在一个只有五行正文的文件里:照着票把活干完、能用
/tdd 就用 /tdd、按固定节奏跑验证、收尾跑
/code-review、把成果 commit 到当前分支。
这节课把这五行逐句拆开:每一句在调用谁、会改仓库里的什么、
上游必须给它准备好什么、行为不对时该去改哪个文件的哪一段。
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-me、
grill-with-docs 同一类写法),真正厚的纪律全部住在它调用的
tdd 和 code-review 里。想改行为时,
先打开被它调用的那个厚文件——这条原则会贯穿本课第 11 节的微调表。
地图:0001 系统地图(三层分法、主流程、「入口薄、纪律厚」)· 定位置:docs/engineering/implement.md(主链引文、「hands not the head」)· 上游的一课:0003 grilling
implement 是 user-invoked 的:只有人能启动它,AI 不会、也不被允许自己伸手。
这不是一句口头约定,而是两道写在文件里的锁:
SKILL.md 的 frontmatter(文件头部那段元数据):
disable-model-invocation: true——模型被禁止把 implement 当作
「看着合适就自己上」的候选。
agents/openai.yaml:
policy.allow_implicit_invocation: false——不允许隐式调用,
也就是不允许 agent 在没有明确指令的情况下替你启动它。
人读文档把话说得很直白:「You invoke this by typing /implement —
the agent won't reach for it on its own.」(你敲 /implement 来启动它;
agent 不会自己去够它。)
tdd 和 code-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 步
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 步
第 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:
/grill-with-docs 把想法问清楚(0003 的面试流程)。四种输入:to-tickets/SKILL.md(frontier、blocking edges、结尾一行)· ask-matt/SKILL.md(triage 的 on-ramp、wayfinder 的交接)· 跳过 tickets 的情形:0001 系统地图的弹性组合一节
第 2 行的后半句「at pre-agreed seams」是整个 implement 的承重墙。先回顾定义 (0005 已经精确定义过):seam(接缝)是不用改那处代码、就能改变行为的位置, 也就是模块接口所在的位置——测试就落在接缝上,永远不捅进内部。 「pre-agreed」(事先约好的)意味着:接缝不是 implement 在施工中途发明的, 而是上游定好、被带进来的。
这条约定链跨了三个 skill,值得逐环看:
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
第 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),根据上一轮学到的东西调整
code-review。这就是为什么 implement 的收尾必须是 review(第 8 节):
施工期欠下的整理账,在那里统一清算。
CONTEXT.md
(如果存在),让测试命名和接口用词跟项目的领域语言一致,并尊重要动的区域里的
ADR(架构决策记录)。也就是说 implement 会读这两个文件,
但它自己不写(第 11 节的副作用表会用到这一点)。
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.md、tdd/mocking.md · prose 调用规则:0001 系统地图的依赖规则一节
第 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 一节末尾
第 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 双轴审查——然后再提交)。
code-review 也是 model-invoked 的,所以第 4 行又是一个 prose 调用。
它对「当前分支上的这堆改动相对一个固定起点的 diff」做两条互相独立的轴:
两条轴由两个并行的子代理分别跑,互不污染上下文,然后并排报告、 故意不合并排名——因为「符合所有规范但做错了东西」和「做对了东西但破坏了约定」 是两种不同的事故,不能让一条轴掩盖另一条。 对 implement 来说,Spec 轴的 spec 来源天然就是你开工时带进去的那张票或那份 spec—— 第 4 行把「做没做对」的终审权交给了它。 code-review 默认只产报告、不改代码;按报告修不修、怎么修, 是报告出来之后的事(0013 会讲透这条 skill)。
「Commit your work to the current branch.」——落地动作只有一个: 在当前分支上制造 commit。注意三个「没写」: 没写新建分支(所以开工前人在哪个分支,commit 就落在哪), 没写发 PR,没写合并。0001 的副作用表里,implement 的「下一步」一栏写的是 「拿下一张没被挡住的票继续 implement;或人工合并、发 PR」——合并和发 PR 是 人的事,不是这个 skill 的动作。
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 一节
implement 是主流程上上下文纪律最苛刻的一站。ask-matt 专门有一节 「Context hygiene」(上下文卫生)讲这件事,规则分两半:
/implement 都新开会话,
只带那一张票进去——「clearing context between each one」(票与票之间清空上下文)。
别拖着之前聊了几万字的旧窗口进施工现场。
为什么票与票之间要清空?两个来自一手材料的理由:
/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
上游(喂给它输入)
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
| 对象 | 会不会动 | 说明 |
|---|---|---|
| 业务代码 | 写 / 改 | 第 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 无关 |
总原则还是 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-invocation、agents/openai.yaml 的 allow_implicit_invocation |
description 字段的措辞(它是给人看的说明,不是锁本身) |
| 反过来:你想让模型能隐式启动它 | 改上述两处锁——但先想清楚:implement 会制造 commit,启动权交出去意味着模型可以自己决定什么时候动你的分支 | plugin.json(它本来就已发布,发布状态没错) |
微调总原则:0001 系统地图的设计规矩与典型症状 · 被调用的厚文件:tdd/SKILL.md、code-review/SKILL.md · 薄入口本体:implement/SKILL.md
先别往回翻表,凭记忆答。选项的长度刻意对齐,不会从版式泄题。答错的题号回到对应小节核对原文。
/implement,合法输入在哪——
是一份 spec、一组 frontier 票,还是根本还不该敲?
本课主一手材料(请打开原文读,不要只背本页摘要):
skills/engineering/implement/SKILL.md
—— 本课的主角:frontmatter 的两道锁之一 + 全部五行正文。全文件只有 15 行,值得逐字读。
…/agents/openai.yaml
—— 第二道锁:policy.allow_implicit_invocation: false。
docs/engineering/implement.md
—— 人读叙事版(aihero.dev/skills-implement):
「hands not the head」、pre-agreed seams、主链位置。
推荐首先精读: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 接着讲闭幕式上的双轴审查。
implement/SKILL.md、tdd/SKILL.md、
code-review/SKILL.md、ask-matt/SKILL.md 的原文,不会临场编造。
做完检索练习后,回复「练习结果 / 哪里卡住 / 开 0012 或先补 0010」,我们安排下一课。