IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

Matt Pocock 的 Skills 系统:真正的工程,不是氛围编程

鸟窝 2026-06-28 17:10:17 累计浏览 10 次
本机暂存
<p>本文深入分析 Matt Pocock 的 Skills 系统——目前社区中设计最精良、哲学最自洽的 AI Agent 能力单元框架之一。它不追求最大最全,但它对「什么是一个好的 Skill」这个问题的思考深度,远超同类项目。从 Prompt-Driven 到 Skill-Driven——Prompt 消失在对话历史里,Skill 留在工具链里。</p><span id="more"></span><blockquote><p>&quot;Always take small, deliberate steps. The rate of feedback is your speed limit. Never take on a task that&#39;s too big.&quot;<br>步步为营,稳扎稳打。反馈的频率决定了你前行的极限。切忌贪大求全。</p><p>——David Thomas &amp; Andrew Hunt, 《The Pragmatic Programmer》, 1999 年</p></blockquote><p>从 Prompt-Driven 到 Skill-Driven——Prompt 消失在对话历史里,Skill 留在工具链里。要让这个主张从一句口号变成可以落地的体系,需要回答一个具体的问题:<strong>Skill 到底是什么?它长什么样?它是如何工作的?</strong></p><p>本章深入分析 Matt Pocock 的 Skills 系统——目前社区中设计最精良、哲学最自洽的 AI Agent 能力单元框架之一。它不追求最大最全,但它对「什么是一个好的 Skill」这个问题的思考深度,远超同类项目。</p><p>在 GitHub 上,Pocock 用一句话概括了他的设计动机:&quot;real engineering, not vibe coding.」(真正的工程,不是氛围编程。)它来自一个 TypeScript 讲师对软件工程本质的执念——在 AI 让任何人都能在十秒内生成一个可运行应用的年代,重新确认:<strong>工程化的价值是什么?</strong></p><p>2026 年 2 月 3 日,Pocock 将日常使用 Claude Code 时积累的 Skills 整理成一个公共仓库,命名为 <code>mattpocock/skills</code>。仓库的描述行直白得不像一个&quot;开源项目&quot;——&quot;Skills for Real Engineers. Straight from my .claude directory.」(为真正的工程师打造的 Skills。直接来自我的 .claude 目录。)没有发布会,没有精心策划的营销——只是把他每天都在用的东西公开了出来。</p><p>接下来的事情超出了所有人的预期。三个月内,这个仓库获得了约 <strong>97,000 个 GitHub Stars</strong>,8600+ 次 Fork,Pocock 的 AI 工程 newsletter 订阅量在同期飙升至约 60,000 人(作者自述数据)。</p><p>这里的关键词是<strong>时机</strong>,不是「网红程序员」。2026 年初,全世界的开发者正在经历同一件事:AI 编码工具的日常化。Claude Code、Codex、Cursor 已经进入大批工程师的日常工作流。但当开发速度暴涨的同时,代码质量的可控性在暴跌。整个社区在呼唤同一件东西——一套让 AI 编码&quot;从能跑变成可信&quot;的工程方法。Pocock 的 Skills 仓库恰好在这个时刻给出了一个精准的回答:不需要你改变整个流程,不需要你安装任何新工具,只需要把几个 Markdown 文件放到你的 <code>.claude</code> 目录里。</p><p>约 10 万 Star 的背后是这个问题的紧迫性本身。</p><h2 id="2-1-概念起源:一个-TypeScript-讲师的工程执念"><a href="#2-1-概念起源:一个-TypeScript-讲师的工程执念" class="headerlink" title="2.1 概念起源:一个 TypeScript 讲师的工程执念"></a>2.1 概念起源:一个 TypeScript 讲师的工程执念</h2><p>Matt Pocock 是 TypeScript 社区广受认可的教育者。他创立的 Total TypeScript 课程线被成千上万的开发者使用,他在 YouTube 和 Twitter 上的技术内容以清晰、深刻著称。但当他开始大量使用 Claude Code、Codex 等 AI 编码工具后,一个挥之不去的问题开始困扰他。</p><p><img src="/images/image-20260523094440736.png"></p><p><strong>&quot;AI Agent 让开发速度飞跃了一个数量级,但代码质量没有跟上。&quot;</strong> 这不是某个人的抱怨,而是大量实践经验汇聚成的判断。Pocock 在多个场合描述了这种紧张:Agent 可以在几秒内生成几百行代码,但那些代码往往难以理解、难以测试、难以修改——在开发速度飞涨的同时,软件的可维护性历史性地塌陷了。</p><p>他在 Skills 仓库 README 中这样描述核心焦虑:&quot;<strong>Approaches like GSD, BMAD, and Spec-Kit try to help by owning the process. But while doing so, they take away your control and make bugs in the process hard to resolve.</strong>&quot;(GSD、BMAD、Spec-Kit 这类方法试图通过接管流程来帮助你。但在这么做的同时,它们夺走了你的控制权,让流程中产生的 bug 难以定位和修复。)</p><p>这句话透露了他的设计哲学最底层的立场。GSD(Generalized Spec-Driven Development)、BMAD(Big Model Agile Development)、Spec-Kit 这类方法有一个共同特征:它们试图<strong>接管流程</strong>——定义好阶段、门控、输入输出格式,让 Agent 在这些约束中按部就班地工作。Pocock 承认这种方式有效,但他看到了一个代价:<strong>当你把控制权交给一个标准化的流程时,当流程出问题时你无法介入修复,因为流程本身就是一个黑箱。</strong></p><p>他的解法是反其道而行之:不定义流程,只定义<strong>原子能力</strong>。每个 Skill 做一件事且只做一件事——调试就用 <code>/diagnose</code>,写测试就用 <code>/tdd</code>,对齐需求就用 <code>/grill-me</code>。用户自己决定在什么时机用什么 Skill,而不是被一个预设的流水线推着走。工程师保留对流程的全部控制权,Skill 只是工具,不是规则。</p><p>他把这个理念凝结为四个设计原则:</p><p><strong>小而可组合。</strong> 每个 Skill 只解决一个问题。一个 Skill 修改一个 SKILL.md 文件,一个文件不超过几百行。复杂的工作流通过组合多个 Skill 实现,而非在单个 Skill 中堆积分支逻辑。这种设计使每个 Skill 都易于理解、易于改造、易于替换。</p><p><strong>模型无关。</strong> Skill 是用 Markdown 写的指令文件,不绑定任何特定模型的 API 或格式。同一个 Skill 可以工作在 Claude Code、Codex CLI、Cursor Agent、OpenCode 上——只要这些平台支持加载自定义指令。这种&quot;写一次,到处跑&quot;的开放性是 Pocock 刻意追求的设计属性。</p><p><strong>可改造。</strong> Skill 不是封装好的二进制包——它是一个 Markdown 文件,你可以打开、阅读、修改任何一行。Pocock 的原话是——&quot;Hack around with them. Make them your own. Enjoy.&quot;(随意折腾。把它们变成你自己的。享受它。)</p><p><strong>模型无关不是妥协。</strong> 很多方法论选择绑定特定模型以换取更强的控制力。Pocock 的选择相反——通过放弃平台绑定来换取通用性。这意味着某些高级特性(如 hooks、权限控制)无法在 Skill 层面实现,但换来的是一套可以在任何 Agent 工具上运行的开放标准。</p><p>这四条原则直接塑造了他接下来要解决的四个核心问题。</p><h2 id="2-2-四个失败模式与四个修复"><a href="#2-2-四个失败模式与四个修复" class="headerlink" title="2.2 四个失败模式与四个修复"></a>2.2 四个失败模式与四个修复</h2><p>Pocock 在 README 中写道:&quot;I built these skills as a way to fix common failure modes I see with Claude Code, Codex, and other coding agents.&quot;(我构建这些 Skill,是为了修复我在 Claude Code、Codex 和其他编码 Agent 身上反复看到的失败模式。)</p><p>他归纳出四种。每一种都配了一个来自经典软件工程文献的引语作为锚点——这个做法暗示 Skill 不是 AI 时代的发明,而是<strong>经典工程原则在 AI 时代的重新编码</strong>。</p><p><img src="/images/image-20260523095224862.png"></p><h3 id="2-2-1-失败模式一:Agent-没做我想要的事"><a href="#2-2-1-失败模式一:Agent-没做我想要的事" class="headerlink" title="2.2.1 失败模式一:Agent 没做我想要的事"></a>2.2.1 失败模式一:Agent 没做我想要的事</h3><p>Pocock 引用的是《程序员修炼之道》(The Pragmatic Programmer)中的一句:&quot;<strong>No-one knows exactly what they want.</strong>&quot;(没有人真正知道自己想要什么。)</p><p>这是软件开发中最古老的问题,也是最昂贵的。在传统开发中,解决方案是需求评审、原型、持续沟通——人类之间的对话。在 AI Agent 开发中,问题更加严重:你不只是在对话,你是在把指令输入一个没有生活经验、没有常识背景、对&quot;合理&quot;的判断高度不可预测的系统中。</p><p>Pocock 的修复是一个名为 <code>/grill-me</code> 的 Skill——也许是这个仓库中最有名的一个。它的行为可以概括为:<strong>&quot;无休止地盘问我关于这个计划的每一个方面,一次只问一个问题。沿着决策树的每一个分支走到底,不跳过任何一个。对每个问题,给出你的推荐答案。&quot;</strong></p><p>这不是闲聊。这是一种结构化的、穷举式的需求澄清协议。你无法对一个&quot;盘问&quot;回答&quot;差不多就行&quot;。每个回答都在闭合一个选择分支,缩小歧义空间。一次只问一个问题——不被后续分支带偏,不跳步。对每个问题给出推荐答案——不把负担完全推给你,但你保留否决权。</p><p><code>/grill-with-docs</code> 是这个 Skill 的增强版。它做同样的事,但额外做了两件关键的记录工作:一是将讨论中产生的术语新定义写入 <code>CONTEXT.md</code>(领域共享语言文档),二是将任何不可逆的架构决策记录为 ADR(Architecture Decision Record)。这两个动作本身,就是解决下一个失败模式的关键。</p><h3 id="2-2-2-失败模式二:Agent-过于啰嗦"><a href="#2-2-2-失败模式二:Agent-过于啰嗦" class="headerlink" title="2.2.2 失败模式二:Agent 过于啰嗦"></a>2.2.2 失败模式二:Agent 过于啰嗦</h3><p>Pocock 引用的是 Eric Evans《领域驱动设计》中的话:&quot;<strong>With a ubiquitous language, conversations among developers and expressions of the code are all derived from the same domain model.</strong>&quot;(有了通用语言,无论是开发者之间的日常交流,还是代码的具体实现,就都建立在同一个领域模型之上了。)</p><p>在传统项目中,开发团队和领域专家之间天然存在语言鸿沟——你说&quot;付款确认&quot;,他理解的是&quot;扣款成功&quot;还是&quot;订单确认&quot;?Pocock 指出,在和 AI Agent 协作时,同样的问题以一种新的形式出现了:Agent 被丢进一个项目,没有被教过这个项目用什么词、怎么理解这些词。它只能靠自己推测。结果?&quot;它们用 20 个词来说明一个只需要 1 个词就能表达的概念。&quot;(They use 20 words where 1 will do.)</p><p>修复手段是一份叫做 <code>CONTEXT.md</code> 的文件——项目的领域词汇表。Pocock 举了一个真实的例子:在他自己的 <code>course-video-manager</code> 仓库中:</p><blockquote><p><strong>修改前:</strong> &quot;There&#39;s a problem when a lesson inside a section of a course is made &#39;real&#39; (i.e. given a spot in the file system)&quot;</p><p><strong>修改后:</strong> &quot;There&#39;s a problem with the materialization cascade&quot;</p></blockquote><p>&quot;Materialization cascade&quot;(物化级联)是一个团队内部定义的术语——一旦被记录在 <code>CONTEXT.md</code> 里,Agent 每次读取项目上下文时就能理解它,不再需要用一句半的篇幅来解释同一个概念。这个节省是复利的:一次定义,此后每次会话都受益。</p><p>Pocock 对共享语言的价值做了四点归纳,总结在他 README 中的一个提示框中:</p><ul><li><strong>变量、函数和文件的命名保持一致</strong>——Agent 使用的是共享语言中的词</li><li><strong>代码库更易于导航</strong>——因为一切遵循同一套命名逻辑</li><li><strong>Agent 在&quot;思考&quot;上消耗的 token 更少</strong>——它能用领域术语做精简的内部推理</li><li><strong>人类与 Agent 之间的通信成本持续下降</strong>——每次会话不再需要重新&quot;教&quot;它项目里的词</li></ul><p>共享语言解决的不只是啰嗦问题。它解决的是<strong>知识的外部化与持久化</strong>——让项目知识不再只存在于你的记忆里,而是可以被任何人在任何会话中接入的结构化文档。正如他所说:&quot;这可能是整个仓库中最酷的一项技术。&quot;(It might be the single coolest technique in this repo.)</p><h3 id="2-2-3-失败模式三:代码跑不起来"><a href="#2-2-3-失败模式三:代码跑不起来" class="headerlink" title="2.2.3 失败模式三:代码跑不起来"></a>2.2.3 失败模式三:代码跑不起来</h3><p>第三个失败模式对应第 1 章中 antirez 工作方式的核心原则:<strong>「审查 AI 生成的每一行代码。」</strong></p><p>Pocock 再次引用《程序员修炼之道》:<strong>&quot;Always take small, deliberate steps. The rate of feedback is your speed limit. Never take on a task that&#39;s too big.&quot;</strong>(步步为营,稳扎稳打。反馈的频率决定了你前行的极限。切忌贪大求全。)</p><p>即使你和 Agent 对齐了需求、&quot;完成了&quot;共同语言的建设——它产出的代码仍然可能跑不起来。可能是一个边缘情况没处理,可能是逻辑假设错误,可能是几个模块之间的协动出了问题。这本质上是反馈回路缺失。没有验证的代码,是猜测。</p><p>Pocock 提供了两个专门的 Skill 来弥补这一点。</p><p><strong><code>/tdd</code>——测试驱动开发。</strong> 这个 Skill 包含了一整条精心设计的 TDD 指南:红-绿-重构循环、正确测试和错误测试的详细示范(详见 <code>tests.md</code>)、Mock 使用指南(详见 <code>mocking.md</code>)。其中最有价值的洞见之一是 <strong>&quot;反模式:水平切片&quot;的警告。</strong></p><p>水平切片的意思是:先写完所有测试,再写完所有实现。Pocock 直截了当地说:<strong>别这么做。</strong>(DO NOT write all tests first, then all implementation.)</p><p>它列出的原因很具体:</p><ul><li>批量写的测试验证的是&quot;想象中的行为&quot;,而不是&quot;真实的行为&quot;</li><li>你最终测试的是数据结构和函数签名,而不是用户看到的行为——测试过拟合于实现</li><li>测试对真实的变化变得麻木——行为坏了测试却通过,行为没变测试反而失败</li><li>你跑得比你看到的信息更远——在没理解实现前就对测试结构做了不可逆的承诺</li></ul><p>正确的做法是 <strong>&quot;垂直切片&quot;——一个测试,一个实现,循环往复。</strong> 每次循环都基于上一轮学到的新信息。因为刚刚写完代码,所以你知道精确地知道什么行为重要,以及怎么验证它。Pocock 用一个简单的图表表达:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">错误 (水平切片):</span><br><span class="line"> RED: test1, test2, test3, test4, test5</span><br><span class="line"> GREEN: impl1, impl2, impl3, impl4, impl5</span><br><span class="line"></span><br><span class="line">正确 (垂直切片):</span><br><span class="line"> RED → GREEN: test1 → impl1</span><br><span class="line"> RED → GREEN: test2 → impl2</span><br><span class="line"> RED → GREEN: test3 → impl3</span><br><span class="line"> ...</span><br></pre></td></tr></table></figure><p>第一个测试是&quot;曳光弹&quot;(tracer bullet)——证明整条路径从头到尾能走通。此后每一个新增的测试都回应上一个实现的产物,形成紧密的反馈回路。</p><p><strong><code>/diagnose</code>——系统化调试。</strong> 这六个阶段的循环是:复现(reproduce)→ 最小化(minimise)→ 提出假设(hypothesise)→ 插桩(instrument)→ 修复(fix)→ 回归测试(regression-test)。</p><p>Pocock 特意强调了第六步——修复完成后必须把复现的场景转化为回归测试,否则同一个 bug 迟早会回来。这种设计方式使调试行为本身也变成了知识积累——每修一个 bug,项目的测试资产就多一条。</p><h3 id="2-2-4-失败模式四:我们构建了一团浆糊"><a href="#2-2-4-失败模式四:我们构建了一团浆糊" class="headerlink" title="2.2.4 失败模式四:我们构建了一团浆糊"></a>2.2.4 失败模式四:我们构建了一团浆糊</h3><p>这是四个失败模式中最深刻的一个,也是 Pocock 引用了两位经典作者来压阵的。</p><p><strong>Kent Beck《解析极限编程》:</strong> &quot;Invest in the design of the system every day.&quot;(每天都要花时间打磨系统架构。)</p><p><strong>John Ousterhout《软件设计的哲学》:</strong> &quot;The best modules are deep. They allow a lot of functionality to be accessed through a simple interface.&quot;(最好的模块是深的——大量的功能通过简单的接口访问。)</p><p>问题描述直指痛处:<strong>&quot;Most apps built with agents are complex and hard to change. Because agents can radically speed up coding, they also accelerate software entropy.&quot;</strong>(大多数用 Agent 构建的应用复杂且难以修改。因为 Agent 能极快地加速编码,它们也在加速软件的熵增。)Agent 能极快地加速编码,因此也在加速软件的熵增。代码库的复杂化速度超过了人类开发者驯化它的速度。</p><p>Pocock 的修复不止一个 Skill,而是一套植入在每个 Skill 中的&quot;关心设计&quot;的立场。</p><p><strong><code>/zoom-out</code></strong> 的做法最简单但最有力。当一个 Agent 在修改你不熟悉的代码时,你对它说 <code>/zoom-out</code>,它会退后一步:不和你说实现细节,而是告诉你——这里的系统全貌是什么?有哪些模块?它们如何协作?使用项目中的领域词汇来描述。实际上就是要求 Agent 用<code>CONTEXT.md</code>中的语言给你画一张系统的&quot;地图&quot;。</p><p><strong><code>/improve-codebase-architecture</code></strong> 是修复&quot;一团浆糊&quot;的主力武器。它会系统性地扫描代码库并生成一份 HTML 报告——用可视化的框图展示每个架构问题的前后对比。报告使用 Ousterhout 的&quot;深度模块&quot;术语来诊断——接口是否相对于实现太浅?将复杂度集中到深模块后面。用&quot;删除测试&quot;来判断一个模块是否在&quot;挣自己的位置&quot;——删除它,如果复杂度消失了(而不是散落到 N 个调用者身上),说明它就是个&quot;透传&quot;模块。</p><p>Pocock 建议每隔几天运行一次——不是因为它每次都有新发现,而是**&quot;持续投资设计&quot;本身就是防止架构退化的必要行为。**</p><p><strong><code>/to-prd</code></strong> 也是设计感的体现——在创建 PRD 之前,它会先问你:这个修改会触及哪些模块?不是问&quot;做什么功能&quot;,而是问&quot;影响什么地方&quot;。这让 Agent 和用户在进行具体讨论之前,先在&quot;我们改动哪个模块&quot;这个核心上达成共识。</p><h2 id="2-3-安装与初始化:30-秒上手"><a href="#2-3-安装与初始化:30-秒上手" class="headerlink" title="2.3 安装与初始化:30 秒上手"></a>2.3 安装与初始化:30 秒上手</h2><p>Skills 系统的&quot;零依赖&quot;设计意味着它的安装不是&quot;装一个工具&quot;,而是&quot;复制几个 Markdown 文件&quot;。</p><p><strong>安装命令:</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npx skills add mattpocock/skills</span><br></pre></td></tr></table></figure><p>这个命令运行后,一个交互式界面会让你选择两件事:安装哪些 Skill(全部或按需勾选),以及安装到哪些 Agent 平台(Claude Code、Codex、Cursor 可多选)。选择后,选中的 <code>SKILL.md</code> 文件被复制到对应平台配置目录下(如 Claude Code 对应 <code>~/.claude/skills/</code>)。</p><p>Pocock 特别强调:<strong>务必勾选 <code>/setup-matt-pocock-skills</code>。</strong> 安装完成后,在 Agent 中运行这个 Skill。它会依次询问三个配置问题,建立项目与本地的连接:</p><ol><li><p><strong>选择 Issue 追踪器。</strong> GitHub Issues、Linear,还是本地 <code>.scratch/</code> 目录?这决定了 <code>/to-issues</code>、<code>/to-prd</code>、<code>/triage</code> 等 Skill 的读写目标。</p></li><li><p><strong>定义 Triage 标签。</strong> 在进行 Issue 分诊(<code>/triage</code>)时,使用哪些标签来标记 Issue 的状态?这些标签必须与项目的真实标签体系对应。</p></li><li><p><strong>选择文档保存位置。</strong> <code>CONTEXT.md</code>、ADR、PRD 等文档该放置的项目路径。</p></li></ol><p>这三个问题的答案被写入 <code>.claude/config/</code> 下的配置文件,成为所有 Skill 的共享上下文。套用第 1 章中的分类,这个字段的结构化信息就是系统的 Harness 层——项目别名、命名约定、状态定义。</p><p>安装完成后,你在 Agent 中输入 <code>/</code> 就能看到已经可用的新版 Skill 命令。不需要重新启动,不需要环境变量,不需要 API key。Pocock 对这个设计理念的概括是:&quot;Bam - you&#39;re ready to go.&quot;(砰——可以开工了。)</p><h2 id="2-4-运行机制:一个-Markdown-文件如何改变-Agent-的行为"><a href="#2-4-运行机制:一个-Markdown-文件如何改变-Agent-的行为" class="headerlink" title="2.4 运行机制:一个 Markdown 文件如何改变 Agent 的行为"></a>2.4 运行机制:一个 Markdown 文件如何改变 Agent 的行为</h2><p>到目前我们已经讨论了 Skill 的定义与设计。接下来回答一个更底层的问题:<strong>一个 Markdown 文件,到底怎么变成 Agent 的行为?</strong></p><h3 id="2-4-1-SKILL-md-的文件结构"><a href="#2-4-1-SKILL-md-的文件结构" class="headerlink" title="2.4.1 SKILL.md 的文件结构"></a>2.4.1 SKILL.md 的文件结构</h3><p>每个 Skill 是一个独立的目录,目录下必须有且仅有一个文件:<code>SKILL.md</code>。没有任何其他技术依赖。</p><p><code>SKILL.md</code> 的结构分为两层。第一层是 YAML 前置元数据(frontmatter):</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">name:</span> <span class="string">skill-name</span></span><br><span class="line"><span class="attr">description:</span> <span class="string">One-line</span> <span class="string">summary</span> <span class="string">of</span> <span class="string">what</span> <span class="string">the</span> <span class="string">skill</span> <span class="string">does</span> <span class="string">and</span> <span class="string">when</span> <span class="string">to</span> <span class="string">use</span> <span class="string">it.</span></span><br><span class="line"><span class="meta">---</span></span><br></pre></td></tr></table></figure><p><code>name</code> 是 Skill 的唯一标识,也是用户调用的斜杠命令名称——<code>name: grill-me</code> 对应 <code>/grill-me</code>。</p><p><code>description</code> 承担两项功能:一是给用户看,描述这个 Skill 做什么;二是给 Agent 的<strong>自动匹配器</strong>看——Agent 运行时扫描所有已加载的 Skill 的 description 字段,当用户当前输入语义上与某个 description 匹配时,自动触发该 Skill。</p><p>第二层是 Markdown 正文——这就是 Agent 收到的实际指令。它不是一份供人类阅读的 API 文档,而是一份<strong>写给 Agent 的行为指令</strong>——用的是第二人称,现在是命令式,语气是一个领域专家对一个刚入职的新手程序员做 onboarding——准确、密集、不废话。</p><p>以 <code>/grill-me</code> 为例,它的正文只有一句话:</p><blockquote><p>Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer. Ask the questions one at a time. If a question can be answered by exploring the codebase, explore the codebase instead.</p></blockquote><p>五句话,没有一句浪费:目标(relentlessly interview)、方法(walk down each branch)、具体操作(one-by-one)、附带责任(provide recommended answer)、约束(validate against codebase)。这个 Skill 的行为完全由这五句话定义——简练到没有留任何歧义空间。</p><p>更复杂的 Skill 使用 <strong>&quot;渐进式信息披露&quot;(Progressive Disclosure)</strong> 模式:核心指令写在 <code>SKILL.md</code> 中,更详尽的参考资料放在同级目录下的其他文件里(如 <code>tests.md</code>、<code>mocking.md</code>、<code>LANGUAGE.md</code>),Agent 在需要时通过文件引用来获取更多上下文。这样 Volatile 的知识(指令、核心规则)和持久化的知识(详细示范、术语解释)分离,Skill 文件本身保持精悍。</p><h3 id="2-4-2-Skill-的触发与运行"><a href="#2-4-2-Skill-的触发与运行" class="headerlink" title="2.4.2 Skill 的触发与运行"></a>2.4.2 Skill 的触发与运行</h3><p>一次 Skill 调用经历了四个步骤:</p><ol><li><p><strong>发现(Discovery):</strong> Agent 启动时扫描配置的 Skill 目录,读取所有 <code>SKILL.md</code> 文件的前置元数据,建立 Skill 索引。</p></li><li><p><strong>匹配(Matching):</strong> 当用户发出指令时,Agent 有三种触发 Skill 的方式:<strong>显式调用</strong>——用户键入了斜杠命令(如 <code>/diagnose</code>),直接执行该 Skill;<strong>自动匹配</strong>——Agent 判断用户的输入语义上与某个 Skill 的 description 匹配,自动加载该 Skill 的指令;<strong>Skill 内引用</strong>——一个 Skill 的指令中引用了另一个 Skill 的行为(如 <code>/grill-with-docs</code> 的行为是 <code>/grill-me</code> 的指令加上额外的文档处理逻辑)。</p></li><li><p><strong>加载(Loading):</strong> Agent 将 <code>SKILL.md</code> 的正文注入当前会话的上下文——就像一个虚拟的&quot;项目文档&quot;被读入对话一样。Skill 之间不共享上下文,每个 Skill 在独立的指令空间中执行,避免交叉污染。</p></li><li><p><strong>兼容性(Compatibility):</strong> Skill 指令使用纯自然语言,不调用任何特定 Agent 平台的内置 API。两个不同的 Agent 工具对同一个 SKILL.md 的解释可能略有不同——因为模型在理解自然语言时会产生细微差异——但核心行为是一致的。这种&quot;平台独立的自然语言编程&quot;是 Skills 系统能在 Claude Code、Codex、Cursor、OpenCode 之间自由移植的根本原因。</p></li></ol><h2 id="2-5-实战:用-Skills-系统完成一次开发流程"><a href="#2-5-实战:用-Skills-系统完成一次开发流程" class="headerlink" title="2.5 实战:用 Skills 系统完成一次开发流程"></a>2.5 实战:用 Skills 系统完成一次开发流程</h2><p>逐个解释 Skill 的原理是基础,但把多个 Skill 串起来跑一条完整链路更能说明问题。</p><p>下面以一个具体的微型任务为例:用纯前端技术做一个在浏览器中可玩的贪吃蛇网页游戏——方向键控制蛇的移动,吃食物变长得分,撞墙或撞到自己则游戏结束。</p><p><img src="/images/image-20260530103954805.png"></p><h3 id="2-5-1-第一步:对齐需求(-grill-with-docs)"><a href="#2-5-1-第一步:对齐需求(-grill-with-docs)" class="headerlink" title="2.5.1 第一步:对齐需求(/grill-with-docs)"></a>2.5.1 第一步:对齐需求(<code>/grill-with-docs</code>)</h3><p>这个任务看起来简单——贪吃蛇的规则人人知道——但落到工程实现,立刻冒出一堆需要闭合的决策分支。网格多大?蛇多快?分数怎么算?游戏结束后怎么办?食物怎么生成?</p><p>启动 <code>/grill-with-docs</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">用户: /grill-with-docs 做一个贪吃蛇网页游戏。方向键控制蛇移动,</span><br><span class="line"> 吃食物后蛇变长、分数增加。撞墙或撞到自己则游戏结束。</span><br><span class="line"> 纯前端 HTML/CSS/JS 单文件实现。</span><br></pre></td></tr></table></figure><p>Agent 一次只问一个问题,逐个闭合决策分支:</p><blockquote><p><strong>Q1:</strong> 游戏网格你期望多大?我推荐 20×20——适合桌面端,移动端也不会太小。每个格子 20px,整个画布 400×400。</p></blockquote><p>用户同意。</p><blockquote><p><strong>Q2:</strong> 蛇的初始移动速度?我推荐 150ms&#x2F;步——有挑战但不至于太快。如果要加难度曲线(每吃 5 个食物加速 10ms),现在也可以预留。</p></blockquote><p>用户选择先做固定速度 150ms,难度曲线以后再考虑。</p><blockquote><p><strong>Q3:</strong> 分数系统怎么设计?每个食物 10 分,还是递增?最高分要不要用 localStorage 存下来?</p></blockquote><p>用户确认:每个食物 10 分,最高分用 localStorage 持久化,刷新后保留。</p><blockquote><p><strong>Q4:</strong> 蛇的初始方向?我建议初始状态为静止——玩家按下第一个方向键后蛇才开始移动。避免玩家还没准备好蛇就撞墙了。</p></blockquote><p>用户同意。</p><blockquote><p><strong>Q5:</strong> 如果用户快速连续按方向键(比如当前向右,在 150ms 内快速按了下再按左),应该怎么处理?我建议用 <code>nextDirection</code> 缓冲——键盘事件只写入缓冲变量,游戏循环每次读取后才同步到实际方向。这样可以吃掉多余的输入,防止蛇反向移动。</p></blockquote><p>用户同意。这个交互细节如果不在这步澄清,后面调试会极其痛苦。</p><p>对话结束后,Agent 自动执行了两个写入操作:</p><ul><li>将新产生的术语(<code>GameState</code>、<code>nextDirection</code> 缓冲机制、网格坐标约定 <code>{x, y}</code>、食物随机生成算法 <code>spawnFood()</code>)写入 <code>CONTEXT.md</code></li><li>将&quot;选择 nextDirection 缓冲而非直接写入方向&quot;这个不可逆决策记录为 ADR</li></ul><p>澄清对话本身是瞬态的,但对话的产物——<code>CONTEXT.md</code> 和 ADR——是持久的。下一次任何人(或任何 Agent)打开这个项目,不需要重新解释&quot;为什么用 nextDirection 而不是直接改方向&quot;。</p><h3 id="2-5-2-第二步:生成-PRD(-to-prd)"><a href="#2-5-2-第二步:生成-PRD(-to-prd)" class="headerlink" title="2.5.2 第二步:生成 PRD(/to-prd)"></a>2.5.2 第二步:生成 PRD(<code>/to-prd</code>)</h3><p><code>/grill-with-docs</code> 结束时,Agent 已经积累了足够的信息:核心行为、约束边界、容错策略。现在运行 <code>/to-prd</code>:</p><blockquote><p><code>/to-prd</code> 不需要再问问题——它直接从刚刚的对话中提取信息,合成一个结构化的 PRD 并提交到 Issue 追踪器中。</p></blockquote><p>PRD 被提交为一个 Issue,包含:问题陈述、用户故事(四条——蛇的移动控制、食物消费与得分、碰撞与游戏结束、最高分持久化)、验收标准(十六条,全部可自动化验证)、非功能需求(150ms 循环间隔、首次渲染 &lt; 500ms、零外部依赖)。</p><h3 id="2-5-3-第三步:拆分为独立-Issue(-to-issues)"><a href="#2-5-3-第三步:拆分为独立-Issue(-to-issues)" class="headerlink" title="2.5.3 第三步:拆分为独立 Issue(/to-issues)"></a>2.5.3 第三步:拆分为独立 Issue(<code>/to-issues</code>)</h3><p>这个 PRD 自然包含四个可独立推进的任务。<code>/to-issues</code> 读取 PRD Issue,将其拆分为四个独立 Issue:</p><blockquote><p><strong>Issue #12:</strong> 创建游戏画布与渲染层——初始化 20×20 Canvas,实现 <code>drawGrid()</code>、<code>drawSnake()</code>、<code>drawFood()</code></p><p><strong>Issue #13:</strong> 实现蛇的移动与键盘控制——<code>gameState</code> 状态对象、方向缓冲 <code>nextDirection</code>、150ms 游戏循环、键盘事件绑定</p><p><strong>Issue #14:</strong> 碰撞检测与食物系统——墙壁碰撞、自身碰撞、食物消费、随机生成</p><p><strong>Issue #15:</strong> 分数系统与游戏状态管理——当前分数&#x2F;最高分显示、游戏结束弹窗、重新开始按钮、localStorage 降级</p></blockquote><p>每个 Issue 都包含独立的验收标准,确保任何一个都可以被检出、实现、测试、合入,而不阻塞其余三个。注意这里的依赖关系:Issue #13 依赖 #12(画布必须先存在),#14 依赖 #13(碰撞检测需要蛇的坐标),#15 依赖 #14(游戏结束触发分数判定)。</p><h3 id="2-5-4-第四步:TDD-实现第一个-Issue(-tdd)"><a href="#2-5-4-第四步:TDD-实现第一个-Issue(-tdd)" class="headerlink" title="2.5.4 第四步:TDD 实现第一个 Issue(/tdd)"></a>2.5.4 第四步:TDD 实现第一个 Issue(<code>/tdd</code>)</h3><p><code>/tdd</code> 的详细机制已在 2.2.3 中展开。这里用一个具体迭代来展示垂直切片如何运作。</p><p>启动 <code>/tdd</code>,选择 Issue #12:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">Agent: 我先写第一个测试——验证画布初始化后能渲染一个空网格。</span><br><span class="line"></span><br><span class="line">Test (RED):</span><br><span class="line"> it(&#x27;renders a 20x20 grid on canvas&#x27;, () =&gt; &#123;</span><br><span class="line"> const canvas = initGameCanvas();</span><br><span class="line"> expect(canvas.width).toBe(400);</span><br><span class="line"> expect(canvas.height).toBe(400);</span><br><span class="line"> const ctx = canvas.getContext(&#x27;2d&#x27;);</span><br><span class="line"> // 验证 drawGrid 调用后 canvas 不为空白</span><br><span class="line"> drawGrid(ctx);</span><br><span class="line"> const imageData = ctx.getImageData(0, 0, 400, 400);</span><br><span class="line"> expect(isCanvasBlank(imageData)).toBe(false);</span><br><span class="line"> &#125;);</span><br><span class="line"> // FAIL: initGameCanvas is not defined</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Agent: 现在写最小实现让测试通过。</span><br><span class="line"></span><br><span class="line">Impl (GREEN):</span><br><span class="line"> function initGameCanvas(): HTMLCanvasElement &#123;</span><br><span class="line"> const canvas = document.createElement(&#x27;canvas&#x27;);</span><br><span class="line"> canvas.width = 400;</span><br><span class="line"> canvas.height = 400;</span><br><span class="line"> return canvas;</span><br><span class="line"> &#125;</span><br><span class="line"> // PASS</span><br></pre></td></tr></table></figure><p>然后写第二个测试:蛇的初始渲染——长度 3,位于网格中央,水平排列——RED → GREEN。第三个测试:食物渲染为红色方块,位置在蛇身范围之外——RED → GREEN。</p><p>三个垂直切片完成后,Issue #12 已经有了三条可验证的行为保证。Agent 继续完成 <code>drawGrid()</code>、<code>drawSnake()</code>、<code>drawFood()</code> 函数,每条都在其对应的测试通过后合并到实现中。</p><h3 id="2-5-5-第五步:调试一个失败的测试(-diagnose)"><a href="#2-5-5-第五步:调试一个失败的测试(-diagnose)" class="headerlink" title="2.5.5 第五步:调试一个失败的测试(/diagnose)"></a>2.5.5 第五步:调试一个失败的测试(<code>/diagnose</code>)</h3><p>生成的html直接里浏览器打开没有启动有游戏,原因是引入的javascript方式的问题,本地以文件的方式打开有问题。不过已开始的时候我们不知道原因,我们可以使用这个斜杠命令诊断这个问题。</p><p><img src="/images/image-20260530105205220.png"></p><p>它给出了两个修复方案,我选择第二种,最后它修复完成:</p><p><img src="/images/image-20260530105315627.png"></p><h3 id="2-5-6-第六步:理解陌生代码(-zoom-out)"><a href="#2-5-6-第六步:理解陌生代码(-zoom-out)" class="headerlink" title="2.5.6 第六步:理解陌生代码(/zoom-out)"></a>2.5.6 第六步:理解陌生代码(<code>/zoom-out</code>)</h3><p>Issue #14 需要实现碰撞检测和食物系统,但接手这个任务的开发者(或 Agent)对前面已经写好的游戏循环和状态结构不熟悉。</p><p>启动 <code>/zoom-out</code>:</p><p><img src="/images/image-20260530105414026.png"></p><p><code>/zoom-out</code> 的输出没有任何代码级别的细节。它提供的是一张&quot;地图&quot;——你要改的东西在哪里、它和其他东西的关系、用这个项目的语言怎么描述你要做的事。Agent 有了这张地图,后续的修改才不至于偏离到不该碰的模块。</p><p>貌似没有更新卡片和提交代码的skill,所以我使用我开发的<a href="https://github.com/smallnest/goal-workflow/tree/master/skills/ship-it">ship-it</a>提交代码给关闭卡片。</p><p><img src="/images/image-20260530105810854.png"></p><p><img src="/images/image-20260530105830752.png"></p><h3 id="2-5-7-第七步:周期性架构检查(-improve-codebase-architecture)"><a href="#2-5-7-第七步:周期性架构检查(-improve-codebase-architecture)" class="headerlink" title="2.5.7 第七步:周期性架构检查(/improve-codebase-architecture)"></a>2.5.7 第七步:周期性架构检查(<code>/improve-codebase-architecture</code>)</h3><p>四个 Issue 全部合入后,运行一次 <code>/improve-codebase-architecture</code>。</p><blockquote><p>Agent: 生成 HTML 报告 → 另存至 <code>/tmp/architecture-review-xxx.html</code> → 自动用浏览器打开。</p></blockquote><p>报告找出了两个值得关注的架构问题:</p><p><strong>渲染与逻辑未分离。</strong> 当前 <code>gameLoop()</code> 中混合了状态更新(<code>moveSnake</code>、<code>checkCollision</code>、<code>checkFoodCollision</code>)和 Canvas 绘制(<code>drawGrid</code>、<code>drawSnake</code>、<code>drawFood</code>)。如果未来要换渲染方案——比如用 DOM 格子替代 Canvas,或者加一个 mini-map——逻辑层应该可以独立于渲染层运行。</p><p>建议:将 <code>gameLoop</code> 拆分为 <code>update()</code>(纯逻辑,返回新 state)和 <code>render()</code>(纯绘制,读取 state)。两个函数各自独立可测试。</p><p><strong>分数持久化直接操作 localStorage。</strong> 当前 <code>saveHighScore()</code> 和 <code>loadHighScore()</code> 直接调用 <code>localStorage.setItem/getItem</code>。如果未来有其他数据也需要本地持久化(如游戏设置、成就系统),当前模式会导致散落的 localStorage 调用。</p><p>建议:提取一个 <code>StorageAdapter</code> 接口(<code>get</code>、<code>set</code>、<code>remove</code> 三个方法),让分数模块和其他模块都依赖接口而非直接操作 localStorage。</p><p>Pocock 建议每隔几天运行一次这个 Skill。在上面的例子中,它发现的问题不在任何一个 Issue 的实现中——它们是跨模块的架构问题,只有在四个模块全部上线后才能浮现。这就是&quot;一团浆糊&quot;的典型来源:个体的修改各自合理,但组合起来产生了意料之外的耦合。<code>/improve-codebase-architecture</code> 的作用就是把这种耦合从隐式变为显式。</p><h3 id="2-5-8-一条完整链路的意义"><a href="#2-5-8-一条完整链路的意义" class="headerlink" title="2.5.8 一条完整链路的意义"></a>2.5.8 一条完整链路的意义</h3><p>从 <code>/grill-with-docs</code> → <code>/to-prd</code> → <code>/to-issues</code> → <code>/tdd</code> → <code>/diagnose</code> → <code>/zoom-out</code> → <code>/improve-codebase-architecture</code>,七步走了一个闭环:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">对齐意图 → 结构化需求 → 可并行分解 → 垂直切片实现 → 系统化调试 → 上下文导航 → 架构审计</span><br></pre></td></tr></table></figure><p>它的模式不是&quot;阶段一 → 阶段二&quot;的流水线,而是<strong>在需要的时间点插入正确的行为</strong>。一个 Skill 只做一件事——用 Pocock 的话——它是小而可组合的——且这一步结束后的产物自动变成下一个 Skill 的输入。</p><h2 id="2-6-两个值得单独讨论的-Skill"><a href="#2-6-两个值得单独讨论的-Skill" class="headerlink" title="2.6 两个值得单独讨论的 Skill"></a>2.6 两个值得单独讨论的 Skill</h2><p>上述四个失败模式中讨论了 <code>/grill-me</code>、<code>/tdd</code>、<code>/zoom-out</code>、<code>/improve-codebase-architecture</code> 等 Skill。还有两个 Skill 值得单独用一节篇幅展开——不是因为它们在体系中&quot;更大&quot;,而是它们各自触及了 AI 软件工程的两个根本性问题:<strong>调试知识的可传递性</strong>和<strong>会话边界的可交接性</strong>。</p><h3 id="2-6-1-diagnose:调试不是「看代码」,是「建反馈回路」"><a href="#2-6-1-diagnose:调试不是「看代码」,是「建反馈回路」" class="headerlink" title="2.6.1 /diagnose:调试不是「看代码」,是「建反馈回路」"></a>2.6.1 <code>/diagnose</code>:调试不是「看代码」,是「建反馈回路」</h3><p>2.2.3 简要介绍了 <code>/diagnose</code> 的六阶段循环。但那只是外壳。打开它的 <code>SKILL.md</code>,第一段话就会让有经验的调试者沉默:</p><blockquote><p><strong>Phase 1 — Build a feedback loop</strong></p><p><strong>This is the skill.</strong> Everything else is mechanical. If you have a fast, deterministic, agent-runnable pass&#x2F;fail signal for the bug, you will find the cause — bisection, hypothesis-testing, and instrumentation all just consume that signal. If you don&#39;t have one, no amount of staring at code will save you.</p><p>Spend disproportionate effort here. <strong>Be aggressive. Be creative. Refuse to give up.</strong></p><p>(阶段一 —— 建立反馈回路。<strong>这就是 Skill 本身。</strong> 其他的一切都是机械的。如果你有一个快速、确定性、Agent 可运行的&quot;通过&#x2F;失败&quot;信号来判断 bug,你就会找到原因——二分法、假设检验、插桩都在消费这个信号。如果你没有这个信号,看再多代码也救不了你。在这一步投入不成比例的精力。<strong>要主动、要有创造力、要拒绝放弃。</strong>)</p></blockquote><p>&quot;<strong>This is the skill.</strong>&quot; 指向的不是六阶段循环,也不是假设生成和验证——而是<strong>建立反馈回路</strong>。Pocock 在此拆解了一个关键洞察:调试的价值不来源于人的判断力,而在于一个可以自动判决&quot;问题是否还在&quot;的信号。后面五个阶段只是机械地消费这个信号。</p><p>这句话对 AI 时代的意义比它看起来更重。传统调试依赖一个资深工程师的直觉——他看到一段代码就知道&quot;这里不太对&quot;。但 Agent 没有直觉。Agent 只有循环——反复运行一段代码、检查输出、比对抗预期。这恰恰是 Agent 最擅长的事。但前提是:你得给它一个能跑出结论的循环。</p><p><code>/diagnose</code> 列出了九种构建反馈回路的方式,按推荐顺序排列:</p><ol><li><strong>失败的测试</strong>——能触及 bug 的任何接缝处的测试(单元&#x2F;集成&#x2F;E2E)</li><li><strong>Curl&#x2F;HTTP 脚本</strong>——对 dev server 的请求-响应验证</li><li><strong>CLI 命令</strong>——用固定输入运行,diff stdout 与已知正确的快照</li><li><strong>无头浏览器脚本</strong>——Playwright&#x2F;Puppeteer 驱动 UI,断言 DOM&#x2F;控制台&#x2F;网络</li><li><strong>回放已捕获的 trace</strong>——把真实请求或事件日志保存到磁盘,在隔离环境中重放</li><li><strong>一次性的 harness</strong>——启动系统的最小子集(一个服务 + mock 依赖),单个函数调用触发 bug 路径</li><li><strong>属性&#x2F;模糊测试</strong>——如果 bug 是&quot;有时输出不对&quot;,跑 1000 次随机输入找失败模式</li><li><strong>二分 harness</strong>——如果 bug 出现在两个已知状态之间,自动化 <code>git bisect run</code></li><li><strong>差分回路</strong>——相同的输入跑老版本和新版本,diff 输出</li><li><strong>人机回路 bash 脚本</strong>——如果必须由人点击,用结构化脚本驱动人工操作、把输出喂回给 Agent</li></ol><p>这个清单的价值不只是&quot;方法多&quot;——它的排序本身就是一条经验曲线:越往上越自动化、越可作为&quot;裁定器&quot;复用在后续所有调试活动中。每向上爬一级,你的调试体系就少一分对人的依赖。</p><p><code>/diagnose</code> 还要求<strong>把反馈回路当作产品来迭代</strong>——有了回路之后,能不能让它更快?更锐利(断言精确症状而不是&quot;没 crash&quot;)?更确定性(固定时间、种入随机种子、隔离文件系统、冻结网络)?一个 30 秒的 flaky 循环几乎不比没有循环好;一个 2 秒的确定性循环是调试超级武器。</p><p>命令式的另一面是<strong>禁止在没有回路时进入假设阶段</strong>。<code>/diagnose</code> 在这个点上的措辞不留余地:<strong>&quot;Do not proceed to Phase 2 until you have a loop you believe in.&quot;</strong>(不建立你确信的反馈回路,就不要进入第二阶段。)</p><p>这六阶段的完整流程形成了一个严密的闭环:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Build Loop → Reproduce → Hypothesise → Instrument → Fix + Regression → Cleanup + Post-mortem</span><br></pre></td></tr></table></figure><p>其中 Phase 3 的假设生成有一个重要的约束:<strong>一次生成 3-5 个有排序的假设,每个假设必须是可证伪的</strong>(&quot;如果 X 是原因,那么改变 Y 会让它消失,改变 Z 会让它更糟糕&quot;)。单假设锚定在第一个灵感上——一个老调试者的直觉陷阱。</p><p>Phase 5 的回归测试要求也超出了常规实践:<strong>&quot;在写修复之前先写回归测试——但前提是存在一个正确的接缝。&quot;</strong> 如果当前架构产生不了正确的测试接缝,说明这个 bug 揭示了架构问题——应当记录并移交 <code>/improve-codebase-architecture</code>。</p><p>Phase 6 的收尾也同样精准:原始复现消失、回归测试通过、所有 <code>[DEBUG-xxx]</code> 探测代码用 grep 前缀一键清理、一次性原型删除、<strong>正确的假设</strong>被写入 commit message。最后一条——把&quot;为什么&quot;写进 commit——是知识的固化。下一次有人读这个 commit(包括 Agent),不需要重新推演推理链条。</p><p><code>/diagnose</code> 最有价值的不是它的步骤多精密,而是它把调试从一种&quot;资深工程师的直觉&quot;转化为一种<strong>系统化的协议</strong>。这个协议可以被传授、被遵循、被验证——这正是 Skill 哲学的核心:把隐性知识外化。</p><h3 id="2-6-2-handoff:Agent-会话不是永恒的"><a href="#2-6-2-handoff:Agent-会话不是永恒的" class="headerlink" title="2.6.2 /handoff:Agent 会话不是永恒的"></a>2.6.2 <code>/handoff</code>:Agent 会话不是永恒的</h3><p>如果说 <code>/diagnose</code> 解决的是&quot;一个 session 内的反馈回路&quot;,那么 <code>/handoff</code> 解决的是&quot;两个 session 之间的信息传递&quot;。它的全部指令只有六句话,但每句话都指向 AI 开发流程中一个被严重低估的问题:</p><blockquote><p>Write a handoff document summarising the current conversation so a fresh agent can continue the work. Save to the temporary directory of the user&#39;s OS — not the current workspace.</p><p>Include a &quot;suggested skills&quot; section in the document, which suggests skills that the agent should invoke.</p><p>Do not duplicate content already captured in other artifacts (PRDs, plans, ADRs, issues, commits, diffs). Reference them by path or URL instead.</p><p>Redact any sensitive information, such as API keys, passwords, or personally identifiable information.</p><p>If the user passed arguments, treat them as a description of what the next session will focus on and tailor the doc accordingly.</p><p>(写一份交接文档,总结当前对话,让一个新的 Agent 可以继续工作。保存到用户操作系统的临时目录——不是当前工作区。在文档中包含一个&quot;建议的 Skill&quot;部分,列出下一个 Agent 应该调用的 Skill。不要重复已经被其他工件(PRD、计划、ADR、Issue、commit、diff)记录的内容,改为通过路径或 URL 引用。脱敏任何敏感信息,如 API key、密码或个人身份信息。如果用户传入了参数,将它们视为对下一个会话重点的描述,按此来定制文档。)</p></blockquote><p>这六句话背后有五个精细的设计决策:</p><p><strong>(1)&quot;不要重复已回答的问题。&quot;</strong> 这是交接文档最常见的失败模式——把 PRD、ADR、Issue、commit diff 的内容重新抄写一遍。应该引用路径,而不是复制内容。一份好的 handoff 只包含&quot;除了已有工件之外还需要知道的东西&quot;——当前卡在哪里、为什么选择了 A 而不是 B、还有哪个假设尚未验证。</p><p><strong>(2)&quot;建议下一步要用的 Skill。&quot;</strong> 交接不只是传递信息,也是传递工作状态的上下文。如果上一个 Agent 在 <code>/grill-with-docs</code> 中完成了对齐但还没写 PRD,交接文档应该明确指出&quot;下一步运行 <code>/to-prd</code>&quot;。这让&quot;交接&quot;不再是&quot;把东西放在那里等人来找&quot;,而是&quot;主动传递下一步行动指引&quot;。</p><p><strong>(3)&quot;保存到操作系统临时目录,不是工作区。&quot;</strong> 这是一个工程直觉:工作区不应当是垃圾场。交接文档是瞬态的——它将被下一个会话消费后删除。它存放在 <code>$TMPDIR</code> 或 <code>/tmp</code> 中,生命周期和它服务的任务一样短。</p><p><strong>(4)&quot;自动脱敏。&quot;</strong> 这是 Pocock 的安全直觉:交接文档中不准出现 API key、密码、个人身份信息。虽然 Agent 不会把这些发到外部,但交接文档以明文存储在磁盘上——它不应该成为一个意外的秘密泄露点。</p><p><strong>(5)&quot;按用户描述的下一个会话目标来定制。&quot;</strong> 如果用户运行 <code>/handoff &quot;继续做 setup 页面&quot;</code>,交接文档应该侧重 setup 页面的当前状态和待解决的设计问题,而不是重复整个项目的 PRD。</p><p>这五个决策共同建立的是一种**&quot;半衰期&quot;意识**:一个会话可以持续很长时间,但它不能永远存在。Agent 的上下文窗口有边界、API 会话有时间限制、人类的专注力也有极限。 <code>/handoff</code> 承认了这个物理现实,并提供了一个工程化的应对方案:在边界处把状态压缩为一份上下文高效的文档,让下一个会话可以冷启动。</p><p>它是 Pocock 的 Skills 体系在与项目交接和工作连续性方面的延伸——它回答了&quot;当 AI 工程会话本身需要考虑工程化时,我们如何设计会话的接口&quot;。这需要交接和状态传递,交接和状态传递需要结构化——这是工程实践的本质。</p><h2 id="2-7-全量-Skill-一览"><a href="#2-7-全量-Skill-一览" class="headerlink" title="2.7 全量 Skill 一览"></a>2.7 全量 Skill 一览</h2><p>以下是 <code>mattpocock/skills</code> 仓库中全部 22 个 Skill 的总览表(不含已废弃的 4 个和开发中的 4 个)。分类沿用 Pocock 自己的目录结构。</p><p><strong>Engineering Skills(工程类)</strong>——日常编码工作中使用的核心技能:</p><table><thead><tr><th>Skill</th><th>功能</th><th>一句话描述</th></tr></thead><tbody><tr><td><code>/diagnose</code></td><td>系统化调试</td><td>六阶段循环:建反馈回路→复现→假设→插桩→修复→回归</td></tr><tr><td><code>/grill-with-docs</code></td><td>对齐盘问 + 文档沉淀</td><td>盘问每个决策分支,同步更新 CONTEXT.md 和 ADR</td></tr><tr><td><code>/improve-codebase-architecture</code></td><td>架构深度改进</td><td>扫描代码库,生成 HTML 报告,找出&quot;深度模块&quot;机会</td></tr><tr><td><code>/prototype</code></td><td>抛弃型原型</td><td>快速搭建终端或 UI 原型,验证设计后丢弃</td></tr><tr><td><code>/setup-matt-pocock-skills</code></td><td>项目初始化</td><td>配置 Issue 追踪器、Triage 标签、文档路径;其他工程 Skill 的前置步骤</td></tr><tr><td><code>/tdd</code></td><td>测试驱动开发</td><td>红-绿-重构循环,垂直切片,禁止水平切片</td></tr><tr><td><code>/to-issues</code></td><td>PRD 拆分为 Issue</td><td>将 PRD 或 Spec 按垂直切片拆解为可独立领取的 Issue</td></tr><tr><td><code>/to-prd</code></td><td>对话合成为 PRD</td><td>从对话上下文中提取信息,生成结构化 PRD 并提交到 Issue 追踪器</td></tr><tr><td><code>/triage</code></td><td>Issue 分诊</td><td>按状态机模型对 Issue 进行分类和标签管理</td></tr><tr><td><code>/zoom-out</code></td><td>系统视角导航</td><td>退后一步给出模块全景地图,使用项目领域词汇描述</td></tr></tbody></table><p><strong>Productivity Skills(生产力类)</strong>——通用工作流工具,不限于编码:</p><table><thead><tr><th>Skill</th><th>功能</th><th>一句话描述</th></tr></thead><tbody><tr><td><code>/caveman</code></td><td>超压缩通信</td><td>去掉冠词、填充词、客套话,节省约 75% token</td></tr><tr><td><code>/grill-me</code></td><td>纯粹需求盘问</td><td>与 <code>/grill-with-docs</code> 相同的穷举式盘问,但不写文档</td></tr><tr><td><code>/handoff</code></td><td>会话交接</td><td>将当前对话压缩为交接文档,供下一会话冷启动</td></tr><tr><td><code>/write-a-skill</code></td><td>创建新 Skill</td><td>为新建 Skill 提供正确的文件结构、渐进式信息披露和打包资源</td></tr></tbody></table><p><strong>Misc Skills(杂项)</strong>——特定场景的一次性工具:</p><table><thead><tr><th>Skill</th><th>功能</th><th>一句话描述</th></tr></thead><tbody><tr><td><code>/git-guardrails-claude-code</code></td><td>Git 安全护栏</td><td>为 Claude Code 设置 hooks,拦截危险的 git 命令</td></tr><tr><td><code>/migrate-to-shoehorn</code></td><td>测试迁移</td><td>将 <code>as</code> 类型断言迁移为 @total-typescript&#x2F;shoehorn</td></tr><tr><td><code>/scaffold-exercises</code></td><td>练习脚手架</td><td>创建带章节、问题、解答和讲解的练习目录结构</td></tr><tr><td><code>/setup-pre-commit</code></td><td>预提交钩子</td><td>安装 Husky + lint-staged + Prettier + 类型检查 + 测试</td></tr></tbody></table><p><strong>Personal Skills(个人类)</strong>——Pocock 自己使用的非通用技能,仅供参考:</p><table><thead><tr><th>Skill</th><th>功能</th><th>一句话描述</th></tr></thead><tbody><tr><td><code>/edit-article</code></td><td>文章编辑</td><td>重构章节、提升清晰度、收紧文字</td></tr><tr><td><code>/obsidian-vault</code></td><td>Obsidian 笔记</td><td>在 Obsidian vault 中搜索、创建、管理笔记</td></tr></tbody></table><p><strong>开发中(In-Progress)</strong>——尚未正式发布,功能可能变更:</p><table><thead><tr><th>Skill</th><th>功能</th><th>一句话描述</th></tr></thead><tbody><tr><td><code>/review</code></td><td>双轴代码审查</td><td>Standards(编码规范)+ Spec(需求符合性)双轴审查,并行子 Agent 执行</td></tr><tr><td><code>/writing-beats</code></td><td>节拍式叙事写作</td><td>每次只写一个&quot;节拍&quot;,写完提供下一方向选项,逐段推进</td></tr><tr><td><code>/writing-fragments</code></td><td>写作碎片收集</td><td>盘问式挖掘用户的论点、金句、半成形想法,汇总为未来文章的素材库</td></tr><tr><td><code>/writing-shape</code></td><td>文章塑形打磨</td><td>将一堆原始素材通过对话打磨成可发表文章,逐段推敲格式和结构</td></tr></tbody></table><p>后三个写作 Skill 构成 Pocock 为自己设计的写作工作流三阶段:碎片收集 → 节拍叙事 → 文章塑形。</p><p><strong>已废弃(Deprecated)</strong>——已被其他 Skill 取代或不再维护:</p><table><thead><tr><th>Skill</th><th>功能</th><th>被替代原因</th></tr></thead><tbody><tr><td><code>design-an-interface</code></td><td>接口设计探索</td><td>功能并入 <code>/prototype</code></td></tr><tr><td><code>qa</code></td><td>对话式 QA 会话</td><td>功能并入 <code>/triage</code> 和 <code>/to-issues</code></td></tr><tr><td><code>request-refactor-plan</code></td><td>重构计划</td><td>功能并入 <code>/improve-codebase-architecture</code></td></tr><tr><td><code>ubiquitous-language</code></td><td>统一语言提取</td><td>功能并入 <code>/grill-with-docs</code> 的 CONTEXT.md 更新机制</td></tr></tbody></table><p>此表中的 Engineering Skills 构成了 Pocock 体系的核心——10 个 Skill 覆盖了意图对齐、需求结构化、测试驱动实现、系统化调试、代码审查、架构审计的完整闭环。Productivity Skills 解决的是&quot;人类与 Agent 的通信效率&quot;——压缩、对齐、交接、创造。两类 Skills 互为补充:Engineering 决定产出质量,Productivity 决定协作效率。</p><h2 id="2-8-本章小结"><a href="#2-8-本章小结" class="headerlink" title="2.8 本章小结"></a>2.8 本章小结</h2><p>Matt Pocock 的 Skills 系统是 AI 时代软件工程方法论图谱中的基石项目。它的贡献不在数量——这方面后续的 superpowers 和 gstack 远在其上——而在<strong>回答了最重要的问题:</strong></p><p><strong>一个可复用的 AI 工程能力单元应该如何设计?</strong></p><p>它的回答是四个原则:<strong>小而可组合</strong>——一个 Skill 只做一件事;<strong>描述即行为</strong>——Skill 的唯一可执行逻辑是 Markdown 中的自然语言指令;<strong>模型无关</strong>——不绑定任何特定模型或平台;<strong>可改造</strong>——用户始终保留修改任何 Skill 的全部权利。</p><p>这四个原则代表了一个价值判断:<strong>工程师保留对流程的全部控制权。</strong> 工具只提供服务,流程应始终在工程师手中。</p><p>在这个哲学之下,Skills 系统通过四种方式解决四种失败模式:<code>/grill-me</code> + 共享语言(CONTEXT.md)解决&quot;意图不一致&quot;和&quot;AI 过于啰嗦&quot;;<code>/tdd</code> + <code>/diagnose</code> 解决&quot;代码跑不起来&quot;;<code>/zoom-out</code> + <code>/improve-codebase-architecture</code> 解决&quot;一团浆糊&quot;。这不是零散的 Skill 拼凑——而是一套覆盖&quot;意图→通信→实现→设计&quot;全闭环的工程化体系。</p><p><img src="/images/image-20260523095648229.png"></p><p>这个体系为全书奠定了基础:</p><ul><li>第 3 章的 <strong>Spec-Driven Development</strong> 在 Skills 的基础上扩展为更完整的规格管理——&quot;先定合约再写代码&quot;;</li><li>第 5 章的 <strong>gstack</strong> 将 Skills 思维贯彻为 23 个专业角色——&quot;一人成军&quot;的虚拟工程团队;</li><li>第 6 章的 <strong>superpowers</strong> 用 159K+ Stars 证明了 Skills 可以是社区级的基础设施;</li><li>第 10 章的 <strong>Harness Engineering</strong> 则进一步讨论了为 AI Agent 提供运行环境需要的结构化基础设施——hooks、权限模型、配置管理——是 Skills 系统在平台层面的工程支撑。</li></ul><p>但所有这些更复杂的体系,其起点都是一个简单的想法:回到一个 Markdown 文件的纯粹。「做一个功能」不如「写一个 Skill」;「跑一条流水线」不如「积累知识」;「用 AI 替代我的判断」不如「用 AI 放大我的判断」。</p><p>Pocock 在 README 结尾处写道:<strong>&quot;Software engineering fundamentals matter more than ever.&quot;</strong> 软件工程的基本原则比以往任何时候都更重要。这正是全书中继续的旋律——从第 2 章到第 18 章,用一套完整的案例来证明。</p><p>下一章将展开 Skills 思维的第一种大规模应用:Spec-Driven Development——当 Skill 不再只是&quot;一个能力单元&quot;,而是&quot;你的项目规格&quot;和&quot;测试和代码之间的合约&quot;。</p>

同分类推荐文章

  1. Understand-Anything:代码知识图谱 (2026-06-28 16:30:00)
  2. Anthropic 官方插件:AI Agent 的领域知识插件 (2026-06-28 16:00:00)
  3. agent-skills:用生产级工程纪律武装 AI Agent (2026-06-28 15:30:00)

查看更多 AI 文章 →

建议继续学习

  1. GitHub中的README.MD文件编写语法 (累计阅读 5,598)
  2. 关于恐惧的自白 (累计阅读 5,009)
  3. 测试驱动开发(TDD)跟敏捷开发有冲突 (累计阅读 4,676)
  4. 实践中的重构 (累计阅读 4,003)
  5. 为什么创业公司需要写博客? (累计阅读 3,776)
  6. 一些做产品的项目经验:立项、流程、文档 (累计阅读 3,682)
  7. 在公众号中优雅地呈现代码 (累计阅读 3,430)
  8. 程序员如何写出一份好的文档? (累计阅读 3,361)
  9. 给明年依然年轻的我们 (累计阅读 3,347)
  10. Omi应用md2site发布-markdown转网站利器 (累计阅读 3,066)