mattpocock/skills—面向真实工程的AI编程工作流
mattpocock/skills 不是一组“让 AI 把代码写得更漂亮”的提示词,而是一套面向真实软件工程的工作流。它把需求澄清、外部调研、原型验证、规格沉淀、任务拆分、实现、审查和故障诊断连接起来,让一个复杂功能可以跨越多个会话继续推进。
如果是第一次接触这个项目,可以先记住三个答案:
它解决什么问题?
它主要解决 AI 编程中最容易失控的部分:需求没有说清就开始写代码、长对话丢失上下文、任务拆得无法独立验收、实现偏离规格,以及复杂缺陷只能靠猜。
第一次应该安装哪些 Skill?
使用 Claude Code 原生插件时直接安装整个插件即可。真正需要先学会的,是本文重点介绍的 10 个高频入口;
grilling、domain-modeling、tdd和code-review会由主流程在内部调用。面对一个任务应该从哪个 Skill 开始?
第一次在仓库中使用先运行
/setup-matt-pocock-skills;不知道如何选择流程时运行/ask-matt;如果需求本身还不清楚,通常从/grill-with-docs开始,而不是直接/implement。
本文不逐项解释仓库中的所有 Skill。低频工具、作者个人工作流、开发中能力和已弃用能力并不是首次使用这套 Skills 的重点。下面只围绕最常用的 10 个 Skill,完成一个从模糊需求到上线前修复的完整案例。
一、先建立正确的使用模型
1. Skill 不是必须全部执行的流水线
这套 Skills 提供的是一组可以组合的工程阶段,而不是每个任务都必须走完的固定流程。
- 改一处已经明确的文案,不需要先写规格。
- 只有通过实际交互才能判断的界面问题,才值得制作原型。
- 一个可以在单次会话内安全完成的小改动,通常不需要先拆成多个 Ticket。
- 已经有稳定复现和明确原因的简单缺陷,不必启动完整的系统诊断。
真正重要的是:在信息不足时不要过早进入实现,在上下文过长时不要勉强留在同一会话,在任务较大时不要让一个 Agent 同时记住所有设计和代码细节。
2. 本文会用到的工程术语
这套 Skills 来自软件工程场景,其中一些英文词在日常语言中可能有不同含义。先明确本文的用法:
- Agent(智能体):能够读取仓库、调用工具并完成编程任务的 AI,例如 Claude Code 中正在工作的 Claude。
- Skill(技能):提供给 Agent 的一套可复用工作说明。它规定什么时候使用、按什么步骤执行以及应该产生什么结果,不等同于一个独立应用。
- Issue Tracker(工作项跟踪系统):保存需求、缺陷和开发任务的地方,例如 GitHub Issues、GitLab Issues、Linear、Jira,或者项目中的本地 Markdown 文件。
- Issue(工作项):Issue Tracker 中的一条记录。它可以记录一个缺陷、一份完整功能规格,也可以记录一项具体开发任务。
- Ticket(任务单):从规格中拆出、准备交给开发者或 Agent 实施的工作单元。它应包含明确范围、验收标准和依赖关系。Ticket 不是某种固定文件格式:在 GitHub 中通常表现为一条 Issue,在 Linear 中是一个工作项,使用 Local Markdown 时则是一个 Markdown 文件。
- Spec(规格,也常称 PRD):对“要解决什么问题、系统应该如何表现、如何验收以及哪些内容不做”的正式说明。它比一句需求描述更完整,但通常不包含容易过期的逐行代码方案。
- ADR(Architecture Decision Record,架构决策记录):记录重要技术决策及其背景、备选方案和取舍理由的文档,用来回答“为什么当时这样设计”。
- Test seam(测试接缝):测试能够从外部控制输入并观察结果的稳定边界,例如 API、领域服务或 Worker 入口。提前确认 seam,是为了避免测试只能依赖内部实现细节。
- Queue、Job 与 Worker:Queue 是等待处理的任务队列;Job 是队列中的一项具体后台任务;Worker 是取出并执行 Job 的进程。本例使用 BullMQ 管理它们。
- 幂等(Idempotency):同一个操作因为重试或并发被执行多次时,最终业务结果仍然只出现一次。例如 Worker 重试三次,用户也只能收到一条提醒。
- Out of Scope(范围之外):本次规格明确不实现的内容。主动写出非目标,可以防止 Agent 在实现时顺手扩大需求。
- 垂直切片(Vertical Slice):围绕一个很小但完整的用户行为,贯穿该行为所需的界面、API、数据、后台处理和测试。
to-tickets章节会用任务提醒案例详细说明。
后文第一次出现其他不常见术语时,也会结合当前步骤解释其具体含义。
3. 本文贯穿场景:TaskBoard 的任务到期提醒
假设我们正在维护一个名为 task-board 的任务管理应用。它包含 Web 前端、API 服务、PostgreSQL 数据库,以及使用 BullMQ 和 Redis 运行的后台任务。
产品只给出了一句话:
给任务增加到期提醒,用户可以在截止时间前收到通知。
这句话还不能直接实现。至少有以下问题尚未确定:
- 通知通过站内消息、邮件还是短信发送?
- 可以提前多久提醒?
- 修改任务截止时间后,旧提醒如何处理?
- 创建时已经过期的任务是否补发提醒?
- Worker 重试时如何避免重复通知?
- 第一个版本是否需要重复提醒、免打扰和时区设置?
接下来会看到,不同 Skill 的职责并不是“换一种方式继续问 AI”,而是分别消除这些问题中的不同风险。
4. 一条典型主流程
对于需要跨多个会话完成的功能,常见顺序是:
1 | 仓库初始化 |
其中,调研和原型是按需分支;交接可以出现在任意阶段。
二、安装:Claude Code 为主,skills.sh 为辅
1. Claude Code 原生插件
在 Claude Code 中,先添加项目提供的插件市场,再安装插件:
1 | /plugin marketplace add mattpocock/skills |
安装完成后,进入实际项目目录并启动 Claude Code。本文中的调用都使用斜杠命令,例如:
1 | /ask-matt 我准备给任务系统增加到期提醒,但需求还不完整,而且会跨前后端。 |
原生插件适合希望直接获得完整依赖关系和后续更新的使用者。某个主 Skill 需要 tdd 或 code-review 时,插件能够提供对应的支撑能力,不需要手工复制提示词。
2. skills.sh:适合需要修改 Skill 的项目
如果希望把 Skill 安装为本地文件,以便阅读、定制或纳入自己的配置,可以使用:
1 | npx skills@latest add mattpocock/skills |
这种方式更适合以下情况:
- 团队需要调整 Issue 模板、标签名称或文档路径;
- 希望审查每个
SKILL.md后再启用; - 需要把工作流固定在项目或个人的 Agent 配置中;
- 准备基于原 Skill 派生自己的内部流程。
手工挑选 Skill 时,不要只复制 10 个入口文件而忽略依赖。本文涉及的内部支撑能力至少包括:
grilling和domain-modeling:支撑grill-with-docs;tdd和code-review:支撑implement。
3. Codex 兼容性
这些 Skill 使用的是通用的 Agent Skills 结构,也可以通过 skills.sh 安装到支持该结构的 Codex 环境。区别主要在调用方式:Claude Code 可以直接使用 /skill-name;在 Codex 中通常明确写出 Skill 名称和任务,例如“使用 research 调研 BullMQ 的 Job ID 规则”。本文后续仍以 Claude Code 的原生命令为准。
三、setup-matt-pocock-skills:让工作流认识当前仓库
setup-matt-pocock-skills 是一次性的仓库初始化入口。它不是安装命令,而是把这套通用工作流与当前项目的 Issue Tracker、领域文档和 Agent 说明连接起来。
什么时候使用
- 第一次在某个仓库中使用这套 Skills;
- 仓库还没有说明使用 GitHub Issues、Linear 还是本地文件管理工作;
- 缺少统一的领域文档位置;
- 安装了
triage,但 Agent 还不知道哪些标签表示“待分流”“缺少信息”或“可以交给 Agent”。
什么时候不需要使用
- 同一仓库已经完成初始化,而且 Tracker、标签与文档约定没有改变;
- 只是进入一个新会话继续工作;
- 只想临时试用某个不依赖仓库约定的 Skill。
精确调用
在 task-board 仓库根目录启动 Claude Code,先单独发送:
1 | /setup-matt-pocock-skills |
发送后等待 Agent 开始初始化并询问 Issue Tracker、标签和文档位置,再把下面的配置作为下一条消息发送,不要与斜杠命令拼在同一条消息中:
1 | 这个项目使用 GitHub Issues。 |
这里的 triage 指“对新工作项进行分类并决定下一步”。默认标签的含义是:
needs-triage:尚未完成分类;needs-info:缺少继续处理所需的信息;ready-for-agent:范围已经清楚,可以交给 Agent 实施;ready-for-human:需要人类判断或操作;wontfix:确认不处理。
只有已经安装 triage Skill 时,初始化流程才需要配置这些标签。项目已有自己的标签体系时可以进行映射,不必创建含义重复的新标签。
Agent 接下来会做什么
它会先检查仓库当前约定,而不是假定所有项目都使用同一种工具。随后确认:
- 工作项记录在哪里;
- 如何创建、关联和关闭工作项;
- 使用哪些状态与分流标签;
- 领域知识保存在哪里;
- 应该把这些约定写入
CLAUDE.md还是AGENTS.md。
会生成或修改什么
常见结果包括:
1 | docs/agents/issue-tracker.md |
对于示例项目,issue-tracker.md 应说明 GitHub Issues 的使用方式,domain.md 应先记录 Task、Due Date、Reminder 等核心术语。这里建立的是项目级约定,不是某一个功能的详细规格。
如果仓库已经有
CLAUDE.md或AGENTS.md,应先审查差异。初始化的目标是补充工作流入口,不是覆盖团队现有规范。
下一阶段
初始化只回答“如何在这个仓库工作”,不回答“当前需求该走什么流程”。下一步通常是 /ask-matt,或者在已经确认需求模糊时直接使用 /grill-with-docs。
四、ask-matt:不知道从哪里开始时先做路由
ask-matt 是工作流路由器。它根据任务状态推荐接下来使用哪个 Skill,本身不会代替调研、写规格或实现。
什么时候使用
- 知道自己要做什么,但不知道应该先调研、澄清、写规格还是实现;
- 一个任务同时包含产品、架构和代码问题;
- 不确定任务是否需要跨多个会话;
- 刚接触这套 Skills,希望避免选错入口。
什么时候不需要使用
- 已经知道下一步,例如外部 API 行为不确定,明确需要
/research; - 只是执行既有 Ticket,直接
/implement <Issue>即可; - 正在按照上一阶段给出的明确下一步继续工作。
精确调用
1 | /ask-matt 我准备给 task-board 增加任务到期提醒。需求还不完整,预计会修改 Web 前端、API、数据库和 BullMQ Worker,可能需要多个会话完成。我应该从哪个流程开始? |
Agent 接下来会做什么
ask-matt 会判断任务目前缺少的是哪类信息。例如:
- 需求语义不清楚:推荐
grill-with-docs; - 关键实现依赖第三方工具行为:先执行
research; - 只能通过交互体验决定:插入
prototype; - 需求已确定但工作量较大:进入
to-spec和to-tickets; - 已有明确、可执行的 Ticket:进入
implement; - 是难以定位的缺陷:使用
diagnosing-bugs。
在这个场景中,一个合理的路由结果是:
1 | 先 research BullMQ 的调度与重试语义 |
会生成或修改什么
通常不会修改源码、文档或远程 Issue。它的主要产物是一条带理由的推荐路径。
这也是理解它的关键:如果 /ask-matt 已经开始替你实现功能,就超出了路由器的职责。
下一阶段
按照推荐结果进入最先需要的阶段。本例先调研 BullMQ 的官方行为,因此下一步是 /research。
五、research:先把外部事实查清,再做内部决策
research 用于调查仓库之外的事实,例如框架行为、API 限制、协议规范和公开实现。如果 Claude Code 已启用网页搜索或网页读取工具,并且当前网络可用,Agent 会主动访问互联网查找资料,不需要使用者提前收集所有链接。它会优先使用官方文档、官方仓库、标准文本和论文等一手资料,再把带引用的结论写回仓库。
需要注意,research 只是规定调研方法,并不会凭空为 Claude Code 增加网络能力。实际能否联网取决于当前环境:
- Claude Code 可以使用
WebSearch、WebFetch等工具时,Agent 会自行搜索和打开网页; - 工具调用触发权限确认时,需要允许本次网页访问;
- 当前环境不能联网时,Agent 应明确报告限制,改用使用者提供的资料或仓库中的现有文档;
- 没有实际读取来源时,Agent 不能把模型记忆包装成“已经查阅官方文档”的结论。
什么时候使用
- 实现依赖第三方库的具体语义;
- 团队对框架行为存在不同记忆;
- 设计决策必须建立在官方限制之上;
- 需要让后续会话复用调研结果,而不是重复搜索。
什么时候不需要使用
- 答案可以直接从当前仓库代码、测试或配置中确定;
- 这是产品偏好,而不是外部事实;
- 只需要确认一个简单且稳定的本地类型定义;
- 已有近期、可信并且可追溯的项目调研文档。
精确调用
research 是带任务参数的命令。与需要先启动、再等待提问的 /setup-matt-pocock-skills 不同,应该把 /research 和完整的调研要求写在同一条消息中发送:
1 | /research 调研 task-board 使用 BullMQ 实现任务到期提醒时必须确认的官方行为: |
发送后,Agent 会自行搜索 BullMQ 官方网站和官方 GitHub 仓库。除非它遇到网页访问权限、登录限制或无法确认的问题,否则不需要再逐条告诉它应该打开哪些页面。如果希望进一步限制资料范围,也可以在命令中直接附上允许使用的链接或域名。
Agent 接下来会做什么
该 Skill 通常会启动独立的调研过程,搜索并比较一手资料,然后完成以下工作:
- 将问题拆成可以验证的子问题;
- 为每条事实找到直接来源;
- 区分文档明确保证的行为与根据资料做出的工程推论;
- 标记仍然无法确认的部分;
- 形成一份后续规格可以引用的调研文档。
这里必须避免一个常见错误:把“我们准备怎么设计”写成“BullMQ 本来就是这样”。例如,使用稳定 Job ID 避免重复入队是项目方案;Job ID 的去重范围和字符限制才是需要从官方资料确认的事实。
会生成或修改什么
应生成一份有明确主题的 Markdown 文档,例如:
1 | docs/research/bullmq-task-reminders.md |
内容可以采用以下结构:
1 | # BullMQ 任务提醒调研 |
它不会直接改业务代码,也不应该在调研阶段擅自确定通知渠道等产品规则。
下一阶段
外部约束明确后,使用 /grill-with-docs 澄清产品语义,并把最终决定写入领域上下文。
六、grill-with-docs:通过提问把模糊需求变成可执行决策
grill-with-docs 是需求澄清的主入口。它不只是进行一轮访谈,还会通过内部的 grilling 和 domain-modeling,将已确认的规则持续写入 CONTEXT.md 和必要的 ADR。
什么时候使用
- 需求只有一句目标描述;
- 多种解释都会产生合理但不同的实现;
- 领域术语、边界条件或失败语义尚未统一;
- 需要在写规格前确认什么属于首个版本。
什么时候不需要使用
- 已有经过确认且足够具体的规格;
- 修改是机械性的,没有产品或领域歧义;
- 当前问题只是第三方行为未知,应先使用
research; - 只是需要在已有 Ticket 上执行实现。
精确调用
1 | /grill-with-docs 我们要为 task-board 增加任务到期提醒。当前只有一句需求:“用户可以在任务截止时间前收到通知”。请结合 docs/research/bullmq-task-reminders.md,逐个澄清通知渠道、提前时间、任务改期、取消截止时间、创建时已过期、重复提醒和 Worker 重试的语义。把确认后的领域规则维护到项目文档中,不要开始实现。 |
Agent 接下来会做什么
这个 Skill 内部组合了两个支撑能力。
grilling:一次只解决一个关键问题
grilling 不会一次抛出二十个问题让使用者填表。它会优先选择当前最影响设计的问题,一次提问一个,并通常给出推荐答案和理由。
例如第一问可能是:
1 | 首个版本使用哪种通知渠道? |
确定渠道后,再继续确认提前时间:
1 | 首个版本是否允许任意分钟数? |
在完整访谈后,本例可能得到以下规则:
- V1 只发送站内通知;
- 提供提前 10 分钟、30 分钟和 1 天三个选项;
- 没有截止时间的任务不能启用提醒;
- 修改截止时间或提前量时,旧计划失效并建立新计划;
- 移除截止时间或关闭提醒时,取消尚未触发的计划;
- 创建或修改时已经错过提醒时间,不补发历史提醒;
- 同一个“任务 + 截止时间版本”最多产生一条业务通知;
- Queue 重试不能让用户收到重复通知;
- V1 不包含邮件、短信、重复提醒、免打扰和用户自定义提前量。
这些答案不是 Skill 自动替产品负责人决定的。Agent 会给出建议,但关键选择仍应由拥有产品上下文的人确认。
domain-modeling:让答案进入长期上下文
访谈中已经确认的稳定概念会被及时写入 CONTEXT.md 或项目指定的领域文档,而不是等对话结束后依靠记忆整理。
例如:
1 | ## Reminder |
如果某项决定同时满足以下条件,才值得记录为 ADR:
- 难以轻易撤销;
- 对不了解背景的人并不显然;
- 存在真实的方案权衡。
例如“为什么除了稳定 Queue Job ID 之外,还需要数据库中的通知幂等记录”可能值得写成 ADR,因为外部发送成功与 Queue 确认失败之间存在跨系统边界。相反,“按钮放在表单右侧”不应该成为架构决策记录。
会生成或修改什么
根据仓库约定,可能更新:
1 | CONTEXT.md |
它不会生成实现代码,也不会直接发布正式规格。访谈结束时应得到“共同理解”,而不是一堆仍然互相冲突的聊天记录。
下一阶段
- 如果某个交互只有实际体验后才能决定,进入可选的
/prototype; - 如果关键规则已经确认,直接使用
/to-spec。
七、prototype:只有必须体验才能决定时才使用
prototype 用最少代码回答一个具体设计问题。它产生的是一次性实验,不是生产实现的开端。
在本例中,领域规则已经确定了三个提醒预设值,但团队仍无法仅凭文字判断选择器应该放在哪里、采用什么交互。这个问题适合原型验证。
什么时候使用
- 只有实际点击、输入或观察运行结果才能做决定;
- 两到三个 UI 方案都合理,讨论无法继续收敛;
- 某项技术可行性需要用最小实验验证;
- 结论的价值高于一次性代码的成本。
什么时候不需要使用
- 通过文档、代码阅读或简单讨论就能回答;
- 产品规则尚未澄清,原型目标仍在变化;
- 已有明确设计稿和验收标准;
- 只是希望“先写一点生产代码看看”,这会混淆实验与实现。
精确调用
建议先切换到一次性分支,再调用:
1 | /prototype 为 task-board 的任务编辑表单制作三个可切换的一次性 UI 方案,用来比较提醒时间选择器: |
Agent 接下来会做什么
它会先把问题限制为“哪种提醒选择器最容易理解”,然后只实现回答这个问题所需的界面:
- 复用最少的项目基础设施;
- 使用固定的示例任务数据;
- 让三个方案可以快速并排或切换比较;
- 提供一条本地运行命令;
- 记录观察结果与最终选择。
原型不应扩展为完整功能。持久化、权限、无障碍细节、完整错误处理和长期测试,除非它们正是要验证的问题,否则都应留到正式实现。
会生成或修改什么
它会产生临时原型代码和一份结论。推荐在 throwaway 分支中完成,例如:
1 | codex/reminder-picker-prototype |
验证后保留的应该是决策,而不是原型代码。这里的 throwaway branch 指“只用于实验、验证结束后不合并的临时分支”。例如:
1 | 选择方案 B:启用提醒后展开设置区。 |
不要把实验分支直接合并到主分支。正式实现应该根据规格重新完成,避免把为了快速验证而省略的边界处理带入生产代码。
下一阶段
把原型结论带回主工作分支,然后运行 /to-spec。如果原型对话已经很长,可以先使用 /handoff 将结论交给一个干净会话。
八、to-spec:把共同理解发布成稳定规格
to-spec 将已经完成的调研、访谈和原型结论整理为可以被后续 Agent 独立读取的规格。它不是新的需求访谈,因此调用前应先解决关键歧义。
是否一定会创建远程 GitHub Issue
不一定。to-spec 的固定目标是“把规格发布到当前项目配置的 Issue Tracker”,但这个 Tracker 不一定是 GitHub。/setup-matt-pocock-skills 会把选择记录在 docs/agents/issue-tracker.md,后续 Skill 根据该文件决定发布位置:
- 配置为 GitHub:创建远程 GitHub Issue;
- 配置为 GitLab:创建远程 GitLab Issue;
- 配置为 Linear、Jira 等其他平台:按照项目记录的工作流发布;
- 配置为 Local Markdown:只在本地写入 Markdown 工作项,不访问远程 Tracker。
本文的 task-board 场景在初始化阶段明确选择了 GitHub Issues,所以后面的 #142 才代表远程 GitHub Issue。这是本例的配置结果,不是 to-spec 对所有项目都固定执行的行为。
如果项目配置的是 GitHub,但当前只想审阅草稿、不希望立刻创建远程 Issue,可以在调用中明确增加:
1 | 先在对话中展示完整规格草稿,得到我确认后再发布到 Issue Tracker。 |
什么时候使用
- 功能需要多个会话或多张 Ticket 才能完成;
- 需要将聊天中的决定转化为稳定、可引用的工作项;
- 参与实现的人不一定经历了前面的讨论;
- 希望在拆票前冻结范围、验收方式与非目标。
什么时候不需要使用
- 改动足够小,可以在一个会话内完成并验证;
- 关键需求仍未确认,应返回
grill-with-docs; - 只是调查问题,还没有计划进入实现;
- 已经存在内容充分且仍然有效的规格。
精确调用
1 | /to-spec 将当前关于 task-board“任务到期提醒”的已确认上下文整理为规格。引用 docs/research/bullmq-task-reminders.md、领域文档和提醒选择器原型结论。规格必须包含用户故事、领域规则、实现决策、测试 seam、验收标准、失败语义和 Out of Scope。先在对话中展示完整草稿,得到我确认后,再发布到项目配置的 Issue Tracker 并应用 ready-for-agent 标签。 |
Agent 接下来会做什么
to-spec 会从当前上下文中提取已经确认的内容,并检查规格能否独立回答以下问题:
- 用户为什么需要这个功能;
- 哪些行为属于首个版本;
- 系统在正常、改期、取消、过期和重试情况下如何表现;
- 哪些技术决定已经确定,哪些仍留给实现者;
- 从哪个公共 seam 验证行为;
- 哪些内容明确不做。
它还会确认测试 seam。对于本例,合理的 seam 可能包括:
- API 层:保存任务提醒设置后,计划记录与响应是否正确;
- 调度层:给定任务、截止时间和提前量,生成确定的计划标识与执行时间;
- Worker 层:重复处理同一提醒时,只产生一次站内通知;
- UI 层:没有截止时间时提醒控件不可用,修改截止时间后提交正确设置。
测试 seam 不是把内部私有函数全部暴露出来,而是提前确定“后续如何证明功能真的成立”。
会生成或修改什么
它会把规格发布到 docs/agents/issue-tracker.md 指定的位置,并应用相应状态。由于本例配置的是 GitHub,所以最终结果是一个远程 GitHub Issue;如果配置的是 Local Markdown,结果则是本地工作项文件。规格的核心结构为:
1 | # Task due reminders |
当 Tracker 配置为 GitHub、GitLab、Linear 或 Jira 等外部系统时,这是一个会修改远程状态的 Skill。发布前应确认目标项目和标签。配置为 Local Markdown 时则只修改本地文件。
本例的 Out of Scope 至少包括:
- 邮件和短信通知;
- 重复提醒;
- 免打扰时间;
- 任意分钟数输入;
- 为已经错过提醒时间的任务补发通知。
下一阶段
如果规格可以在一个会话内实现,可以直接进入实现;本例横跨 UI、API 和 Worker,应使用 /to-tickets 将规格拆成可独立验证的垂直切片。
九、to-tickets:把规格拆成可独立验收的垂直切片
to-tickets 的目标不是按照技术目录分工,而是把规格拆成多个可以在单个上下文中实现、验证和审查的行为切片。
先理解什么是“垂直切片”
这里的“垂直”不是指界面布局,而是指一张 Ticket 会跨过让某个行为成立所需的多个技术层。可以把 task-board 想象成由以下部分组成:
- 前端:让用户启用提醒;
- API:接收并校验提醒设置;
- 数据库:保存设置和通知记录;
- BullMQ:在正确时间调度任务;
- Worker:触发站内通知;
- 测试:从可观察入口证明整条路径成立。
如果按照技术层拆票,会得到“建表”“写 API”“写页面”“最后补测试”等水平任务。完成“建表”后,用户仍然不能启用提醒;完成“API”后也不一定能收到通知。每张 Ticket 都只是零件,只有所有任务结束后才能判断功能是否可用。
垂直切片换一个方向拆:**每张 Ticket 选择一个很小的用户行为,并贯穿实现该行为所必需的所有层。**例如第一张 Ticket 只交付以下行为:
用户为一个 12:00 到期的任务启用固定提前 30 分钟提醒后,系统保存设置、创建 11:30 执行的 Job,并在 Job 执行时生成一条站内通知。
为了让这个行为真的成立,这张 Ticket 可以同时包含少量 UI、API、数据库、Queue、Worker 和测试改动。范围虽然窄,却已经形成完整闭环。完成后可以独立演示,也可以通过自动化测试验收,不必等后续 Ticket。
这就是项目原文所说的 tracer bullet:先用一条很窄但贯穿系统的路径证明整条链路可行,再逐步增加多个提前量、改期处理和重试幂等。这里并不是要求每张 Ticket 机械地修改所有目录,而是要覆盖该行为成立所必需的层,避免交付无法单独运行的半成品。
什么时候使用
- 规格需要多个会话才能完成;
- 功能包含多个可逐步交付的行为;
- 希望每张 Ticket 都能独立验证;
- 需要明确 Ticket 之间的依赖和阻塞关系。
什么时候不需要使用
- 整个规格可以在一个会话内安全完成;
- 当前还没有稳定规格;
- 只是一个不可再拆的修复;
- 拆分后每个任务都只能产生无法运行的半成品。
精确调用
假设规格发布在 GitHub Issue #142:
1 | /to-tickets https://github.com/example/task-board/issues/142 |
Agent 接下来会做什么
它会先阅读完整规格,寻找最小的端到端 tracer bullet,然后提出一个编号拆分方案。此时还不会立即发布 Ticket,而是先询问使用者:
- 每张 Ticket 的大小是否适合一个新会话;
- 是否有 Ticket 过粗或过细;
- 阻塞关系是否正确;
- 是否需要合并或继续拆分。
只有使用者确认拆分方案后,它才会把 Ticket 发布到已配置的 Tracker。每张 Ticket 应包含:
- 清晰的用户可见行为;
- 必要的上下文和规格链接;
- 明确的范围与非目标;
- 可执行的验收标准;
- 测试 seam;
- 对其他 Ticket 的阻塞关系。
“阻塞关系”通常写成 Blocked by,表示当前 Ticket 必须等哪些前置 Ticket 完成后才能开始。例如 Ticket 2 — Blocked by Ticket 1 表示 Ticket 1 没有完成时,Ticket 2 还不具备可靠的实施基础;Blocked by: None 则表示可以立即开始。
错误的水平拆分如下:
1 | Ticket A:设计数据库表 |
这种拆法会导致前三张 Ticket 都无法独立证明用户获得了任何能力,而且“测试”被推迟到最后。
更合适的垂直拆分可以是:
Ticket 1:固定提前 30 分钟的站内提醒
- 用户可以为有截止时间的任务启用提醒;
- 从 API、计划记录、BullMQ Job 到站内通知形成最小闭环;
- 使用固定的 30 分钟提前量;
- 包含端到端行为测试;
- 不包含改期和多个预设值。
Ticket 2:支持三个提醒提前量
- UI 提供 10 分钟、30 分钟和 1 天;
- API 校验仅接受三个合法值;
- 修改提前量会更新计划;
- 每个选项都有可观察的行为测试。
Ticket 3:截止时间改期、移除和过期语义
- 修改截止时间时使旧计划失效;
- 移除截止时间或关闭提醒时取消计划;
- 已错过提醒时间时不补发;
- 覆盖旧 Job 未触发的回归测试。
Ticket 4:重试与业务幂等
- 重复执行同一提醒不会产生第二条站内通知;
- 记录通知唯一键和发送状态;
- 覆盖“已写入通知但 Worker 重试”的场景;
- 明确可观测性与失败恢复方式。
这里的每一张 Ticket 都跨越必要的数据库、服务和测试层,但只交付一个完整行为。这就是垂直切片。
会生成或修改什么
发布方式同样由 docs/agents/issue-tracker.md 决定:
- Local Markdown:在
.scratch/<feature-slug>/issues/下为每张 Ticket 写一个独立文件,并在文件中记录Blocked by; - GitHub、GitLab、Linear 等真实 Tracker:每张 Ticket 创建一个远程 Issue,使用平台支持的阻塞关系;平台不支持时,在正文中写明
Blocked by。
在本文场景中,Tracker 配置为 GitHub,因此会创建多张相互关联的远程 Issue,并链接回规格 Issue。
使用远程 Tracker 时,这一步会修改远程状态;使用 Local Markdown 时只修改本地文件。Skill 会先展示拆分方案并等待确认,仍应在确认时检查数量、依赖和范围。
下一阶段
按照依赖顺序,每张 Ticket 都开启一个新的 Claude Code 会话,并分别执行 /implement <Issue URL>。不要在已经承载整个规格讨论的长会话中连续实现所有 Ticket。
十、implement:在新会话中完成一张 Ticket
implement 是执行阶段。它的输入应该是一张范围明确、能够独立验证的 Ticket,而不是一句模糊需求。它会在内部使用 tdd 和 code-review,完成实现、验证、审查和提交。
什么时候使用
- 已经有明确的 Ticket、验收标准和测试 seam;
- 当前分支和工作区状态已经确认;
- 任务适合在本次会话中完成;
- 依赖的前置 Ticket 已经落地。
什么时候不需要使用
- 需求仍然不完整;
- Ticket 大到无法在单个上下文中完成,应先重新拆分;
- 当前目标只是探索或原型;
- 正在诊断一个原因不明的复杂缺陷,应使用
diagnosing-bugs。
精确调用
为 Ticket 1 开启一个新的 Claude Code 会话,在正确分支中运行:
1 | /implement https://github.com/example/task-board/issues/143 |
处理 Ticket 2 时再开启另一个新会话:
1 | /implement https://github.com/example/task-board/issues/144 |
Agent 接下来会做什么
它会先读取 Ticket、规格、仓库规范和相关代码,然后形成一个受 Ticket 范围约束的实现计划。接下来通常包含以下阶段。
1. 内部使用 tdd 完成单个红—绿行为切片
tdd 不是“先把所有测试写完,再一次性补实现”,而是反复完成小的行为闭环:
1 | 选择一个公共行为 |
以 Ticket 1 为例,第一个切片可以是:
1 | 行为:为 dueAt=12:00 的任务启用提醒时, |
测试先通过 API 或领域服务这一公共 seam 表达行为:
1 | it("schedules an in-app reminder 30 minutes before the due date", async () => { |
先运行它并确认失败是因为提醒能力尚不存在,而不是测试环境错误。随后只实现让这一行为通过所需的最少代码,再进入“计划被送入 Queue”“Worker 生成站内通知”等下一个切片。
这种做法有两个边界:
- 测试公共行为,不锁死私有函数的内部结构;
- 一次只推进一个红—绿切片,避免失败时无法判断是哪部分引入问题。
2. 运行分层验证
目标行为通过后,implement 不会把单个测试变绿当作完成。它还应依次运行:
- 与改动直接相关的测试;
- 类型检查;
- 仓库要求的静态检查;
- 完整测试套件;
- Ticket 指定的手工或端到端验证。
如果完整测试出现回归,应该继续修正,不应以“目标测试已经通过”为理由忽略。
3. 内部使用 code-review 做双轴审查
code-review 会从一个固定比较点审查当前改动,而不是只看最后编辑的文件。审查包含两条轴:
- Standards 轴:是否遵守仓库约定、类型和错误处理是否可靠、是否引入安全或性能问题;
- Spec 轴:是否真正满足 Ticket 和上游规格,是否越界实现了后续功能,是否遗漏验收条件。
例如,代码可能在技术上完全正确,却擅自增加了邮件通知。它能通过 Standards 审查,但会在 Spec 审查中被指出超出 Ticket 1 的范围。
审查时应基于分支与固定基线之间的完整差异,例如 Git 的 three-dot diff。three-dot diff 表示“当前分支相对于它和目标分支共同祖先所新增的改动”,适合只查看本次分支带来的变化。审查不能只依赖 Agent 对自己刚才操作的记忆;发现问题后应修复,并重新运行受影响的验证。
4. 创建提交
当前 implement 工作流默认会在完成验证和审查后创建 Git 提交。这是一个必须提前知道的副作用。
调用前应检查:
1 | git status --short |
确保工作区没有其他人的未提交改动,也没有不属于当前 Ticket 的文件。否则自动提交可能把无关内容一起带入历史。
会生成或修改什么
它会:
- 修改实现代码和测试;
- 可能更新与 Ticket 直接相关的文档;
- 运行项目验证;
- 完成代码审查;
- 默认创建一个 Git 提交。
它不应:
- 修改规格之外的行为;
- 顺手实现后续 Ticket;
- 自动把实验原型当作生产代码;
- 把未验证的改动标记为完成。
下一阶段
- 当前 Ticket 完成后,在新会话中实现下一张 Ticket;
- 出现原因不明、反复修补仍失败的缺陷时,切换到
/diagnosing-bugs; - 上下文已经过长但工作尚未完成时,使用
/handoff。
十一、diagnosing-bugs:定位并修复难以解释的运行时 Bug
假设到期提醒上线前出现一个缺陷:
同一个任务偶尔收到两条完全相同的提醒。
如果直接在 Queue、数据库和前端各加一个“去重判断”,可能暂时隐藏现象,却无法知道重复发生在哪个边界。diagnosing-bugs 的目标是先建立快速、可重复的反馈回路,再通过证据缩小原因。
它能不能用来定位程序运行时 Bug
可以,这正是 diagnosing-bugs 的主要用途。它不是只阅读代码的“错误扫描器”,而是一套让 Agent 运行程序、复现问题、收集证据、定位原因并验证修复的诊断流程。
例如,以下问题都适合使用:
- 程序启动后崩溃,但从报错堆栈看不出真正原因;
- 某个接口偶尔返回错误结果;
- 同一个请求被处理两次;
- 只在特定数据、并发量或操作顺序下出现异常;
- 测试偶发失败;
- 程序突然变慢、内存持续增长或 CPU 占用异常;
- 已经尝试过直觉修复,但问题仍然出现。
调用时应尽量提供以下信息:
- 预期结果:正常情况下应该发生什么;
- 实际结果:现在出现了什么错误;
- 复现步骤:执行哪些操作或命令能够看到问题;
- 错误证据:报错信息、堆栈、日志或失败截图;
- 运行环境:操作系统、运行方式、相关依赖版本;
- 出现频率:必现、偶发,还是只在生产环境出现;
- 最近变化:问题出现前修改过哪些代码、配置或依赖。
例如,一个普通 Node.js 运行时错误可以这样调用:
1 | /diagnosing-bugs task-board 启动正常,但调用 POST /tasks 时会返回 500。 |
如果 Agent 可以访问代码和运行环境,它会实际执行复现命令、测试与必要的插桩。如果问题只存在于无法访问的生产环境,它仍然可以根据脱敏后的日志和监控信息制定排查方案,但不能在没有证据的情况下保证已经找到根因。
使用这个 Skill 时会发生什么
调用 /diagnosing-bugs 后,Claude Code 不会切换成另一个更强的模型,Skill 也不会为 Agent 增加原本没有的文件、终端、生产环境或网络权限。它的作用是把一套严格的诊断方法加载到当前 Agent 的工作上下文中,让 Agent 按证据推进,而不是看到报错后立即修改第一处可疑代码。
在权限允许的范围内,Agent 通常会:
- 阅读相关代码、测试、配置、错误堆栈和日志;
- 运行程序或测试,确认问题是否能够复现;
- 缩小复现范围,排除无关模块和环境因素;
- 提出 3~5 个按可能性排序、能够被证据推翻的原因假设;
- 添加临时日志、断言或诊断测试,一次验证一个假设;
- 根据证据确定根因,而不是根据第一印象猜测;
- 添加能够稳定重现原问题的回归测试;
- 实施针对根因的最小修复;
- 运行相关测试与完整测试;
- 删除没有长期价值的临时插桩。
如果缺少复现命令、运行依赖或必要日志,Agent 可能先向使用者索取信息。它不能访问的生产环境也不会因为调用 Skill 而自动变得可访问。
与直接要求 Agent 定位并修复有什么区别
两种方式使用的仍然是同一个 Agent,区别在于是否强制执行系统化的诊断过程。
| 直接要求“定位并修复 Bug” | 使用 /diagnosing-bugs |
|---|---|
| Agent 可能直接根据堆栈猜测原因 | 先建立复现,再根据证据判断 |
| 容易修改第一处看起来可疑的代码 | 先提出可证伪假设,再逐项排除 |
| 可能只让表面现象暂时消失 | 要求说明能够解释现象的真正根因 |
| 修复后可能只运行已有测试 | 要求增加针对原问题的回归测试 |
| 多处修改可能同时进行,难以判断哪一项有效 | 一次验证一个假设,保持反馈清晰 |
| 临时日志可能遗留在代码中 | 诊断结束后清理临时插桩 |
| 更适合原因明确、改动局部的小问题 | 更适合偶发、并发、重试、缓存和性能问题 |
以“同一个任务收到两条提醒”为例,直接要求修复时,Agent 可能马上增加一个 notificationExists 判断。这可能隐藏重复结果,却没有解释重复调度发生在哪里。
diagnosing-bugs 会先区分:
- API 是否创建了两个 Job;
- 两个 Job 是否使用了不同的 Job ID;
- Worker 是否因为失败而重试;
- 通知是否已经写入,但 Worker 在确认 Job 完成前崩溃;
- 数据库是否缺少业务唯一约束。
只有证据表明“通知已经写入,但 Worker 确认失败后再次执行”时,才应该使用数据库唯一约束或幂等写入修复,并用回归测试模拟这个失败边界。
可以只定位,不立即修改代码吗
可以。diagnosing-bugs 的完整流程包含修复,但使用者可以在命令中限制本轮权限。如果只希望先确认根因:
1 | /diagnosing-bugs 调查 task-board 的重复提醒问题。 |
如果希望 Agent 完成诊断、修复和验证:
1 | /diagnosing-bugs 调查并修复 task-board 的重复提醒问题。 |
这个 Skill 可能在本地修改诊断测试、临时插桩和业务代码,但它本身不会默认创建远程 Issue、推送分支或创建 Git 提交。实际文件修改仍受调用要求和当前工具权限约束。
什么时候使用
- 缺陷无法稳定解释;
- 已经尝试过一两个直觉修复但问题仍在;
- 涉及并发、重试、缓存、时序或性能;
- 需要插桩才能观察内部状态;
- 错误横跨多个系统边界。
什么时候不需要使用
- 已有稳定复现、明确根因和局部修复;
- 只是编译错误、拼写错误或显然的条件判断错误;
- 当前只有产品行为争议而不是代码缺陷;
- 缺少任何复现信息,此时应先收集基本环境和日志。
精确调用
1 | /diagnosing-bugs task-board 中同一个任务偶尔收到两条相同的到期提醒。 |
Agent 接下来会做什么
1. 建立反馈回路
首先找到能够快速重复运行并观察“重复通知”的方式。理想情况是一条自动化测试;如果暂时做不到,也可以是受控脚本、局部日志或最小测试环境。
反馈回路必须能够在缺陷存在时变红,否则后面的修复无法被证明。
2. 最小化复现
Agent 会逐步移除无关因素,例如:
- 不经过浏览器,只直接调用 Worker;
- 不等待真实时间,使用可控时钟;
- 使用单个任务和固定 Job ID;
- 模拟第一次通知写入成功后,Queue 确认失败;
- 对比单 Worker 与多 Worker。
目标是找到仍然能够产生两条通知的最小系统。
3. 提出 3—5 个有排序、可证伪的假设
本例可能包括:
- 通知已写入数据库,但 Worker 在确认 Job 完成前失败,重试再次写入;
- API 并发保存导致同一任务版本被调度两次;
- 修改截止时间时旧 delayed job 没有失效;
- 多个 Worker 对同一业务事件分别完成了物化;
- 自定义 Job ID 没有按预期构造,两个调度使用了不同 ID。
“BullMQ 有问题”不是合格假设,因为它无法指导下一项观察。合格假设必须说明:如果它是真的,应该看到什么;如果看不到什么,就可以排除。
4. 添加针对性插桩
为了区分假设,可以临时记录:
1 | taskId |
插桩应围绕系统边界,而不是无选择地输出全部对象。日志中也不能包含访问令牌、完整用户内容等敏感数据。
5. 修复、回归和清理
假设如果被证据证实,例如“通知写入后 Worker 重试造成第二次插入”,修复可能是建立数据库唯一约束和幂等写入,而不只是依赖 Queue Job ID。
回归测试应精确重现该边界:
1 | 第一次执行成功写入通知 |
最后重新运行完整测试,并删除临时插桩或将真正有长期价值的指标整理为正式可观测性。
会生成或修改什么
诊断过程中可能产生:
- 最小复现测试或脚本;
- 临时的定向日志和指标;
- 一份假设与证据记录;
- 最终修复;
- 能够阻止复发的回归测试。
它的核心产物不是“改了哪一行”,而是一条可以证明根因和修复有效的证据链。
下一阶段
修复被完整验证后回到正常交付流程。如果问题尚未解决但上下文已接近上限,使用 /handoff 保存复现方式、已排除假设和下一项实验。
十二、handoff:把必要上下文交给一个干净会话
handoff 用于结束当前会话并生成一份面向新会话的交接说明。它不会把整段聊天机械复制过去,而是引用已经存在的规格、Issue、ADR、提交和差异,只补充尚未持久化的关键信息。
什么时候使用
- 对话已经很长,Agent 开始遗忘早期约束;
- 即将从需求讨论切换到独立实现;
- 原型实验完成,需要回到干净的正式实现环境;
- 缺陷诊断尚未结束,但已经积累了复现和排除证据;
- 需要把工作交给另一个人或另一个 Agent 会话。
什么时候不需要使用
- 当前任务即将完成,剩余步骤很少;
- 所有必要信息都已经在一张自包含 Ticket 中,新会话可以直接读取;
- 只是暂停几分钟,不会更换上下文;
- 尚未形成任何可复用结论。
精确调用
从原型分支返回正式流程
1 | /handoff 为 task-board 到期提醒创建新会话交接。说明提醒选择器原型最终选择方案 B;引用规格 Issue #142、BullMQ 调研文档和提醒幂等 ADR;明确原型分支不能合并,下一步是在主工作分支执行 /to-tickets。 |
在缺陷诊断中交接
1 | /handoff 交接“重复提醒”诊断。保留最小复现命令、已经排除的假设、当前插桩字段、相关提交和下一项实验。引用 Issue 与 ADR,不复制完整内容。检查并移除日志中的令牌、Cookie 和个人数据。 |
Agent 接下来会做什么
它会整理:
- 当前目标和完成状态;
- 已经确认的决定;
- 规格、Issue、ADR、研究文档和提交引用;
- 当前分支与工作区状态;
- 已执行的验证及结果;
- 未解决问题;
- 新会话应该执行的第一条命令。
对诊断任务,还应特别记录:
- 最小复现方法;
- 哪些假设已经被什么证据排除;
- 哪些临时插桩仍然存在;
- 下一项最有信息价值的实验。
会生成或修改什么
handoff 通常会在操作系统临时目录中写入一份 Markdown 交接文件,供使用者在新会话中加载。它倾向于引用已有材料,而不是复制整份规格。
交接前会检查敏感信息。终端输出、环境变量、Cookie、令牌和真实用户数据不应进入交接文档。
它不会自动替你完成远程发布,也不会把未提交改动安全地“传送”到另一个分支。分支、提交和工作区状态仍需明确检查。
下一阶段
开启新会话,加载交接文件,先核对目标、分支和工作区,再执行交接中写明的下一步。例如:
1 | 请读取交接文件,然后继续 Issue #147 的重复提醒诊断。 |
十三、把整个案例连起来
下面是一套可以照着执行的顺序。命令中的仓库地址和 Issue 编号是示例,需要替换为真实值。
阶段 1:初始化仓库
1 | /setup-matt-pocock-skills |
确认 GitHub Issues、标签、领域文档路径和 CLAUDE.md 已经建立连接。这一步每个仓库通常只执行一次。
阶段 2:让路由器选择流程
1 | /ask-matt 我准备给 task-board 增加任务到期提醒。需求还不完整,预计跨 Web、API、数据库和 BullMQ Worker,并需要多个会话。 |
获得调研、澄清、规格化和拆票的推荐顺序。
阶段 3:调查第三方约束
1 | /research 调研 BullMQ delayed job、attempts/backoff、自定义 Job ID、重新调度和重复执行的官方语义。只使用一手资料,并把事实与项目建议分开写入 docs/research/bullmq-task-reminders.md。 |
确保后续设计建立在可引用的外部事实之上。
阶段 4:确认产品与领域语义
1 | /grill-with-docs 结合 BullMQ 调研,逐个澄清 task-board 到期提醒的渠道、提前时间、改期、取消、过期和重复发送语义。将确定规则维护到领域文档,必要时记录 ADR,不要实现。 |
结束条件不是“所有问题都问过”,而是规格所需的关键决定已经一致。
阶段 5:按需验证交互
1 | /prototype 为提醒时间选择器制作三个一次性 UI 方案。只验证交互选择,提供一个运行命令,不接持久化,不做生产抽象。 |
只有当实际体验会改变决定时才执行。完成后只保留结论。
阶段 6:发布规格
1 | /to-spec 将任务到期提醒的确认上下文发布为规格,包含用户故事、领域规则、实现决策、测试 seam、验收标准和 Out of Scope。 |
检查生成的远程 Issue 是否准确,然后再继续。
阶段 7:拆分垂直 Ticket
1 | /to-tickets https://github.com/example/task-board/issues/142 |
确认每张 Ticket 都交付一个完整行为,并具有清晰依赖。
阶段 8:逐张 Ticket 实施
每张 Ticket 都使用新会话:
1 | /implement https://github.com/example/task-board/issues/143 |
观察它是否:
- 先从公共 seam 写出一个会正确失败的测试;
- 以单个红—绿切片推进;
- 运行类型检查、目标测试和完整测试;
- 同时按仓库规范与规格审查;
- 只提交当前 Ticket 的文件。
阶段 9:系统诊断复杂缺陷
1 | /diagnosing-bugs 同一任务偶尔收到两条提醒。先建立会变红的最小复现,提出并验证可证伪假设,修复后添加回归测试并清理临时插桩。 |
不要把“加一个去重判断”当作已经找到根因。
阶段 10:必要时交接
1 | /handoff 引用规格、Ticket、ADR、调研和相关提交,记录当前状态、验证结果、未解决问题与新会话的第一步。 |
新会话应从交接中的第一项验证开始,而不是重新阅读整段历史对话。
十四、推荐的工作原则
1. 让文档承担跨会话记忆
对话适合探索,仓库文档和 Tracker 适合长期保存。外部事实进入 research 文档,领域规则进入 CONTEXT.md,重要权衡进入 ADR,可执行范围进入规格和 Ticket。
2. 一张 Ticket 对应一个新实现会话
规格讨论需要宽上下文,实现 Ticket 需要窄上下文。让新的 Agent 只读取当前 Ticket、上游规格和相关代码,通常比让同一会话连续处理整个功能更稳定。
3. 原型代码默认丢弃
原型的成功标准是帮助做出决定,而不是“已经写了不少代码,顺便继续做完”。保留结论,正式实现重新遵循仓库规范、测试和错误处理。
4. 区分事实、决策与实现
research回答外部世界如何工作;grill-with-docs回答项目希望如何工作;to-spec固化已经确认的合同;implement在合同范围内修改代码。
混淆这四类信息,是 AI 编程最常见的返工来源之一。
5. 提前认识有副作用的阶段
setup-matt-pocock-skills 会修改项目文档,to-spec 和 to-tickets 可能创建远程工作项,implement 默认创建 Git 提交。调用前检查目标仓库、工作区和远程 Tracker,调用后审查实际差异。
十五、最后只记住这张决策图
1 | 第一次使用 → setup |
这套 Skills 的价值不在于命令数量,而在于让 Agent 在正确的阶段做正确的事:不确定时先澄清,依赖事实时先调研,需要体验时才做原型,复杂工作先沉淀规格和垂直 Ticket,实现时用测试与审查收口,问题难以解释时依靠证据诊断,最后用交接把上下文安全地带入新会话。







