Chengshu@skadai · 2026.10.20
RSS
1,580 字 · 366 词 · 约 6 分钟

implement 精读:17 行的技能,怎么用三条契约驱动整次实现

implement 的 SKILL.md 只有 17 行,却承担了整条链上最重的一步。本文走一遍它的真实触发路径,解释它为什么把『测试怎么写』和『代码怎么审』全部推给别的技能,用两次 commit 说明指针的措辞本身就是机制,并列出它刻意不做的五件事:不访谈、不建分支、不做 PR、不碰工单、不把并发塞进自己。

(本文读的是 mattpocock/skills 快照 5beb35b,2026-10-19。引用原文都能按文中路径回仓库核对。这是「逐个技能精读」系列的第八篇,聚焦 implement 一个技能。)

先看实物:十七行

skills/engineering/implement/SKILL.md 全文如下,一字不差:

---
name: implement
description: "Implement a piece of work based on a spec or set of tickets."
disable-model-invocation: true
---

Implement the work described by the user in the spec or tickets.

If the user passes a ticket reference, fetch it from the issue tracker and state its title before starting. If the reference is ambiguous, ask.

Call the Skill tool with "tdd" where possible, at pre-agreed seams.

Run typechecking regularly, single test files regularly, and the full test suite once at the end.

Once done, call the Skill tool with "code-review" to review the work.

Commit your work to the current branch.

真实触发路径:你敲 /implement #42,或者敲 /implement 指着刚讨论完的方案。它先去 tracker 把 #42 拉出来、念一遍标题——这是它唯一一次和你确认「我理解对了没有」。然后:在事先商定的接缝上调 tdd,一个红绿切片一个红绿切片地写;过程里反复 typecheck、反复跑单个测试文件,最后完整跑一遍全部测试;收尾调 code-review;把工作提交到当前分支。

产物是一次 commit。它不关工单、不打勾、不发 PR。

它和「一般技能」的差别:薄技能,强契约

如果你翻过一堆「实现类」技能,会发现它们的形状高度相似:一整页的规则——要写测试、别 mock 内部实现、保持简单、不要过度设计、注意命名、记得跑测试、必要时拆分函数……implement 的做法完全相反:它不内联任何一条「怎么实现」的知识。

测试怎么写、接缝在哪里、什么算好测试、反模式有哪些,全在 tdd 里;两轴怎么分、报告怎么给,全在 code-review 里。implement 只拥有顺序和终点:先接缝测试,再常跑小测试,最后全量,然后审,然后 commit。

这不是「写得短」,这是把技能拆成薄指针 + 厚原语。它的代价是必须保证那两个指针真的会被触发,而这一点在这个仓库里被抬到了很高的规格——见 .agents/invocation.md:

Dependencies are expressed as an explicit instruction to call the Skill tool with the named skill (Call the Skill tool with "grilling"), not deep ../other-skill/FILE.md cross-references, and not a bare /skill-style mention left for the model to interpret. Naming the tool is what gets it fired.

所以那两行读起来像样板,其实整个技能的机制都压在它们的措辞上。仓库为此专门花了两次提交:e48341a 把 Use /tdd where possible 改成 Call the Skill tool with "tdd",提交信息写明理由是 bare /skill-style prose 的命中率低于点名工具;紧接着 04320ee 又把语序调成 Call the Skill tool with "tdd" where possible, at pre-agreed seams.,让祈使句的前两个词就是动作。

指针的措辞就是机制本身。 薄技能之所以稳,是因为它没有第二份关于「怎么写测试」的说法可以和 tdd 漂移:改 tdd 的定义,implement 免费跟着变;两处永不冲突,因为它们只有一处。

它和薄指针的搭档关系

implement 里那个它自己承诺不了的词是 seam(接缝)。它写的是 at pre-agreed seams,但商定接缝这件事不在它内部发生:负责问的是 tdd,而 tdd 拒绝在未确认的接缝上写测试。文档把这层依赖说得很难看:

The “pre-agreed” part matters, and it is also the skill’s weakest point. Nothing inside implement agrees the seams. tdd is the skill that asks, and it refuses to write a test at an unconfirmed seam. So in practice the agreement happens either upstream in the spec, or in the first exchange of the run. If it happens nowhere, the run becomes “just write the code” and nothing warns you.

这就是「薄」的价格:接缝要么在 to-spec 里写成明文,要么在这次 run 的第一次对话里敲定;两处都没有,它就退化成「照我说的写」,而且没有任何提示。

它有意识摒弃了什么

一、摒弃了重新访谈。 文档第一段就把这件事当头等约束:

It never reopens the plan. There is no interview, no clarifying round, no proposal of a different approach. Whatever was settled upstream is the input, and the skill’s whole job is to turn that into a commit.

这也是它和「对着一个空白 agent 说 build this」最本质的区别——后者常常一边建一边改设计。

二、摒弃了分支管理。 Commit your work to the current branch. 它不建分支、不问你想提交到哪里、不做 stash。前提条件写得很直白:先确认你在正确的分支上,它不会替你确认。

三、摒弃了 PR 模式。 没有配置项、没有开关;想开 PR,要么你自己在调用时改口,要么改本地副本。文档承认有人觉得「落地太快、我还没验证」,但没加模式。

四、摒弃了完成动作。 它没有收尾步骤:不关工单、不勾验收标准、不写报告。文档说这是「Correct, and expected」,并且明确这是它能被复用的原因之一——它只负责把决定变成 commit。

五、摒弃了并发。 它一次只干一票。有人要它批量派发、并行扇出,文档的回应是把这类需求整个指向兄弟技能:dc5cb3e 那一行修改就是把 implement 的文档改成「整份 spec 一次落地请用 implement-spec」,而不是给 implement 加上批量模式。新技能提案的规则更狠——.out-of-scope/new-skills.md:「if you can compose the behaviour from existing skills, it doesn’t get a new skill.」

一个它没藏起来的代价

implement 在提交之前跑 code-review,而 code-review 审的是 git diff <fixed-point>...HEAD——三点比较,不含暂存区和工作区。于是就有了这个报了多次的问题:review 说它看不到你的改动。两边都没修,文档把它写成已知缺陷,建议是「先提交,再对着分叉点审」。

同一段还留了第二条更诚实的话:一个刚写完代码的 agent 审自己的代码是有偏的,这也是 code-review 要把两条轴拆成两个平行子代理的原因。在会话里跑 review 是默认路径,但不是一个不可替代的路径。

原文证据

它工作没工作,判据给得很具体,第一条直接检查 trace:

You can see an actual tdd Skill tool call in the trace, not just tests appearing in the diff.

另一条是范围判据:

The diff is one ticket’s worth of change: a vertical slice through every layer, not several tickets swept together.

而它唯一的「我理解对了吗」检查点,就是 6d6a5b9 加进去的那一行——拉取传入的工单引用并先念标题;引用有歧义就问。问题 #700 描述的症状很典型:在新会话里敲 /implement #2,agent 拿 #2 去对了上下文里另一个编号清单,干出了完全无关的活。

可迁移结论

  1. 把「流程」和「知识」分开放。 顺序和终点留在薄技能里,「怎么写测试」「怎么审」留在各自的参考技能里;改一处,所有调用点免费同步。
  2. 点名工具,别只写斜杠。 Call the Skill tool with "tdd" 比 use /tdd 更可靠,而且不绑定某个 harness 的触发语法。指针的措辞值得为它单独提交。
  3. 一个技能只承诺一个终点。 implement 的终点是一次 commit,不是「一票完成」,所以它不需要知道 tracker 怎么关票,也就不会在那里出错。
  4. 把接缝写进上游产物。 如果你的实现技能依赖某个它自己无法确认的前提(这里是接缝),就把它写进 spec——否则运行时会静默退化成「照我说的写」。
  5. 需要新能力时先找组合。 批量、并行、PR 都有人要,答案是 implement-spec、pr 和一行文档,不是给 implement 加模式。

implement 可能是整个系列里最「不像技能」的技能:全文 17 行,没有一句教你写代码。但它把一件事做到了头——把一次实现固定成一条可检查的顺序,然后把每条分支的细节交还给拥有它的技能。

讨论

用 GitHub 账号留言;评论保存在公开仓库chengshu-blog-discussions的 Discussions 里。也可通过 RSS 订阅后续文章。