Ponytail ponytail-review:一个只找"该删什么"的过度设计代码审查技能
Ponytail 把"最懒的资深工程师"装进你的 AI Agent,其中 /ponytail-review 是它提供的六个技能之一,专门做一件事:审查当前 diff,只找过度工程(over-engineering),并输出一份"删除清单"。读完本文,你将掌握这条审查规则的完整输出格式、五种发现标签(delete / stdlib / native / yagni / shrink)的判定标准、评分机制与边界约束,以及它如何在 Claude Code、Codex、Hermes、pi 等宿主中以命令、技能或插件形式被触发——这套规则本身就是一份可以直接抄进任何 Agent 工作流的"减法式审查"规范。
定位:它不查正确性,只查复杂度
skills/ponytail-review/SKILL.md 的 frontmatter 把技能定位写得很明确:
- 输入是一次代码改动(diff),任务是对"不必要的复杂度"做审查;
- 每条发现一行:位置、该删什么、用什么替代;
- 目标是让 diff 变得更短——"The diff's best outcome is getting shorter";
- 触发条件:用户说 "review for over-engineering"、"what can we delete"、"is this over-engineered"、"simplify review",或直接调用
/ponytail-review; - 与常规审查的关系是互补:常规审查找正确性 bug、安全漏洞、性能问题,而这个技能"只猎杀复杂度"(this one only hunts complexity)。
这种切分不是随口一说,它和 Ponytail 主技能的设计一脉相承。主技能 skills/ponytail/SKILL.md 定义了一条"阶梯"(ladder),要求 Agent 写代码前停在第一级站得住的横档上:
- 这段代码需要存在吗?(YAGNI)
- 代码库里已经有了吗?复用,别重写
- 标准库能做吗?用它
- 平台原生能力能覆盖吗?用原生(如
<input type="date">胜过日期选择器库) - 已安装的依赖能解决吗?用它
- 能一行搞定吗?一行
- 最后才写:能工作的最小代码
ponytail-review 的五种标签(下一节详述)正是对这条阶梯的逆向检查:delete: 对应第 1 档,stdlib: 对应第 3 档,native: 对应第 4 档,yagni: 对应"只有一个实现的抽象"这类第 1 档违规,shrink: 对应第 6/7 档。也就是说,主技能管"写的时候别多写",ponytail-review 管"写完之后审掉多写的"。
输出格式:一行一个发现
技能文件给出的格式规范只有一句模板:
L<line>: <tag> <what>. <replacement>.
对多文件 diff,前面加上文件名:
<file>:L<line>: ...
格式刻意压缩到最简:不写段落、不写论证、不写"建议考虑"。每条发现必须包含三个要素——位置(行号或文件:行号)、该删/该换什么、替代品。替代品可以为"无"(即直接删掉)。
五种标签:delete、stdlib、native、yagni、shrink
SKILL.md 的 "Tags" 小节定义了完整的标签表,这是整个技能的核心判定标准:
| 标签 | 判定标准 | 替代物要求 |
|---|---|---|
delete: |
死代码、没人用的灵活性、投机性功能 | 替代品:无(nothing) |
stdlib: |
手搓了标准库本身就带的东西 | 必须点名那个标准库函数 |
native: |
依赖或代码在做平台已经会做的事 | 必须点名那个平台特性 |
yagni: |
只有一个实现的抽象、没人设置的配置、只有一个调用者的层 | — |
shrink: |
同样的逻辑、更少的行数 | 必须展示更短的写法 |
注意后三列"替代物"的强制性:stdlib: 不能只说"用标准库",必须写出具体函数名(如 dict(zip(...))、Intl.DateTimeFormat);native: 必须写出具体平台特性;shrink: 必须给出更短形态本身。这保证了审查结果是可直接执行的删除清单,而不是需要再翻译一遍的评论。
yagni: 的判定措辞也值得对照主技能 skills/ponytail/SKILL.md 的 Rules 一节:"no interface with one implementation, no factory for one product, no config for a value that never changes"——一个实现接口的抽象、一个产品的工厂、一个永不变更值的配置,就是 yagni 标签的三个标准形态。而"惰性,不是疏忽"的底线(信任边界校验、数据丢失防护、安全、可访问性永不裁剪)同样适用于审查:主技能 AGENTS.md 中 "Not lazy about" 一节列出的那些东西,审查时同样不应标记为可删。
示例:拒绝模糊,只给结论
SKILL.md 的 "Examples" 小节先给了一个反面教材,再给了五个正面样例。反面教材展示了 Ponytail 明确反对的审查腔调:
❌ "This EmailValidator class might be more complex than necessary, have you considered whether all these validation rules are needed at this stage?"
("这个 EmailValidator 类可能比必要的更复杂,你考虑过这个阶段是否需要所有这些校验规则吗?"——含糊、无定位、无替代物。)
然后是五个正面样例,完整继承如下:
✅ L12-38: stdlib: 27-line validator class. "@" in email, 1 line, real validation is the confirmation mail.
✅ L4: native: moment.js imported for one format call. Intl.DateTimeFormat, 0 deps.
✅ repo.py:L88: yagni: AbstractRepository with one implementation. Inline it until a second one exists.
✅ L52-71: delete: retry wrapper around an idempotent local call. Nothing replaces it.
✅ L30-44: shrink: manual loop builds dict. dict(zip(keys, values)), 1 line.
五条样例恰好各用一个标签,也各自示范了标签的硬性要求:
stdlib:样例同时点名了替代函数,并补了一句业务判断——"真正的校验是确认邮件本身",把校验逻辑的成本归零;native:样例点名了Intl.DateTimeFormat,并量化了收益 "0 deps";yagni:样例展示了多文件 diff 的repo.py:L88写法,替代动作是"内联,直到出现第二个实现";delete:样例展示了替代品为"无"的写法,并且给出的删除理由是语义性的(幂等的本地调用套重试包装没有意义);shrink:样例直接写出了更短的那一行代码dict(zip(keys, values))。
仓库 examples/ 目录下的实战案例(如 examples/email-validation.md、examples/debounce.md)展示了同一套思维在"写代码"侧的产物;ponytail-review 则是把同样的判断标准用在"审代码"侧。
评分:唯一重要的指标是净删行数
"Scoring" 小节规定审查必须以唯一重要的指标收尾:
net: -<N> lines possible.
如果没什么可删,输出 Lean already. Ship.(已经是精简的,直接发布)然后停止。这个收尾设计有两个作用:一是把审查结果量化成单一数字,让"这次审查值不值"可比较;二是给了"无可删"一个明确出口,避免 Agent 为了交差而硬凑发现——代码本来够精简时,正确的输出就是"没有发现"。
边界:不修、不越界、可退出
"Boundaries" 小节划出了四条硬边界,这也是使用这个技能时最容易踩错的点:
- 范围仅限过度工程与复杂度。正确性 bug、安全漏洞、性能问题被明确排除在范围外(explicitly out of scope),应当路由到常规审查流程,而不是在这条通道里报;
- 最低限度的测试不算臃肿。单个冒烟测试或基于
assert的自检是 Ponytail 体系的"最低要求"而非 bloat——主技能 skills/ponytail/SKILL.md 的 "When NOT to be lazy" 一节规定非平凡逻辑要留下一个可运行的检查,审查时必须与这条自洽,永远不能把这类测试标记为删除对象; - 只列清单,不执行修复(does not apply the fixes, only lists them);
- 可退出:用户说 "stop ponytail-review" 或 "normal mode" 时,回退到冗长的常规审查风格。
第 3 条让它天然适合嵌入流水线:审查产出是一份待办删除清单,是否执行、何时执行由人决定,Agent 不越权改码。
在宿主中如何调用
ponytail-review 作为技能存放在 skills/ponytail-review/SKILL.md,各宿主通过各自的适配层把它注册成命令或技能,适配规则见 docs/agent-portability.md:"skills/ 持有核心行为,宿主文件只是让它容易被加载的适配器"。从源码结构看,几种典型宿主的接入方式如下:
Claude Code / Codex 插件:仓库根目录的 commands/ponytail-review.toml 是命令适配器,内容与技能文件同源——它把整条规则压缩成一段 prompt 注入:
description = "Review changes for over-engineering, what can be deleted"
prompt = "Review the current code changes for over-engineering only, not correctness. One line per finding: L<line>: <tag> <what to cut>. <replacement>. Tags: delete (dead code/speculative feature), stdlib (reinvented standard library), native (dependency doing what the platform does), yagni (abstraction with one implementation), shrink (same logic, fewer lines). End with the net lines removable. If nothing to cut: 'Lean already. Ship.'"
这段 prompt 完整保留了技能文件的全部要素:单行格式、五个标签、net 行评分、"Lean already. Ship." 出口。安装与调用方式(/plugin marketplace add + /plugin install ponytail@ponytail,详见 README.md 的 Install 一节)之后,直接在会话中发 /ponytail-review 即可对当前改动执行审查。
Hermes Agent:plugin.yaml 把 ponytail-review 同时注册在 provides_commands 和 provides_skills 两个列表里,即它既是斜杠命令 /ponytail-review,也可作为 ponytail:ponytail-review 技能引用;after-install.md 给出的命令清单里它是 /ponytail-review [target],支持指定审查目标。
pi agent harness:pi-extension/index.js 中 pi.registerCommand("ponytail-review", ...) 把命令映射为 /skill:ponytail-review 的别名发送,即复用同一份 SKILL.md 的完整规则。
Codex:技能以 @ 前缀调用,写作 @ponytail-review(见 README.md Commands 一节的说明)。
指令级宿主(Cursor、Windsurf、Cline、Copilot 等无技能支持的宿主)没有斜杠命令,只有常驻规则集;此时可以把 skills/ponytail-review/SKILL.md 的正文内容直接贴给 Agent 作为一次性审查指令使用——因为它本身不依赖任何运行时。
与 ponytail-audit 的区别:diff 与全库
容易混淆的相邻技能是 skills/ponytail-audit/SKILL.md。它的开头一句话就说明了关系:"ponytail-review, repo-wide. Scan the whole tree instead of a diff."——同一个标签体系、同一套边界,只是扫描范围从当前改动扩大到整个代码树,且结果按"删得最多的排最前"排序,收尾指标也多了一项依赖数(net: -<N> lines, -<M> deps possible.)。两者都只列清单、不执行修复。选哪个取决于问题粒度:审查一次提交用 review,体检整个仓库用 audit。
可验证性与工程约定
这条规则并不是孤立的文本:仓库 scripts/check-rule-copies.js 负责在修改紧凑规则文本时校验各宿主的副本保持一致,npm test(测试见 tests/)会校验技能与其派生包(如 OpenClaw 技能包)不出现漂移。这意味着你从任何一个宿主看到的 ponytail-review 行为,都来自这一份 skills/ponytail-review/SKILL.md,且各宿主副本受脚本与测试约束对齐。
小结:把"删"当作审查的第一性
ponytail-review 的价值不在它发现了什么模式,而在它对审查形态的强制约束:一行一个发现、标签必须对应可执行动作、替代物必须点名、以净删行数收尾、无可删则明说。它把 code review 从"意见交换"变成"删除清单",并且用边界条款(不查正确性、不删最低限度测试、不改码)保证了自己不会变成另一个什么都说的常规审查器。如果你的 Agent 工作流里需要一个"瘦身专用"的审查通道,这份不到六十行的 SKILL.md 本身就可以作为规范直接引用。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00