wth2jhl.online

Back

“Developing real applications is hard. 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. These skills are designed to be small, easy to adapt, and composable.” —— mattpocock/skills README 第一段


一、为什么我会去翻这个仓库#

起因是我在读 anthropic-cybersecurity-skills(817 个 SKILL.md 那篇写过)的时候,被它”靠 description 触发”的机制勾起了兴趣。我开始想:一个 agent skill 文件到底写到什么颗粒度才算对?描述多详细?SKILL.md 自身该不该承载流程?什么时候该把内容拆成 tests.md、mocking.md 这种 sibling 文档?

Matt Pocock 这个仓库是绕不开的参考——他在 TypeScript 教育圈子里 6 万订阅者,自带 “real engineering, not vibe coding” 的招牌,而且他这套 skills 每天在真生产里用,不停在更新。

我把它 git clone 下来:3.3 MB,34 个 SKILL.md,4 个 README,4 篇 ADR。比起 Anthropic Cybersecurity Skills 的 817 个,这个数字很轻,但每个文件都写得很重。我用了一天把它读完,整理出下面这篇文章。

我给的判断:这是一个”agent 工程化的最佳实践样本”,不是”agent 工程化的解决方案”。它不试图用一两个大流程把所有开发场景吞掉,而是把开发拆成 30 个小而互相引用的命令,让你自己挑、自己组合。


二、目录长得很稀疏,但 bucket 设计透露哲学#

注意三点:

  1. engineering 和 productivity 是 promoted bucket——README 顶部会列它们,每个 skill 必须在 .claude-plugin/plugin.json 的 skills 数组里登记,Claude Code plugin 只 ship 这两个 bucket 的 skill。misc、in-progress、deprecated 都不进 plugin。这种”分级发布”机制很少见。

  2. docs/ 镜像 skills/ 的两个 promoted bucket——每个 promoted skill 都有一篇 docs/<bucket>/<skill-name>.md 给人读,URL 都是 https://aihero.dev/skills-<skill-name>,但路径只是组织用,访问入口统一在 aihero.dev。这意味着:人看的文档和 agent 用的 SKILL.md 是两套独立文件,更新一个 skill 要同时改两处。

  3. misc/ 和 deprecated/ 还在仓库里——这跟 Anthropic Cybersecurity Skills 一次性归档不同。Misc 留着但不推广,Deprecated 只有 README 解释”为什么不再用”。这是一种**“温柔弃用”**的策略:你不一定要删掉旧 skill,可以让它们在仓库里慢慢被遗忘。

CLAUDE.md 第二段开宗明义:

“No em-dashes anywhere in this repo’s prose (SKILL.md files, docs, README.md, CHANGELOG.md, ADRs, changesets, code comments). Where a sentence reaches for one, rewrite it instead with a comma, colon, period, parentheses, or a conjunction, whichever the sentence actually wants; never do a blind character substitution.”

——连标点都有规范。这是把自己仓库当出版物的写法。


三、CLAUDE.md + CONTEXT.md + ADR 三件套:让 skill 自己管自己#

Matt 的仓库不只是”装了一堆 skill 文件”,它示范了怎么管理一个不断增长的 skill 集合。

3.1 CLAUDE.md:仓库级的 agent 行为规范#

CLAUDE.md 本身不是 skill,但任何 agent 进到这个目录都会被它约束。它告诉 agent:

  • skill 怎么分类(4 个 bucket 的语义边界)
  • 哪些 bucket 算 promoted,promoted 的 skill 必须出现在 README.md 和 plugin.json
  • 每个 promoted skill 必须有对应的 docs page(按 .agents/writing-docs.md 模板)
  • 每个 SKILL.md 要么 user-invoked(加 disable-model-invocation: true)要么 model-invoked,二选一
  • ask-matt 是 router——任何 skill 增减必须同步更新它的路由表,否则 router 就在撒谎
  • 不要在 prose 里用 em-dash(上一段引的那条)

这是”元 skill”概念——CLAUDE.md 本身就在教 agent 怎么维护 skill 文件集。

3.2 CONTEXT.md:领域词汇表#

Issue tracker
  → 托管 issue 的工具(GitHub Issues / Linear / 本地 .scratch/)

Issue
  → 一个被追踪的工作单元

Decision ticket
  → wayfinder 引入的术语:决议类 issue,不是执行切片
text

这段重要在它显式划清了边界:什么词用什么、什么词禁用(“backlog”、“backlog backend” 都不许用了)。SKILL.md 里 wayfinder 一篇全程用这套词汇,不混用。

一个 agent 进到这种仓库,因为 CONTEXT.md 在上下文里,它读 wayfinder 时不会把 “ticket” 错当成 “Jira ticket”——这就是词汇表的工程价值。

3.3 ADR:为什么是 Claude Code plugin 而不是 Codex#

.agents/adr/0002-ship-as-a-claude-code-plugin.md 解释为什么现在只发 Claude Code plugin。这种 ADR 在 Anthropic Cybersecurity Skills 里是没有的——它没有写”为什么我们采用 5 个 ZIP 切片”的决策记录。

Matt 的做法是把决策当作代码——ADR 跟 skill 放在同一个仓库,未来如果改主意,整个历史跟着走。这跟 Twelve-Factor App 把配置当代码是同一类思想:重要决策不能只存在于创始人脑子里。


四、五个核心 skill:这是真正的设计样板#

30 个 skill 我没法全讲。挑五个最有设计含量的,每个用一段 SKILL.md 原文 + 我的解读。

4.1 wayfinder——把”模糊大活”拆成决策 ticket#

engineering/wayfinder/SKILL.md 第一段定义得很清楚:

“A loose idea has arrived, too big for one agent session, and wrapped in fog: the way from here to the destination isn’t visible yet. Wayfinding is about finding that way, not charging at the destination. This skill charts the way as a shared map on the repo’s issue tracker, then works its decision tickets (questions whose resolution is a decision, not slices of a build to execute) one at a time until the route is clear.”

它解决的是:当一个 agent session 装不下的大块工作来临时,怎么不冲进去乱做,而是先画一张决策地图。

具体机制:

  • The Map 是一张 wayfinder:map 标签的 issue,里面是 ## Destination(目标)+ ## Notes(领域、必读 skill、长期偏好)+ ## Decisions so far(已闭 ticket 的索引)+ ## Not yet specified(迷雾里的事)+ ## Out of scope
  • 每个 ticket 是 map 的子 issue,body 里只放一个问题,类型分 research / prototype / grilling / task
  • Refer by name——所有人和 agent 都用 ticket 的名字而不是 #123 来引用,“name wraps its link, but they ride inside the name, never stand in for it”
  • Frontier 是当前可领的未闭 ticket,由 tracker 原生依赖关系渲染——人能在 tracker UI 里直接看到能拿什么

最大的反直觉设计:“Plan, don’t do”——wayfinder 默认不执行,它只产出决策。“The pull to just do the work is usually the signal you’ve reached the edge of the map and it’s time to hand off.” 只有在某个 effort 的 Notes 里显式覆盖,才能让 wayfinder 越界去做执行。

我觉得这是 GSD / BMAD / Spec-Kit 之外第三条路:不拥有过程,但给你一张决策地图,让你自己按图走。

4.2 tdd——把”红绿循环”变成可审查的工程纪律#

engineering/tdd/SKILL.md 一上来就定调:

“TDD is the red → green loop. This skill is the reference that makes that loop produce tests worth keeping: what a good test is, where tests go, the anti-patterns, and the rules of the loop. Every section applies on every cycle: consult them before and during the loop, not after.”

它不是教你 TDD 的——它是你写 TDD 时的强制规范。几个亮点:

“Seam: where tests go”——借鉴 Michael Feathers 的 Working Effectively with Legacy Code:

“A seam is the public boundary you test at: the interface where you observe behavior without reaching inside. Tests live at seams, never against internals.”

并且强制一个动作:“Before writing any test, write down the seams under test and confirm them with the user.”——你写测试前必须先问”我要测哪个公开 seam”,用户确认了才能动。

Anti-patterns 是这篇文章的精华:

  • Implementation-coupled: mock 内部协作者、测私有方法、走侧信道(查数据库代替走接口)。Tell: 重构了但行为没变,测试却红了
  • Tautological: expect(add(a, b)).toBe(a + b)——assertion 用跟代码一样的方式算期望值,靠构造通过,永远不会不同意代码
  • Horizontal slicing: 先写完所有测试再写实现。Tell: 测试在测形状而不是用户行为,对真实变更不敏感

第三个最重要——很多人写 TDD 是先把测试全列出来再实现,Matt 直接说不行:

“Work in vertical slices instead: one test → one implementation → repeat, each test a tracer bullet that responds to what the last cycle taught you.”

Rules of the loop 收尾:

  • Red before green(先写失败的测试)
  • One slice at a time(一次一个 seam、一个测试、一个最小实现)
  • Refactoring 不属于循环(refactor 是 code-review 的事)

最后一条最狠——它把 TDD 和 code-review 切成两个独立 skill,正是为了让 refactor 不会污染 red-green。这是用 skill 边界强制流程纪律。

4.3 diagnosing-bugs——把”修 bug”拆成 10 种反馈循环#

engineering/diagnosing-bugs/SKILL.md 第一句话是全文的灵魂:

“Phase 1: Build a feedback loop. This is the skill. Everything else is mechanical. If you have a tight pass/fail signal for the bug (one that goes red on this bug), you will find the cause; bisection, hypothesis-testing, and instrumentation all just consume it. If you don’t have one, no amount of staring at code will save you.”

它把修 bug 的核心总结成一句话:先建一个能在你这个 bug 上变红的反馈循环。然后列出 10 种建循环的方式,按优先级排:

1. Failing test       (unit / integration / e2e)
2. Curl / HTTP script
3. CLI invocation + snapshot diff
4. Headless browser script (Playwright / Puppeteer)
5. Replay captured trace
6. Throwaway harness
7. Property / fuzz loop
8. Bisection harness (git bisect run)
9. Differential loop (老版本 vs 新版本 diff)
10. HITL bash script (scripts/hitl-loop.template.sh)
text

第 10 种是人肉点击也能包成循环,因为”如果人类必须点击,至少用脚本驱动他们”。这是个强约束:宁可人肉驱动,也要保持循环结构。

Tighten the loop 段教你怎么把循环变快:

“Can I make it faster? Can I make the signal sharper? Can I make it more deterministic?”

并且对非确定性 bug给出明确策略:“The goal is not a clean repro but a higher reproduction rate.”——目标不是 100% 复现,是把复现率提到 debugable。

最值得抄的是完成标准:

“Phase 1 is done when the loop is tight and red-capable: you can name one command … that is:

  • Red-capable(能在你这个 bug 上变红)
  • Deterministic(每次跑结果一样)
  • Fast(秒级,不是分钟级)
  • Agent-runnable(agent 能无人值守跑)”

——修 bug 的第一阶段有明确的 done 条件:你能给出一个名字(一行命令),并证明它在你这个 bug 上会红。如果给不出来,不许进入 Phase 2:

“If you catch yourself reading code to build a theory before this command exists, stop: jumping straight to a hypothesis is the exact failure this skill prevents.”

——这条 warning 让我起鸡皮疙瘩。很多 agent 修 bug 就是栽在这里。

4.4 codebase-design——“deep module”的强制词汇表#

engineering/codebase-design/SKILL.md 的开场:

“Design deep modules: a lot of behaviour behind a small interface, placed at a clean seam, testable through that interface.”

它不是给你流程,是给你一套强制词汇。Glossary 段直接列:

  • Module: any thing with interface + implementation(函数 / 类 / 包 / 跨层切片都行)
  • Interface: 调用者必须知道的一切(签名、不变量、顺序约束、错误模式、配置、性能特征)
  • Depth: interface 背后的行为量 / interface 本身的复杂度
  • Seam (Michael Feathers): 改行为而不用编辑此处的地方
  • Adapter: 在 seam 上满足 interface 的具体物
  • Leverage: 调用者从 depth 里获得的杠杆
  • Locality: 维护者从 depth 里获得的局部性

并且显式禁用:

“Use these terms exactly: don’t substitute ‘component,’ ‘service,’ ‘API,’ or ‘boundary.’ Consistent language is the whole point.”

——这是因为词汇不一致是设计腐化的根源。“Module” 和 “component” 听起来像,但混用会让接口和实现的边界模糊。

两个核心可视化:

Deep module     Shallow module
┌──────────┐    ┌──────────────────┐
│ Small    │    │ Large Interface  │
│ Interface│    ├──────────────────┤
├──────────┤    │ Thin Impl        │
│ Deep     │    └──────────────────┘
│ Impl     │
└──────────┘
text

Three principles:

  • Depth is a property of the interface, not the implementation. 一个深模块内部可以有 mockable parts,但它们不在 interface 里
  • The deletion test. 删掉这个模块,复杂度消失 → pass-through;如果复杂度散到 N 个调用方 → 它在做贡献
  • The interface is the test surface. 调用方和测试过的是同一个 seam

最后一条是测试驱动设计的硬规则:“If you want to test past the interface, the module is probably the wrong shape.”——想测得更深,说明模块形状不对。

这跟我之前拆的 Anthropic Cybersecurity Skills 是同一个思路:用强制词汇对抗熵增。

4.5 grill-me / grilling——把”压力测试想法”做成可组合 skill#

productivity/grilling/SKILL.md 教 agent 怎么 grill 用户:

“Interview the user relentlessly until you reach a shared understanding. Map this as a design tree: every decision branches into the decisions that hang off it. Work the tree in rounds. The frontier is every decision whose prerequisites are already settled.”

它的工作机制:

  1. 设计树:每个决策分支出挂在它下面的子决策
  2. Round-based:一轮问 frontier 上所有问题(前置已定的)
  3. Frontier 重新计算:用户答完一轮,frontier 推进,新一轮问题解锁
  4. 找 fact 是 agent 的事:要环境信息就派 sub-agent,不要问用户你能查到的东西

每个问题的格式:

❓ **Q1** - **<question title>**: <body, 多段含多选>
➡️ <your recommended answer>
text

——问完必给推荐。这是”压力测试”的关键:你不只是问,你还给出立场,让用户反驳或同意。

do not act until user confirms——frontier 空了(设计树走完)也不许动手,必须用户说”yes we have shared understanding”。

grill-me 是 wrapper skill:

---
name: grill-me
description: A relentless interview to sharpen a plan or design.
disable-model-invocation: true
---

Call the Skill tool with "grilling".
text

——它自己不做事,调 grilling。disable-model-invocation: true 让它只能人触发,不能 agent 自动跳进去。这是 user-invoked vs model-invoked 的标准示范。


五、三个细节设计,让 30 个 skill 不变成 30 个孤岛#

5.1 互相引用,不重复写#

tdd 引用 codebase-design:“When the shape of that interface is itself in question … call the Skill tool with ‘codebase-design’ for the vocabulary.”

diagnosing-bugs 引用 tdd 和 codebase-design 的概念。

wayfinder 把自己的 grilling / domain-modeling / research / prototype 标成”在循环里会调用的子 skill”。

improve-codebase-architecture 强制要求:“Use these terms exactly … and don’t drift into ‘component,’ ‘service,’ ‘API,’ or ‘boundary.’”——它不允许下游 skill 改词汇。

这种网状引用让 30 个 skill 之间存在强结构,不是 30 块砖头。

5.2 user-invoked vs model-invoked 二元划分#

SKILL.md 的 frontmatter 决定 skill 怎么被触发:

---
name: wayfinder
description: Plan a huge chunk of work ...
disable-model-invocation: true     # user-invoked only
---
yaml

vs

---
name: tdd
description: Test-driven development ...
# 没有 disable-model-invocation → model-invoked
---
yaml

Wayfinder 必须人启动(你不想让 agent 自己决定要不要画决策地图)。TDD 可以 agent 自动跳进去。

CLAUDE.md 强制两者之一:“Every SKILL.md is either user-invoked (disable-model-invocation: true plus policy.allow_implicit_invocation: false in agents/openai.yaml, reachable only by the human) or model-invoked (model- or user-reachable).”

——skill 不是默认都能自动跳进去的,二选一是强制决策。

5.3 CHANGELOG.md + changesets:把 skill 当 release 管#

仓库里有 CHANGELOG.md 和 changesets 目录。skill 不是”加了就行”——加新 skill 要写 changeset,CHANGELOG 记录每次发版改了哪些 skill 的什么行为。

这是把 skills 集合当成版本化产品来运营——对比 Anthropic Cybersecurity Skills(817 个文件基本无 CHANGELOG,纯文档集合),Matt 的做法更接近 SDK 维护。


六、我从这套仓库学到的 5 条#

  1. 小而组合 > 大而全。 30 个独立 skill + 互相引用,比 1 个 monolithic 流程可控。GSD / BMAD 试图拥有整个过程,Matt 把过程拆碎给你拼。你要 trade-off 的话,Matt 这边赢了。

  2. CLAUDE.md / CONTEXT.md / ADR 三件套是 skill 仓库的标配。 没有 CLAUDE.md,agent 不知道哪些 bucket 算 promoted;没有 CONTEXT.md,词汇会漂移;没有 ADR,未来会重复犯错。Anthropic Cybersecurity Skills 缺这套,所以它像一个静态图书馆,不像一个持续演进的产品。

  3. 强制词汇比强制流程更有效。 codebase-design 不教你”先这样再那样”,它给你 7 个词并禁用 4 个反义词。你用对了词,做法自然对。这是用词汇的稳定性换设计的稳定性。

  4. 完成标准 (completion criteria) 必须可勾选。 diagnosing-bugs 的 Phase 1 done 条件是四条 checkbox;tdd 的 red-green 是三个动词;wayfinder 的 done 是”frontier 为空 + 用户确认”。所有 skill 都有清晰的 done 信号,这是它们能可靠被 agent 调用的前提。

  5. description 是触发器不是简介。 每个 SKILL.md 的 description 都用 Use when ... 起头,把触发分支写明。“Use when the user says ‘diagnose’/‘debug this’, or reports something broken/throwing/failing/slow.”——这就是 Anthropic Cybersecurity Skills 那篇说的”靠 description 触发”的最佳实践。description 的写法 = skill 的可达性。


七、它不适合什么场景#

公平起见,这套仓库不是万能的:

  • 不适合 0 流程的纯 vibe coding——你只是想让 agent 一次性帮你写个小工具,grill-me / wayfinder 太重
  • 不适合跨多仓库的大型项目——wayfinder 假设 issue tracker 是单仓的(虽然支持 Linear / 本地 .scratch/)
  • 不适合不是 TypeScript / JS 的项目——SKILL.md 的例子几乎全是 TS,虽然 codebase-design 的原则通用
  • 不适合没有 issue tracker 的团队——wayfinder 的整个机制建立在 ticket 系统上

它的甜蜜区是中大型 TypeScript 项目 + 有 issue tracker 的团队 + 想要”agent 不替代你做决策、但帮你跑流程”的工程师。Matt 的受众画像非常清楚。


八、给想抄这套仓库的人#

如果你想 fork Matt 的结构做自己的 skills 集合,建议按这个顺序:

  1. 抄 CLAUDE.md 骨架——4 个 bucket 语义 + promoted / non-promoted 区分 + plugin 清单
  2. 写 CONTEXT.md 词汇表——先列你的领域词,再禁用 4-5 个反义词
  3. 拆 user-invoked 和 model-invoked——每个 skill 二选一
  4. 先写 5 个 skill:wayfinder + tdd + diagnosing-bugs + codebase-design + grilling
  5. 强制互相引用——这 5 个之间至少 10 处 cross-reference
  6. 配 docs//.md——每个 promoted skill 配一篇人读文档
  7. 加 CHANGELOG 和 changesets——每次改 skill 写 changeset
  8. 写 ADR——至少解释”为什么是这个 bucket 结构”

走完这套,你的 skills 仓库就有演化能力,不只是文件堆。


结语#

Matt Pocock 的 skills 仓库证明了一件事:好的 agent 工程不是 prompt 调优,是工程纪律。

GSD / BMAD / Spec-Kit 想用一个流程把所有开发场景吞掉;Matt 用 30 个小 skill 让你自己挑、自己组合。他不替代你做决策,他让你做的每个决策有可调用的纪律。

我读完这套仓库最大的收获不是 30 个 skill 本身——是它示范了怎么把”agent 怎么做工程”这件事拆成可单独调用的命令。每一个 skill 都是一个有明确完成标准、有强制词汇、跟其他 skill 互相引用的小单元。

这是 agent 工程化的下一站:不是更大的模型,是更小的可组合单元。


引用#

关联阅读#

Matt Pocock 的 Claude Code Skills:30 个工程级 skill 拆解
https://wth2jhl.online/blog/mattpocock-engineering-skills/
Author 小吴同学
Published at August 20, 2026