拆 9.5 万 star 的 agent-skills:当你有 25 条规则,你怎么知道它们还在生效
这是我拆的第四个 Skill 仓库,也是 star 最多的一个(95,125)。前三个都在解决「怎么让 agent 做对一件事」,它解决的是另一个问题:「当你有 25 条规则,你怎么知道它们还在生效」。答案是一套三层评测框架——其中第二层用词法近似把「路由」变成了可确定、免费、能进 CI 的检查。另外两个我觉得该抄的是:每个技能都附一张「agent 的借口 vs 现实」反合理化表,以及一句关于训练与架构腐坏的洞察——「架构腐坏要几个月才显现,永远进不了权重,棘轮就是那个缺失的惩罚项」。
A teardown of addyosmani/agent-skills (95k stars, 25 skills). The first three repos I tore down solved 'how do I get an agent to do one thing right'; this one solves 'how do I know my 25 rules still work'. Its answer is a three-tier eval framework whose middle tier turns routing into a deterministic, free, CI-safe check via lexical approximation. Two other things worth stealing: an anti-rationalization table in every skill, and the insight that architectural rot never reaches the weights — a ratchet is the missing penalty, written down where the build can see it.
拆 9.5 万 star 的 agent-skills:当你有 25 条规则,你怎么知道它们还在生效
这是我这两天拆的第四个 Skill 仓库。
95,125 star,是四个里最多的(夏林果封面 125 → diagram-design 40,045 → hypit 2,315 → 这个 95,125)。作者是 Addy Osmani——Google Chrome 的老工程师、《Learning JavaScript Design Patterns》的作者。
它跟前三个不在同一个问题上。前三个都在回答**「怎么让 agent 把一件事做对」**:封面、图表、视频。
这一个回答的是**「当你有 25 条规则,你怎么知道它们还在生效」**。
主要作用
它把资深工程师的开发流程拆成 25 个技能,覆盖软件生命周期的六个阶段,并用一套三层评测框架持续验证这些技能本身是否还能被正确触发、还互不冲突、还真的改变了 agent 的行为。
DEFINE PLAN BUILD VERIFY REVIEW SHIP
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│ Idea │ ───▶ │ Spec │ ───▶ │ Code │ ───▶ │ Test │ ───▶ │ QA │ ───▶ │ Go │
│Refine│ │ PRD │ │ Impl │ │Debug │ │ Gate │ │ Live │
└──────┘ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘
/spec /plan /build /test /review /ship
9 个斜杠命令 1:1 对应六个阶段,每个命令自动激活对应的技能;25 个技能(24 个生命周期 + 1 个元技能路由器);4 个审查人格(code-reviewer / test-engineer / security-auditor / web-performance-auditor);7 份共享检查清单;16 份各工具的安装文档;13 个校验脚本。MIT。
知识来源也写在 README 里,很坦率:Hyrum 定律进了 API 设计技能、Beyonce Rule 和测试金字塔进了测试、变更尺寸和评审时效进了代码评审、Chesterton's Fence 进了简化、主干开发进了 Git 工作流、Shift Left 和特性开关进了 CI/CD——「这些不是抽象原则,它们直接嵌进了 agent 遵循的步骤里」。
它要解决的问题,README 里说得很直白
先看它怎么定义自己存在的理由,这句话是全部设计的起点:
AI 编程 agent 默认走最短路径——而最短路径通常意味着跳过规格、跳过测试、跳过安全审查,以及跳过那些让软件可靠的实践。
这是对 agent 的一句准确的病理描述。 不是因为模型不聪明,是因为它在优化"这一步看起来完成了",而不是"这个系统三个月后还能改"。
于是它给出的答案是流程 + 门禁。但——有了 25 条规则,新问题立刻出现:
- agent 该触发哪一条?用户说"帮我改个 bug",它会去找
debugging-and-error-recovery吗? - 两条规则会不会抢同一条请求?
- 就算触发了,agent 会不会表面上照做、实质上跳过?
这三问就是这篇文章的主线。 它给出的三个答案,是我觉得最值得抄的部分。
第一层答案(结构):每个技能长同一个形状
它的技能模板是固定的:
┌─────────────────────────────────────────────────┐
│ SKILL.md │
│ ┌─ Frontmatter ─────────────────────────────┐ │
│ │ name: lowercase-hyphen-name │ │
│ │ description: Guides agents through [task].│ │
│ │ Use when… │ │
│ └───────────────────────────────────────────┘ │
│ Overview → What this skill does │
│ When to Use → Triggering conditions │
│ Process → Step-by-step workflow │
│ Rationalizations → Excuses + rebuttals │
│ Red Flags → Signs something's wrong │
│ Verification → Evidence requirements │
└─────────────────────────────────────────────────┘
25 个 SKILL.md 合计 353 KB。四条设计原则里,有两条特别值得看:
Process, not prose. 技能是 agent 遵循的工作流,不是它们阅读的参考文档。每个都有步骤、检查点和退出条件。 Verification is non-negotiable. 每个技能都以证据要求结束——测试通过、构建输出、运行时数据。"看起来对"永远不够。
第二层答案 ⭐:把「路由」变成可确定、免费、能进 CI 的检查
这是整个仓库最有原创性的部分,也是我花时间最多的地方。
它的 evals/ 里有 25 个评测用例(每个技能一个)+ 25 组 fixture、共 48 个文件,分成三层:
| 层 | 检查什么 | 何时跑 | 成本 |
|---|---|---|---|
| 1. 结构 | frontmatter、命名、必需章节、命令一致性 | CI | 免费 |
| 2. 触发与路由 | 正例 prompt 能排到自己的技能 top-k;负例不会;没有两个描述近乎撞车 | CI | 免费 |
| 3. 行为 | 跟着技能走的 agent 是否满足它的 expectations[] | 按需 | Token |
关键在第二层。
它自己在文档里承认,第二层是「路由的词法近似(对描述做词干化 TF-IDF)」——它判断不了语义,那是第三层的活。 但它能抓住真实世界触发 bug 的两大主因:
- 假阴性:描述里缺了用户真会说的词
- 假阳性:描述太宽,压过了本该胜出的那个技能
而且它对失败给出了一个非常明确的处置方向:
Tier-2 失败通常意味着「去改描述」,而不是改 eval。
四个我认为可以直接搬走的机制细节:
① 正例要写「用户真会说的话」,不能抄描述。 文档里写得很清楚:"paraphrase how users actually talk; don't copy the description (that's gaming the eval)." 如果一条真实说法排不上名,那就说明描述确实缺了词汇——这是真实发现,不是 eval 的问题。
② 负例必须是对偶的,否则会空过。
负例 prompt 属于另一个技能,你还要在 owner 字段里声明是哪个;然后 runner 会断言那个 owner 必须排在本技能前面。不写 owner 的负例,在 prompt 谁都不匹配时也会通过——那就是一条白拿分的测试。
③ rank-1 门槛是钉住的,而且允许留余量。
CI 用 --min-rank1 95 跑,而仓库里的基线是 100%。文档解释了为什么故意留缺口:这样一次无关的描述改动不会立刻把 CI 打红。附一句纪律:
随着路由改善就调高门槛;永远不要为了放行一个回归而调低。
④ 撞车检测有明确阈值。 两两描述相似度 ≥75% 直接报错,≥50% 警告。文档的解读是:排名数字在掉,说明描述在朝彼此漂移。
这套东西解决了一个我之前从没想清楚的问题:评测 Skill 最难的地方不是判断它好不好,是判断它「会不会被想起来」。 而这一层居然可以用很朴素的办法做成确定、免费、每次 CI 都跑的检查——因为它不需要理解语义,只需要回答"这段话里的词,跟用户那句话里的词,像不像"。
第三层答案 ⭐⭐:反合理化表,以及「检查的自我循环性」
这一层是我觉得它最硬的地方。它没有停在"写清楚流程",而是预先把 agent 会用来偷懒的借口一条条写下来,然后逐条反驳。
每个技能都有一张 Common Rationalizations 表。摘 TDD 技能里的几行:
| Agent 的借口 | 现实 |
|---|---|
| "我先把代码写通,之后再补测试" | 你不会补的。而且事后写的测试测的是实现,不是行为。 |
| "这个太简单了不用测" | 简单的代码会变复杂。测试记录的是预期行为。 |
| "测试拖慢我" | 测试现在拖慢你。以后每次改代码它都在加速你。 |
| "我手动测过了" | 手动测试不留痕。明天的改动可能把它弄坏而无人知道。 |
| "代码本身已经很清楚了" | 测试就是规格。 它们记录代码该做什么,而不是它现在做什么。 |
| "这只是个原型" | 原型会变成生产代码。从第一天写测试能防住"测试债"危机。 |
最后一行我要单独夸:
| "我再跑一遍测试,保险一点" | 干净的测试跑完之后,除非代码变了,否则重复同一条命令什么也没增加。在随后的编辑之后再跑,而不是当安慰剂。 |
这一行让我停下来想了很久。它堵的不是"偷懒",是**"过度验证带来的虚假安全感"**——一种看起来更认真、实则在浪费的失败模式。能写出这一行,说明作者真的观察过 agent 的行为,而不是在抄最佳实践清单。 因为"多测一遍总没坏处"这句话在任何一本教材里都是对的。
除了反驳表,每个技能还有 Red Flags(出现这些迹象说明出问题了)和 Verification(需要什么证据)。
但这还不够。 因为 agent 有一个更隐蔽的失败模式:它可以让检查通过,而不让代码变对。
它最深的那个技能——constraint-driven-development——就是专门治这个的。技能描述里那句我读了两遍:
当 agent 一直把检查静音或跳过测试来换取绿灯时使用。
它列出了四种"质量门槛被悄悄降低"的形态,其中第三种讲得极细:
一个检查器被静音了。 新增
@ts-ignore或eslint-disable。有四种抑制注释值得特别关注,因为它们关掉的正是你依赖的检查:istanbul ignore把代码从覆盖率里删掉而不是去测它,Stryker disable藏起一个存活的变异体,nosemgrep和gitleaks:allow对安全发现做同样的事。
然后它写下了我认为整个仓库最值钱的一段推理——如何给检查分级:
不是所有检查都同样自我循环。 用一个问题给它们排序:agent 能不能靠"写不能工作的代码"让它通过?
- 外部:axe-core 编码了 WCAG、
osv-scanner读的是漏洞数据库、Lighthouse 测量的是真实浏览器。agent 没法跟这些争辩。- 项目:你的 lint 规则、你的分层边界。文件是人拥有的。
- 套件:你自己的测试。最有用,也是唯一真正自我循环的一类。
一个完全由第三类构成的门槛,价值低于一个掺了外部意见的门槛。 检查一下至少有一条外部约束在里面。
"agent 能不能靠写不能工作的代码让它通过"——这个提问方式我觉得可以直接当工具用。它一眼就区分开了"真验证"和"自证",而且它给出的处方很克制:不是"多写测试",是**"至少掺一条外部意见进去"**。
第四层 ⭐:棘轮——一个连模型训练都考虑进去的设计
同在一个技能里,还有一段关于门槛该设多少的推理。
它先否掉了直觉做法:
在一个 62% 覆盖率的代码库上把门槛设成 80%,你会得到一个永远红的构建,然后得到一群学会忽略红色构建的人。
替代方案叫棘轮(ratchet):不要求任何决策——记录你现在在哪,然后拒绝变差。 每个检查对比的是记录值,不是愿景。数字变好了就更新;数字掉了,那就是发现。
然后是那句我认为全仓库最锋利的话:
这也回答了一个关于训练的合理质疑。模型被奖励通过测试,而测试你几秒钟就能评估。架构腐坏要几个月才显现,永远进不到权重里。棘轮就是那个缺失的惩罚项——写在构建看得见的地方。
"架构腐坏永远不会进到权重里。" 这句话解释了我一直隐约感觉到但说不清的一件不公平:为什么 agent 在"让测试变绿"上越来越强,在"让系统三年后还能改"上没什么进步。因为前者几秒钟就能判分,后者要几个月——而没有反馈信号的地方,就不会长出能力。
所以在没有反馈信号的地方,你得人工把惩罚项补上。棘轮就是这个补丁:它不指望模型学会长远的品味,它只是让"变差"这件事在构建里当场可见。
配套的默认值也做得很好——每个数字都附了「为什么是这个数」:
| 约束 | 默认值 | 为什么 |
|---|---|---|
| 改动行覆盖率 | ≥ 80% | 高到能逼出一个测试,低到能放一行配置 |
| 项目覆盖率 | 今天的值,不许掉 | 采用它不需要任何争论 |
| 变异得分 | 起步 ≥ 60% | 从没跑过变异的套件典型值;80% 算成熟 |
| 依赖漏洞 | 高危及以上为零 | 再低的多数是噪音 |
| LCP | ≤ 2500 ms | Core Web Vitals 的 "good" 阈值 |
| 无障碍 | axe 严重/重要级为零 | 中度和轻微常年有争议 |
| 例外有效期 | 90 天 | 长到能安排修复,短到还记着 |
| 棘轮容差 | 0.5% | 吸收无关文件移动导致的漂移 |
把数字和理由一起写下来。一个没有理由的阈值,会被下一个撞上它的人删掉。
还有两条我特别喜欢的克制:
采访只问四个问题,而且每个都有默认值——所以"I don't know"本身就是一个能产出可用配置的完整回答。文档最后一句:"停在四问。十二问的访谈产出的是没人看得懂的配置,和一个后悔开始的人。"
门槛分三级牙齿:只写下来(免费,靠 agent 自觉)→ 脚本化(npm run check,确定性,无新依赖)→ 工具化。「大多数项目应该在第二级停下。」 什么时候上第三级?"当你维护的检查脚本超过大约三十行 shell 的时候。"
第五层:两个 hooks,把规则变成物理约束
这个仓库还带了 hooks,其中两个的设计思路已经不是"提示词"了。
① SDD-CACHE:缓存,但每次都向源站复验。
source-driven-development 技能要求每个框架决策都去查官方文档。问题是同一项目跨多次会话会反复抓同一页。而用本地记忆缓存内容,正好违反这个技能的本意——文档会变,陈旧的缓存会掩盖这一点。
它的解法:内容缓存在本地,但每次复用都用 HTTP If-None-Match / If-Modified-Since 向源站复验;只有服务器回 304 Not Modified 时才从缓存取。
那是一次新鲜验证,不是一次记忆读取。
② SIMPLIFY-IGNORE:让模型看不到被保护的代码。
/code-simplify 的风险是把你故意写丑的关键代码"简化"掉。它的做法不是叮嘱模型"别动这段",而是:
/* simplify-ignore-start: perf-critical */
// 手工展开的 XOR —— 比循环快 3 倍
result[0] = buf[0] ^ key[0];
...
/* simplify-ignore-end */被标记的块在 /code-simplify 运行时会被替换成 /* BLOCK_de115a1d: perf-critical */ 占位符——模型围着它推理,但根本看不到它的实现。
这两条合起来说明一件事:当一条规则足够重要时,不要靠提示词,靠机制。 前者把"用过期的记忆"这个可能性从流程里删掉,后者把"模型手贱改了关键代码"这个可能性从上下文里删掉。它们在设计"能不能发生",而不是设计"应该怎么做"。
它的诚实,以及一处名不副实
有几件事它做得很坦率,值得记下来:
① 竞品对比文档里,故意不放 star 数。
(我们刻意略过 star 数和采用量:它们在博客里的引用极其不一致,而且每周都在变。三个项目都在被积极使用和维护。)
一个 9.5 万 star 的项目,在跟两个竞品做对比的文档里主动不用 star 数当论据——因为它对这个项目有利,所以它自己禁掉了。 这份对比还把 Superpowers 和 Matt Pocock 的强项写得很实在(包括给对手指出的优点,以及自己"覆盖广但每个不深"的取舍)。
② 自曝了两个缺陷,都挂了 issue 号。
- 可移植性缺口(#361):单独
npx装一个技能时只复制skills/<name>/,不会带上仓库级的references/——技能还能用,但指向共享检查清单的路径会失效。 - Antigravity 包装命令限制:某些版本会报告旧式命令 TOML"已转换",但包装命令根本发现不了,得改为直接调用底层命名空间的技能。
③ 一份「被拒绝的改动」账本。
evals/skill-impact.md 是一个只追加的账本,记录因为评测证据而被拒绝的技能与描述改动,目的是让贡献者在提重叠的改动之前,能先看到别人试过什么。
每条被拒提案记一行;已接受的改动不要记在这里。
表格列的字段是:日期 / 受影响技能 / 尝试的改动 / rank-1 分数(改前 → 改后) / 被拒的 PR 与结果。
这个设计我很服气——它把"失败过的尝试"变成了公开资产。 大部分项目里,一次被拒的改动就消失了,下一个人半年后重新踩同一个坑。这里它被记下来,还带着量化的证据(改动让路由分数从多少掉到多少)。
不过我得诚实说一句:这份账本目前是空的——文件一共 6 行,只有标题、说明和表头,还没有任何一条记录。所以它是刚立起来的机制,不是已有的成果。这个区别对判断它的成熟度很重要,我不想含糊过去。
④ 一处名不副实(无害)。 仓库只有一个 CI 工作流,但文件名是 test-plugin-install.yml——而它实际上承担了全部校验:验证所有技能、验证 manifest 版本、测试版本校验器、测试评测 runner、跑路由评测(--min-rank1 95)、验证 skills 里的引用链接、验证命令一致性、验证产物路径。
我抄走的四条
- 给每条技能写一张反合理化表。 不是写"应该怎么做",是写"agent 会用哪句话跳过它,然后为什么那句话不成立"。而且要包括防止过度验证的那一行——因为"再测一遍保险一点"在教材里永远是对的,只有观察过真人才写得出来。
- 用一句话给检查分级:"agent 能不能靠写不能工作的代码让它通过?" 能,就是自证;不能,才是验证。至少保证有一条外部意见在里面。
- 没有目标数字时用棘轮,不要用愿景。 在 62% 的库上设 80% 只会训练人忽略红灯。记录今天,拒绝变差,数字掉了就是发现。
- 规则足够重要时,别靠提示词,靠机制。 让"用过期记忆"和"改到关键代码"这两个可能性物理上不存在,比反复叮嘱有效得多。
还有一条不是"抄",是对比出来的东西:它证明了 Skill 是可以被评测的,而且评测不必昂贵。 第三层行为评测确实要花 token,但第二层把"路由"做成了免费的确定性检查——这层恰好是最容易悄悄坏掉、也最没人检查的。
四个仓库,四条不同的路
拆完四个,这张表我自己是最想留着的:
| 仓库 | 它垫在下面的是什么 | 所以它能做到 |
|---|---|---|
| 夏林果封面 | 9 种风格的提示词 + 样图 | 稳定出一张好看的封面 |
| diagram-design | 40 种类型参考 + 58 条 CI 关卡 | 可靠地出 40 种编辑级图表 |
| hypit | 一门语言 + 编译器 + 运行时 | 可重跑、可批量、成本可精确为 0 |
| agent-skills | 25 个技能 + 三层评测 + 反合理化表 | 让 25 条规则持续被触发、被遵守、被验证 |
而把它们连起来看,有一条线:它们都在把"人的判断"变成"机器能执行的判据",只是变成的东西不一样——变成坐标(diagram-design 的 4px 网格)、变成语义锚点(hypit 的词级时间轴)、变成可判定的路由评测(这个仓库的 Tier 2)。
一个有意思的对照:diagram-design 的结论是**"一条只活在散文里的规则,就是一条会发版坏例子的规则";agent-skills 的结论是"没有反馈信号的地方,就不会长出能力,所以要人工把惩罚项补上"**。
两句话说的是同一件事的两端:散文里的规则会失效,是因为没有人给它记分。
怎么装
任意 agent 一行:
npx skills add addyosmani/agent-skills # 装全部 25 个
npx skills add addyosmani/agent-skills --list # 先浏览
npx skills add addyosmani/agent-skills --skill test-driven-development # 只装一个Claude Code:
/plugin marketplace add addyosmani/agent-skills
/plugin install agent-skills@addy-agent-skills另外还支持 Cursor、Gemini CLI、Antigravity、OpenCode、Windsurf、GitHub Copilot(含独立 CLI)、Codex、Kiro、Command Code。注意上面提到的可移植性缺口:只装单个技能时不会带上 references/,所以要完整能力就用整仓安装。
仓库地址:github.com/addyosmani/agent-skills · 技能站台 skills.addy.ie
最后说个实在的:我这边本来就装了这套里的不少技能(test-driven-development、spec-driven-development、code-review-and-quality 这些名字在 agent 圈里已经到处都是了)。
拆完的感受有点复杂——我平时在用它们的时候,只看得到流程;拆开才看到,真正花力气的地方是"怎么防止流程被绕过",以及"怎么知道流程还在生效"。 这两件事在我自己的技能库里都是空白。
我大概该给自己写一份反合理化表了。