安装此技能
npx skills@latest add mattpocock/skills --skill=implement-spec 然后在你的编码 agent 里输入 /implement-spec 。
本页目录
它做什么
implement-spec 拿一份规范文档(spec)和它的工单(tickets),在一次运行里把整个东西落地。编排的 agent 把每个工单交给一个在自己的 git worktree 里工作的实现者子代理(subagent),把每个完成的分支合并进一个集成分支(integration branch),对结果运行 code-review,并结清这些工单。
它把工单读成一张任务图(task graph),而不是一个列表。阻塞边(blocking edges)决定什么可以开始,所以在任何时刻都存在一个前沿(frontier),由阻塞者全部落地的工单组成,而前沿上的每个工单都同时运行。这就是它与逐个处理工单的区别。决定节奏的是图的形状,而不是工单在追踪器上的顺序。
什么时候用它
你通过输入 /implement-spec 来调用它,agent 不会主动去拿它。
| 你的处境 | 该用 |
|---|---|
| 一份规范文档,已经拆成带阻塞边的工单,你想在一次运行里落地 | /implement-spec |
| 一次一个工单,在你自己的上下文窗口(context window)里,工单之间清除(clearing) | implement |
| 一份还没拆成工单的规范文档 | 先用 to-tickets |
| 一件没有真正图形结构的小工作 | 直接用 implement |
前提条件
- 一个 issue 追踪器(issue tracker)。 这个技能从 setup-matt-pocock-skills 配置好的追踪器上读取工单,并在那里结清它们。如果还没有配置过,它会停下,告诉你要先运行那个,而不是猜测。
- 带阻塞边的工单,就像 to-tickets 写出的那样。没有边,图就是平的,每个工单都会同时开始。
- 一个在后台运行子代理、并给每个子代理一个 git worktree 的运行环境(harness)。 这个技能存在的目的就是同时运行工单,所以在一次只运行一个子代理的运行环境上,它只是一个更慢的
implement。
集成分支
一切都落在一条分支上。每个实现者(implementer):
- 在开始之前确认它的 worktree 基于集成分支,
- 用 tdd 构建它的工单,一次一个红—绿切片,
- 在报告完成之前把集成分支的顶端合并进自己的分支,这样它落地时就是一次快进(fast-forward)。
追踪器决定到底有没有一个 PR(pull request)存在。如果你的追踪器通过 PR 来关闭工作,或者你要求一个 PR,技能会在第一次合并之后开一个草稿 PR,并在最后把它标记为就绪。否则这次运行停在集成分支上,每个工单都按你的追踪器关闭工作的方式结清,这在面对一个本地 markdown 追踪器时可以完全离线工作。
实现者通过上下文指针(context pointers)(规范文档、工单、共享的探索笔记、更早的提交)与编排者(orchestrator)交谈,而不是通过粘贴的摘要。这让每个子代理的提示词保持小,并在编排者的窗口里为那张图留出空间。
常见问题
它和我自己在每个工单上跑 /implement 有什么不同?
这正是这个技能存在的目的。在它发布之前,人们不断自己搭建版本,有一位用户这样描述需求:他们想要「子代理实现这些工单」,而不是在「一份规范文档可能包含超过 5 个工单时,还得一个一个地新建会话,告诉它们实现一个工单」。用 implement 时你是调度员:每个工单一场会话(session),之间清除,并自己记录哪些工单已经解除阻塞。implement-spec 把这项工作交给一场编排会话。代价是你不再在每份工作落地时阅读它;你在最后审查集成分支。要启动一次运行,清除上下文,然后输入 /implement-spec,带上指向规范文档的指针(一个 issue 编号或一个文件路径)。对于没有真正图形结构的小改动,跳过它,直接用 implement。
它需要 GitHub 吗?我想让它停在分支上。
不,不再需要了。一位喜欢进行中版本的用户恰好有这个抱怨:「它在最后创建一个 PR,而这需要一个像 GitHub 这样的在线仓库。我希望它能离线做同样的工作,并停在所有工作都已合并的那条分支上。」这次运行现在结束在集成分支上。只有配置好的追踪器通过 PR 关闭工作、或者你要求一个 PR 时,才会开一个 PR,所以在本地 markdown 追踪器上,运行结束时每个工单都已结清,工作已合并到那条分支上。
它的审查与修复循环跑了几个小时,或者一直在「修复」还没构建的工单。
当 code-review 在技能指定的那一个点之外的任何地方运行时,两种情况都会发生。它把代码对照整份规范文档来比较,所以只有每个工单都落地之后才有意义。如果它在中途运行,每个还没构建的工单都会被读成一个失败。然后 agent 去构建那个工单,而这又触发另一次审查。在最后,技能运行 code-review 一次,并把每条发现发给一个修复子代理,但它还没有说明那次修复之后什么时候停。有一位用户报告了一个五个工单的功能,其中「审查与修复循环花了大约四个小时」。如果你看到第二轮大范围审查开始,就告诉它针对已修复的发现跑聚焦检查然后停下。预期第一次审查会找出真正的问题。这次运行的输出是一份由审查补全的草稿,不是可以独自发布的东西。
它会像 implement 那样驱动 tdd 吗?
现在会,虽然一开始并不会。运行进行中版本的用户注意到「实现子代理不继承 /tdd 指令」,所以一从单个工单扩大到整份规范文档,红—绿就停了。现在每个实现者都用 tdd 构建自己的工单。仍然没有一步让你交互式地商定接缝(seam),就像 implement 会话里那样,所以如果你想把它们钉住,就在规范文档或工单里点名接缝。
两个并行运行的实现者在同一个文件上撞了,或者给同一个东西起了不同的名字。
worktree 不会消除冲突;它们把冲突推迟到合并时。一条从工单文本写出来的阻塞边,是对每个工单会碰哪些文件的猜测,而两个位于「代码库不同部分」的工单仍然共享一个消息目录、一个配置注册表或一个类型。每个实现者只看到自己的工单和共享笔记,从来看不到另一个进行中的工作,所以有一位用户的 web 工单和 mobile 工单,给同一个字符串分别加了 blockedSince 和 blockedOn。当两个前沿工单碰到同一个共享文件时,要么在它们之间加一条阻塞边,让它们一个接一个运行,要么让探索笔记固定每个工单添加的确切名字。
被阻塞的工单从不开始,即使它的阻塞者已经合并。
这是 GitHub 上的一个已知问题。追踪器的 blocked-by 计数只在阻塞者关闭时才下降,而工单通常在 PR 合并时关闭,也就是这次运行的终点。追踪器是起始图的正确来源,但在运行中途却是一个会过时的来源。告诉编排者自己去追踪哪些工单已经合并进集成分支,并据此计算前沿。
这会取代 Sandcastle 或一个 AFK 脚本吗?
不会。人们这么问,是因为这些技能现在伸进了实现:「Sandcastle 还有意义吗?你的技能现在似乎也能处理实现了。」implement-spec 让一个 agent 在一场运行环境会话里负责编排,这不需要基础设施,还能让你观看和操控。对于真正离开键盘(AFK)的工作,一个确定性的循环(Sandcastle、一个 shell 脚本、一个 CI 任务)更快、更便宜、更可靠,因为没有 agent 来做编排决定。
一个工单的关键测试在它的 worktree 里被跳过了,而它报告了绿色。
一个 worktree 只保存 git 追踪的东西。读取被 gitignore 的 fixture、本地数据库或凭据的测试,在那里可能静默跳过。对于一个验证依赖未追踪材料的工单,告诉编排者在主检出目录里运行它。
它生效的标志
- 只要图允许,就有好几个实现者在同时运行,而不是一个接一个。
- 一个工单在它最后一个阻塞者落到集成分支上时就开始,而不是等整次运行结束时。
- 每个工单的轨迹都显示
tdd在运行,代码之前先有一个失败的测试。 - 合并进集成分支都是快进,不是冲突解决。
- 运行结束在一条分支上,每个工单都已结清,只有你的追踪器想要时才有 PR。
它在体系中的位置
implement-spec 是主链上的构建步骤,是相对于每个工单跑一次 implement 的并行替代:
grill-with-docs → to-spec → to-tickets → implement-spec → retro
它的邻居是 to-tickets——它声明这个技能读成任务图的阻塞边——以及 code-review——它在收尾之前对集成分支运行它。ask-matt 是当你不确定自己处在哪条流程(flow)时,覆盖整套技能的路由器。