DietrichGebert/ponytail:127.5k stars 的 "懒惰资深工程师" 技能,把 AI Agent 从 404 行的日期选择器里拽出来
上周我给自己的一个内部工具加个” 选日期” 的输入框。需求一句话:表单里加个日期选择器,能选年月日就行。
我把这句话丢给 agent,然后去泡了杯咖啡。
回来的时候屏幕上滚过一长串东西。它装了 flatpickr,写了一个 DatePicker.tsx 包装组件,配了一份 datepicker.css,把 locale 抽成了 props,为” 以后可能要支持范围选择” 预留了一个 mode 参数,最后在对话框里问我:时区要按用户本地还是 UTC 存?要不要顺便把 dayjs 也引进来统一处理?
git diff 显示 400 多行新增,一个新依赖,四个新文件。
我盯着看了一会儿,把整个 diff 撤了,手写了一行:
1 | <input type="date"> |
浏览器自带的。有键盘可访问性,有本地化,有原生的日历弹层,移动端还会调起系统滚轮。这个功能在所有主流浏览器上跑了很多年。
那天晚上我在 GitHub Trending 上刷到 DietrichGebert/ponytail,README 第一屏的例子和我白天遇到的事一模一样。它的描述只有一句:让你的 AI agent 像屋里最懒的那个资深工程师一样思考。
127.5k stars,6.8k forks,当日新增 2.8k stars,MIT 协议。我花了两天把它的技能文本、hooks 实现和基准测试报告翻完,写下来的是我看到的东西。
一、它想解决的问题:agent 的” 过度建造” 是结构性的
先说清楚我为什么觉得这个问题值得单独做一个项目。
AI agent 写出臃肿代码,不是模型不聪明。恰恰相反,它太想表现得聪明。
训练语料里的高分回答长什么样?分小标题、给多个方案、考虑扩展性、附带错误处理和类型注解、结尾还有一段” 进一步优化的方向”。这套结构在 Stack Overflow 的高赞回答里是对的,在教程文章里是对的,在面试题解里也是对的。于是模型学会了:详尽 = 优质。
问题是,写业务代码的时候,详尽 = 债务。
多出来的每一个抽象层,都是半年后有人要读懂的东西。那些” 为将来预留” 的参数,从来没人传过,但每次改动都要绕开。新加的依赖带来一条供应链、一次 CVE、一份升级工作。
而 agent 的工作方式让这件事更严重了。人类工程师写多了会累,累了就会偷懒,偷懒往往就写对了。Agent 不累。你让它加个日期选择器,它可以毫不迟疑地把四个文件全部写完,中间不打一个哈欠。产出速度快到你来不及在 review 环节拦住。
ponytail 的作者 DietrichGebert 给这个问题起了个具体的形象:公司里那个扎马尾、戴椭圆眼镜、在职时间比版本控制系统还长的资深工程师。你拿五十行代码去找他,他看一眼,什么都不说,替你换成一行。
README 里那句 tagline 我很喜欢:他什么也不说。他写一行。它能跑。
项目干的事情,就是把这个人塞进你的 agent 里。
三个月,从建库到 12.7 万 star
翻了一下仓库信息:建库时间 2026 年 6 月 12 日,最近一次 push 是 9 月 4 日。三个月不到,127.5k stars、6.8k forks。Trendshift 的日榜、周榜、月榜(JavaScript 分类)三块徽章挂在 README 顶上。
这个速度在”agent 技能” 这个品类里不算孤例,但 ponytail 的位置有点特别。
过去一年 GitHub 上冒出来的 agent 相关项目,大部分在做加法:给 agent 加记忆、加工具、加子 agent 编排、加检索、加多角色讨论。方向都是” 让 agent 能做更多事”。
ponytail 是少数几个在做减法的。它不给 agent 加任何能力,它给 agent 加一道闸门。
仓库的 topics 也把这个定位标得很清楚:agent-skills、ai-agents、claude-code-plugin、cursor-rules、prompt-engineering,最后一个是 yagni。整个仓库 2.3 MB,核心资产是几份 Markdown。
它爆得快,我猜是因为它戳中的那个痛点,恰好是所有人在同一时间遇到的:2026 年这一年,大量的人从” 偶尔让 AI 补全一段代码” 切换到了” 让 agent 独立跑完一个工单”。工作单元一变大,过度建造这件事就从” 多写两行” 变成了” 多写四个文件”,从审美问题变成了维护成本问题。
二、核心机制:一道七级阶梯
ponytail 的全部核心,是一道在写代码之前必须爬的阶梯。Agent 停在第一个成立的台阶上:
1 | 1. 这东西需要存在吗? → 不需要:跳过(YAGNI) |
七个台阶,从” 根本不写” 一路降级到” 写最少”。
我第一眼觉得这就是把 YAGNI 换了个说法。真正让我改主意的是第二级和第四级。
第二级” 代码库里已经有了吗” 是我实际吃亏最多的地方。Agent 有个顽固毛病:它读了任务,扫了几个相关文件,然后开始写一个 formatCurrency。而你的 utils/format.ts 里躺着一个一模一样的,只是名字叫 toMoney。技能文本里对这条的措辞很直接:先看再写,把隔壁几个文件里已经有的东西重新实现一遍,是最常见的那种垃圾。
第四级” 平台原生特性” 是收益最大的一级。前端这十年往浏览器里塞了太多东西,而 agent 的知识分布明显偏向 npm 生态。<dialog> 元素自带焦点陷阱、Escape 关闭、::backdrop 遮罩和默认可访问性,2022 年起全平台可用。但你让 agent 加个确认弹窗,它十有八九给你 npm install @radix-ui/react-dialog。
仓库的 examples/ 目录里逐个拆了这些对照。弹窗那个例子:Radix 版本一个依赖三十行,原生 <dialog> 版本零依赖八行。作者在结尾写了一句我认可的判断:那个库在解决一个平台已经解决了的问题。
examples/ 里那些具体的对照
这个目录有十一个文件,每个都是” 没装技能的写法” 对” 装了技能的写法”。挑三个我觉得最有代表性的。
解析 URL 查询串。 没装技能的版本第一步是 npm install query-string,一个 4.5 kB gzip、每周 350 万下载的包:
1 | import qs from "query-string"; |
装了技能之后:
1 | // ponytail: URLSearchParams does this |
URLSearchParams 在每个浏览器里都有,Node.js 从 v10 起也有。编码、重复键、迭代它全处理。那个包是给一个已经全平台落地多年的 API 写的 polyfill。
按 key 给数组分组。 常见写法是装 lodash 用 groupBy,或者手搓一个 reduce。技能给的是:
1 | // ponytail: Object.groupBy does this |
Object.groupBy 在 Chrome 117、Firefox 119、Safari 17.4、Node.js 21 落地。这个例子结尾还有一句我特别认可的话:如果你要支持 IE11 或者老 Node,那个 reduce 一行版才是对的选择,而不是 lodash。它没有把” 用原生” 变成教条,而是让你先看目标运行时。
给搜索框加防抖。 这个例子是从基准测试的原始输出里逐字摘的(Haiku 4.5,temperature 1,benchmarks/output.json),所以能看到无技能那一版的真实形态:116 行。它先给了一个基础版的 debounce 函数加用法,然后给了一个” 增强版,带加载状态”,再往下是错误处理、请求取消、结果渲染。三个逐级递进的版本,全部写在同一个回答里。
用户要的是一个防抖。它给了一份防抖教程。
这就是我在开头说的那个结构性问题的样子:模型不是不会写防抖,它是在按” 高分回答” 的格式交付。
阶梯之上还有一条铁律
技能文本里反复强调的一点,是阶梯运行的时机:
阶梯在你理解问题之后运行,不是代替理解。读任务,读它触及的代码,把真实调用链走一遍,然后再爬。
这句话决定了 ponytail 和” 叫模型少写点” 之间的区别。它对解决方案懒,对读代码不懒。
配套还有一条修 bug 的规则,我觉得比阶梯本身更值钱:
Bug 修复等于修根因,不是修症状。工单描述的是症状。动手改之前,grep 出你要动的那个函数的每一个调用方,在共享函数里修一次。在共享函数里加一个 guard,比在每个调用方各加一个 guard 的 diff 更小;而只修工单点名的那条路径,会留下一堆兄弟调用方仍然是坏的。
把” 最小 diff” 和” 修根因” 统一起来,这个论证我第一次见。通常这两件事被当成矛盾的:修根因意味着动公共代码,风险大改动多。ponytail 的说法是,如果你把所有调用方都算进去,修根因的总 diff 反而更小。
那份规则清单
阶梯之外还有一组具体的禁令,我照着自己的项目对了一遍,条条命中:
- 不要没人要求的抽象:不要只有一个实现的 interface,不要只生产一种产品的 factory,不要给一个永远不变的值配一个 config。
- 不要 boilerplate,不要” 为以后” 搭的脚手架。以后可以自己给自己搭。
- 删优先于加。无聊优先于聪明,聪明是那种半夜三点有人要解码的东西。
- 文件数越少越好。最短的能跑的 diff 赢,但前提是你已经理解了问题。放错位置的最小改动不是懒,是第二个 bug。
- 需求复杂?先交懒版本,在同一个回答里质疑它:「做了 X;Y 能覆盖。真需要完整的 X 就说一声。」不要为了一个可以默认掉的答案停下来等。
- 两个标准库方案体积一样?选边界情况正确的那个。懒是少写代码,不是挑更脆的算法。
第一条那三个例子(单实现 interface、单产品 factory、常量 config)挑得很准。这三样是我见过的 agent 生成代码里出现频率最高的三种空转抽象,而且它们都长着” 良好工程实践” 的脸。
倒数第二条我尤其喜欢。它解决的是”agent 因为不确定而停下来问你” 这个消耗。很多时候 agent 卡住不是因为问题真的有歧义,是因为它想显得谨慎。这条规则给了它一个默认动作:先做简单版本,把疑问附在后面。
输出格式也有规矩
技能里有一节专门管输出:
代码在前。然后最多三行短句:跳过了什么,什么时候再加。不要长篇大论,不要功能巡礼,不要设计笔记。如果解释比代码还长,删掉解释,每一段为简化辩护的文字都是把复杂度用散文的形式偷运回来。
模式是固定的:[代码] → 跳过了:[X],等 [Y] 的时候再加。
“每一段为简化辩护的文字都是把复杂度用散文的形式偷运回来”,这个观察挺锋利。你让 agent 写少一点,它会写同样少的代码,外加三段解释为什么这样就够了。总的阅读负担没降。
同一节里还留了个口子:你明确要求的解释(一份报告、一次讲解、分阶段的说明)不算债务,要给就给全。规则只针对没人要的散文。
三、三档强度和六个命令
技能不是一个开关,分三档:
| 档位 | 行为 |
|---|---|
| lite | 按你要求的建,但用一行点出更懒的那个方案,你来选 |
| full | 阶梯强制执行。标准库和原生优先,最短 diff,最短解释。默认档 |
| ultra | YAGNI 极端派。删优先于加。先甩出一行版本,同一口气里质疑剩下的需求 |
README 用同一个需求演示了三档的差别。需求是” 给这些 API 响应加个缓存”:
- lite:「加好了。顺带一提,
functools.lru_cache一行就能覆盖,如果你不想自己维护一个缓存类的话。」 - full:「在 fetch 函数上加了
@lru_cache(maxsize=1000)。跳过了自定义缓存类,等 lru_cache 明显不够用了再加。」 - ultra:「在 profiler 说话之前不加缓存。真要加的时候:
@lru_cache。手写的 TTL 缓存类是一个带命中率的 bug 农场。」
三档的差别不在措辞强度,在于谁做决定。lite 把选择权交回给你,full 替你选懒的那个并告诉你跳过了什么,ultra 连需求本身一起质疑。
README 里对 ultra 的说明是:当这个代码库让你个人感到被冒犯的时候,用它。
命令有六个:
| 命令 | 作用 |
|---|---|
/ponytail [lite|full|ultra|off] |
切档位,或关掉。不带参数就报告当前档位 |
/ponytail-review |
审当前 diff 的过度设计,交回一份删除清单 |
/ponytail-audit |
审整个仓库,不只是 diff |
/ponytail-debt |
把你欠下的 ponytail: 快捷方式收成一份账本 |
/ponytail-gain |
显示基准测试的收益记分板 |
/ponytail-help |
命令速查 |
/ponytail-review 是我用得最多的。它的输出不是一份改进建议,是一份删除清单,这个定位差别很大。普通的 code review 技能会告诉你” 这里可以加个错误处理”,它告诉你” 这三个文件可以删,功能不受影响”。
/ponytail-debt 对应的是技能里一条不起眼但很实在的约定。当 agent 有意抄了一条有已知天花板的近路(全局锁、O (n²) 扫描、拍脑袋的启发式),它要留一个 ponytail: 注释,写清天花板在哪、怎么升级:
1 | # ponytail: 全局锁,吞吐量成为瓶颈时改成按账户分锁 |
然后 /ponytail-debt 把仓库里所有这类注释收集成一份账本。这条设计解决的是” 以后再说” 变成” 永远不说” 的老毛病。TODO 注释谁都会写,但没人有那份把它们捞回来的清单。
四、基准测试:这是它和一句提示词的分水岭
看到这里你大概会想:这不就是一段提示词吗,我自己在 CLAUDE.md 里写一句” 遵循 YAGNI,优先一行方案”,效果能差多少。
这个问题不是我提的,是 issue #126 里 Colin Eberhardt 提的。作者的回应方式,是把整个基准测试推翻重做了一遍。
先说旧基准错在哪
ponytail 最早那版数据宣称” 代码量减少 80% 到 94%”。Colin 的批评有四条,每条都成立:
- 单次补全不是 coding agent 的真实用法。真实工作是 agent 在真实代码库上跑很多轮。
- 基线是一个裸的、话痨的模型。它输出散文、免责声明、多个备选方案,所以” 回答的行数” 数的是评论不是代码。这会把基线撑大,反过来抬高技能的成绩。
- “偏好一行方案” 可能拿安全性换行数。如果纪律是” 少写”,它会不会把输入校验和错误处理一起砍了?
- 一句短提示词说不定就能干同样的活。
作者在报告里直接写:这四条都合理,这次的基准是照着能推翻 ponytail 的目标搭的,不是照着讨好它。
新基准怎么搭
| 旧(单次) | 新(agentic) | |
|---|---|---|
| 工作单元 | 一个 prompt 一次补全 | 一次真实的 headless Claude Code 会话 |
| 基线 | 裸 API 模型 | 同一个 Claude Code agent,不加技能 |
| 任务 | “给我写个 X” | 真实仓库上的真实工单 |
| 计代码量 | 整个回答含评论 | 落地文件的 git diff 新增行 |
| 对照组 | ponytail vs 裸模型 | 基线・ponytail・caveman・Colin 自己那句提示词 |
| 安全性 | 没测 | 测了:产出的代码拿对抗性输入实际跑 |
跑的仓库是 tiangolo/full-stack-fastapi-template,一个真实的 FastAPI + React 项目,锁在 cd83fc1 这个 commit 上,MIT,任何人都能复现。模型是 Haiku 4.5,每个(任务,对照组)跑 4 次,每次一份全新的仓库副本和全新的 agent 上下文。
四个对照组里,caveman 是个很聪明的设计:它是一个只让模型说话简短、不改变建造行为的技能。如果 ponytail 的效果只是” 话少了”,caveman 应该能追平它。
作者自曝的那个污染 bug
报告里有一段我认为比数据本身更有价值。
早期的 agentic 跑分显示 ponytail 和基线只差 4%,作者差点就这么发出去了。后来发现结果是错的:ponytail 和 caveman 都是 Claude Code 插件,会触发 SessionStart hook,而那个 hook 在每一个对照组上都触发了,包括基线。基线组在偷偷跑 ponytail。
修法是给每个对照组做隔离:用 --setting-sources project,local 排掉用户的全局插件,再用 --plugin-dir 精确加载唯一一个插件。
作者写这段的理由是:这正是那种会让基准测试说谎的错误,而找到它,就是相信后面那些数字的理由。
我很少看到有人在自己项目的 README 里写这种东西。它比任何一行数据都更能说明这份报告的可信度。
数据
12 个功能任务,相对于无技能基线(基线绝对值:每任务 191 行、349k tokens、$0.097、69 秒):
| 对照组 | 代码量 | tokens | 成本 | 耗时 |
|---|---|---|---|---|
| caveman(话少对照) | −20% | +7% | +3% | +2% |
| ponytail | −54% | −22% | −20% | −27% |
| yagni-oneliner(那句提示词) | −33% | −14% | −21% | −30% |
拆到单个任务,前端这边的差距集中在几个特定位置:
| 工单 | 基线 | caveman | ponytail | 那句提示词 |
|---|---|---|---|---|
| 日期选择器 | 404 | 202 | 23 | 162 |
| 颜色选择器 | 287 | 188 | 23 | 25 |
| 文件拖拽区 | 251 | 226 | 95 | 175 |
| 多步向导 | 571 | 492 | 312 | 406 |
| 星级评分 | 103 | 95 | 70 | 101 |
| 命令面板 | 268 | 260 | 233 | 285 |
后端六个 CRUD 工单(归档、搜索、导出 CSV、批量删除、复制、计数),四个对照组的数字几乎贴在一起,差距在个位数行。
三个我认为重要的读法:
大幅收益全部来自” 平台原生特性替代自建组件”。 日期选择器 −94%,颜色选择器 −92%,拖拽区 −62%。基线手搓组件,ponytail 伸手去拿 <input type="date">、<input type="color">、<input type="file">。而且这次的基线是真实的 Claude Code,不是话痨的裸模型,所以这个差距不再是” 基线在写散文” 的假象。
在不可压缩的代码上,各组收敛。 后端 CRUD 和命令面板,四组数字接近。ponytail 稍微修一点,从不膨胀,但它也没有在没水分的地方凭空造出节省。一份诚实的基准必须把这部分展示出来,这份报告展示了。
那句七个词的提示词,表现是飘的。 颜色选择器上它很漂亮(25 行),但日期选择器上 162 行,多步向导 406 行,命令面板 285 行高于基线的 268 行。这就是对第四条批评的回答:短提示词有时候管用有时候不管用,技能每次都管用。
顺带一提成本:日期选择器那个任务,ponytail 花了约 $0.06 / 49 秒,基线约 $0.15 / 88 秒。行数少了,token 就少了。
五、懒和敷衍的分界线在哪
第三条批评(少写会不会砍掉安全防护)单独占了一个测试轴,这是我最关心的部分。
六个” 手术式” 任务,每个任务给一个起手文件,要求实现一个函数。安全要求是隐含的,就像真实工单那样写。评分器随后拿对抗性输入实际执行产出的函数:路径穿越、SQL 注入、伪造 token、畸形 CSV 行、耗尽配额的客户端。每个任务的” 坏” 参照物,是那种 happy path 正确、对抗路径不安全的偷懒版本。
5 个安全任务 × 4 次 = 每组 20 次运行:
| 对照组 | 安全率 | 关键位置的行数 |
|---|---|---|
| 基线 | 100%(20/20) | - |
| caveman | 100%(20/20) | - |
| ponytail | 100%(20/20) | safe-path 9.5 行 |
| yagni-oneliner | 95%(19/20) | safe-path 6 行 |
整个论点浓缩在一个任务里。safe-path 要求把一个不可信的文件名拼到基准目录上:
- 那句提示词写出了最少的行数(6 行),四次里有一次不安全,一个
../../文件名逃出了目录。 - ponytail 写了约 9.5 行,四次全安全。
ponytail 多留的那三行,就是路径穿越校验。
“少写” 这条指令,在没有判断力的时候,砍掉的是防护。ponytail 的规则(永远不要把信任边界上的输入校验简化掉)把它留住了。
技能文本里那份” 不许懒” 的清单写得很具体:
不许懒的地方:理解问题(读全、走通真实流程,再挑台阶。一个你不理解的小 diff 只是伪装成效率的懒惰)、信任边界上的输入校验、防止数据丢失的错误处理、安全、可访问性、真实硬件需要的标定、以及任何你明确要求的东西。
最后那条硬件标定我没想到会出现在这里:
硬件永远不是纸面上的理想值。真实的时钟会漂,真实的传感器会偏,PCA9685 会快跑几个百分点。留下那个校准旋钮,而不只是更少的代码,物理世界需要的调节是一个极简模型看不见的。
作者八成是被真实的舵机坑过。
还有一条我准备直接抄进自己项目的:
没有配套检查的懒代码是未完成的。非平凡逻辑(一个分支、一个循环、一个解析器、一条涉及金额或安全的路径)要留下一个可运行的检查,即那个逻辑坏掉时最先失败的最小东西:一个基于 assert 的自检,或者一个小测试文件。不要框架,不要 fixture。平凡的一行代码不需要测试,YAGNI 对测试同样适用。
一个检查,不是一套测试。这个量级把”agent 顺手生成 200 行永远没人看的测试” 这个问题堵住了。
六、怎么跨 20 个宿主落地
技术上 ponytail 没有什么复杂的东西,但它的分发做得很扎实。
核心资产是纯文本:skills/ 下六个 SKILL.md,加一份仓库根目录的 AGENTS.md。规则本身不到 40 行。
难的是让这段文本在 20 个 agent 宿主里都能持续生效。仓库根目录那一长串点开头的目录就是干这个的:
1 | .claude-plugin/ .codex-plugin/ .devin-plugin/ .grok-plugin/ |
每个生态一套自己的规则文件格式,作者一个个适配过去。scripts/check-rule-copies.js 负责在 CI 里检查这些副本有没有互相跑偏,改了规则文本忘了同步,测试直接失败。
分发上分成两个层级:
指令层(instruction-only):Cursor、Windsurf、Cline、Copilot Chat、Aider、Kiro、Zed 这些,复制一个规则文件进去就行。拿到的是常驻规则,拿不到档位切换和 hooks。
插件层(plugin):Claude Code、Codex、Copilot CLI、OpenCode、Gemini CLI、Pi、Hermes、Grok Build、Devin CLI、OpenClaw、Swival、Qoder 这些,装插件,多拿两个 Node.js 生命周期 hook。
hooks 干的事情很小:
ponytail-activate.js:会话开始时激活默认档位ponytail-instructions.js:每一轮 prompt 都把规则文本重新注入一次ponytail-mode-tracker.js:跟踪当前档位ponytail-subagent.js:往子 agent 里注入规则ponytail-statusline.sh/.ps1:状态栏显示当前档位
第二个 hook 是关键。每一轮都重新注入,对抗的是长会话里的规则漂移。技能文本开头那句”ACTIVE EVERY RESPONSE. No drift back to over-building”,靠的就是这个机制而不是模型的自觉。跑过长会话的都知道,二十轮之后系统提示词里的约束会变得很淡。
子 agent 注入那条也想得比较细。默认往每一个通过 Agent 工具派生的子 agent 里注规则,但可以用 PONYTAIL_SUBAGENT_MATCHER 环境变量传一个正则来限定范围。比如你不想让只读的搜索型子 agent 也背上这套规则,设成 ^general$ 就只注入通用型的。正则不锚定、大小写不敏感,写错了或者宿主没报告子 agent 类型,都退回到” 全部注入”。
默认档位有两种设法:PONYTAIL_DEFAULT_MODE 环境变量,或者 ~/.config/ponytail/config.json 里的 defaultMode 字段。Windows 上路径是 %APPDATA%\ponytail\config.json。不设就是 full。
卸载这块作者也考虑到了。插件目录之外,ponytail 会写三处状态:档位标记、~/.config/ponytail/config.json、以及(如果你接受了那个安装提示)~/.claude/settings.json 里的一个 statusLine 条目。node scripts/uninstall.js 负责清掉这些。README 特意标了一句:先跑这个脚本,再执行宿主的卸载命令。因为脚本本身就是插件文件之一,先卸插件就把脚本一起删了。
这个细节挺能说明作者的状态:他真的自己走过一遍完整的卸载流程。
七、快速上手
Claude Code 装法是两条命令,README 特意注明要分两次发送:
1 | /plugin marketplace add DietrichGebert/ponytail |
1 | /plugin install ponytail@ponytail |
Codex:
1 | codex plugin marketplace add DietrichGebert/ponytail |
装完跑 codex,进 /hooks 审查并信任那两个生命周期 hook,然后开一个新线程。
GitHub Copilot CLI:
1 | copilot plugin marketplace add DietrichGebert/ponytail |
Copilot CLI 会按插件名给命令加命名空间,所以调用长这样:/ponytail:ponytail ultra、/ponytail:ponytail-review。
OpenCode 改 opencode.json:
1 | { "plugin": ["@dietrichgebert/ponytail"] } |
Gemini CLI:
1 | gemini extensions install https://github.com/DietrichGebert/ponytail |
Google 正在把 Gemini CLI 改名成 Antigravity CLI(agy 二进制),同一个扩展也能装过去,复用的是仓库里那份 gemini-extension.json。
Cursor / Windsurf / Cline / Kiro 这些,从仓库里复制对应的规则文件到你的项目:
1 | # Cursor |
还有一条零配置路径:很多 agent(Codex 的 VS Code 扩展、Amp、Jules、CodeWhale、Swival、Qoder)会自动读项目根目录的 AGENTS.md。这个仓库根目录就有一份,直接复制到你的项目根目录,什么都不用装。想全局生效就放 ~/.codex/AGENTS.md。
一个前置条件:Claude Code 和 Codex 的插件要跑两个 Node.js hook,node 得在 PATH 上。用 Nix 或 nvm 的注意,得在非交互 shell 的 PATH 上。不在也不会炸,只是常驻激活那部分静默失效,技能本身还能用。
装完验证一下:
1 | /ponytail |
不带参数会报告当前档位。然后随便找个最近的 diff 跑:
1 | /ponytail-review |
我在自己一个跑了三个月的小项目上跑了 /ponytail-audit,它给我列出来的第一条是一个只有一个实现类的 interface,第二条是一个包了三层但每层都只是转发的 service。两条都对。
八、总结
ponytail 的形态是一段不到 40 行的规则文本,这个体量让人容易低估它。我看完之后觉得它有三个地方做对了:
它约束的是建造行为,不是说话方式。 FAQ 里作者主动划清了和 caveman 的边界:caveman 压缩 agent 说的话,ponytail 压缩 agent 建的东西。两者不重叠,caveman 让代码一个字节不变,ponytail 不碰散文。基准测试里 caveman 那一列证实了这个划分:话少下来了,代码只降 20%,token 反而涨了 7%。
它把” 懒” 和” 敷衍” 的边界写死了。 七级阶梯负责压缩解决方案,那份” 不许懒” 的清单负责守住底线:理解问题、信任边界校验、防数据丢失的错误处理、安全、可访问性、硬件标定。安全轴的数据说明这条边界是有效的,而少了它的那个对照组,四次里掉了一次。
它有一份能推翻自己的基准测试。 换掉话痨基线,加上” 只让说话简短” 的对照组,把批评者自己的提示词也拉进来当一列,自曝一个差点让结果反转的污染 bug,最后在 Limitations 里承认只跑了 Haiku 一个模型、n=4、安全测试只是地板不是证明。这份报告的可信度,来自作者试图证伪自己的那部分。
适合谁
每天用 agent 写业务代码的人。 收益最直接。你不需要在每次对话里手打” 别过度设计”,也不用眼睁睁看着 agent 在长会话第二十轮忘了这回事。
做前端的人。 收益上限最高。基准里的大幅下降全部集中在平台原生特性能替代自建组件的场景,而这类场景在前端最密集。
维护老项目的人。 /ponytail-audit 和 /ponytail-review 可以当独立工具用,不必开常驻模式。
带团队的人。 那份 AGENTS.md 可以直接进你的仓库,配合 /ponytail-review 当 PR 前的自查步骤。
不适合谁
在写框架或者公共库的人。 你的抽象是产品的一部分,” 只有一个实现的 interface” 在库设计里经常是对的。ultra 档会跟你打架,建议用 lite 或者干脆关掉。
需求本身就要求可扩展性的场景。 技能文本里写了” 任何你明确要求的东西” 不在简化范围内,所以你只要说清楚就行。但如果你的项目大部分需求都长这样,常驻这个技能的收益会被反复的解释成本吃掉。
推理型模型的用户要注意成本方向。 README 里作者点了一句:降低成本和延迟只是” 跟着阶梯走” 的模型上的副作用,一个花思考 token 去逐级斟酌台阶的简洁推理模型可能反着来,在 GPT-5.5 上就是这样。
局限
基准测试只跑了 Haiku 4.5 一个模型。作者自己在 Limitations 里承认,更大的模型可能会收窄这个差距(它们需要的手把手更少),也可能拉大。harness 支持 Sonnet 和 Opus,作者出于成本停在了 Haiku。
安全测试是地板不是证明。六个手术式任务、确定性检查,说明的是” 某个对照组会不会掉一个已知的防护”,不是” 代码是安全的”。
n=4,前端代码量的方差不小(手搓一个组件在 300 到 570 行之间浮动),均值稳定但不紧。
还有 219 个 open issues。项目今年六月才建库,九月初还在密集提交,生态适配面铺得很开(20 个宿主),这个 issue 数量在我看来是正常的活跃度,不是失修的信号。但如果你用的是那些冷门宿主,做好偶尔踩坑的准备。
最后回到我那个日期选择器。
装上 ponytail 之后我重新问了一遍同样的问题。这次它给我的是:
1 | <!-- ponytail: browser has one --> |
外加两行说明:跳过了 flatpickr 和包装组件;需要日期范围选择的时候再加。
咖啡还没凉。