ARTICLE · 1113616
AI 写的代码越堆越多?ponytail 让编程 Agent 学会偷懒
YAGNI · 原生优先 · 最短可行差异 · 编码 Agent 约束
DietrichGebert/ponytail 把一位「最懒的资深工程师」塞进你的编程 Agent, 让它在动手写代码前先问一句:这段代码真的需要存在吗。 它是一份可安装的规范包,以技能、插件与生命周期钩子的形式, 覆盖 Claude Code、Codex、Cursor、OpenCode 等 20 个编程 Agent 宿主。 它不教 Agent 写得更漂亮,只逼它写得更少—— 少到刚好够用,同时不许碰掉校验、安全与无障碍。
过度建设:Agent 的默认姿势
你让 Agent 加一个日期选择器。 它装上 flatpickr,写一个包装组件,加一份样式表, 最后拉着你讨论时区处理——而你只是想要一个能选日期的框。
这不是模型笨,而是它的默认姿势就是「尽量显得有用」。 在不确定需求边界时,它倾向于交付完整的、可配置的、面向未来的方案, 因为这样的答案在训练数据里被反复奖励过。
过度建设通常会以这几种面孔出现:
• 为一次性需求引入依赖: 为了一个格式化函数装进整个日期库,或者为了一个弹窗装一整套组件库。
• 只有一个实现的抽象: 一个接口配一个实现、一个工厂只生产一种产品、一层包装只做转发。
• 没人会设的配置: 为永远不会变化的取值留一个参数, 为「以后可能要支持」的第三种情况预留分支。
• 面向未来的脚手架: 先把目录、基类、注册表搭好,功能本身还没开始写。
这些多出来的东西,代价不在当下,而在往后: 更多代码要评审、更多 token 要付费、 更多抽象要在某个凌晨被后人读懂。 对每天用 Agent 提交 diff 的团队、按量计费的独立开发者, 以及在成熟仓库里做增量功能的人来说,这是持续成本。
更棘手的是,Agent 的产出速度远高于人的审查速度。 当一份 diff 里有一多半是你并不需要的代码时, 真正的功能改动反而被淹没其中, 评审者要么逐行读完再整体退回,要么干脆放行。
怎么用:装一次,长期生效
ponytail 的安装是一次性的,生效是长期的。 它按宿主提供对应入口,你挑自己正在用的那条路即可:
• Claude Code:在插件市场里添加仓库再安装, 官方提示需要分两条消息发送插件市场添加与安装两条命令。
• OpenCode:在 opencode.json 里加一行 plugin 配置即可,
插件会每轮注入规则,并补上四档强度。
• Cursor:执行安装脚本, 它会把两个原生钩子合并进你的钩子配置,你原有的钩子不受影响。
• 只读规则文件的宿主(Codex、Windsurf、Cline、Copilot Chat 等):
把仓库根目录的 AGENTS.md 或对应规则文件复制进项目即可,零配置。
装好之后,用 lite / full / ultra / off 调档,默认是 full;
lite 只提示更懒的替代,ultra 是 YAGNI 极端派,off 恢复正常模式。
三个贴近真实需求的样例,能看出它到底改了什么:
• 加一个日期选择器。 你只说「加个日期选择器」,它不再引入组件库,直接给出原生日期输入框。 在官方基准里,同一个任务从 404 行降到 23 行。
• 做删除确认弹窗。
常见做法是先装一套对话框组件再写三十行包装;
它改用原生 <dialog>,八行搞定,
焦点陷阱、Esc 关闭、遮罩都由浏览器自带。
• 写一个深拷贝。
过去要么装 lodash,要么用 JSON.parse(JSON.stringify(x)) 这种会丢掉
Date、Map 与循环引用的写法;它一句 structuredClone(x) 收工。
需要说清楚的误区是:ponytail 不是「越短越好」。 它在规则里明确划出不许动的部分—— 信任边界的输入校验、防止数据丢失的错误处理、安全措施、无障碍基础。 官方对照实验中,它和基线一样通过了全部安全用例; 反而是只写「偏好一行代码」的短提示词,在路径穿越那道题上掉了一次防线。
如果它确实为了省事砍掉了一个角,也必须留下痕迹:
用 ponytail: <天花板>, <何时回头> 形式的注释标出来,
/ponytail-debt 能把这些欠账收成一张账本,
避免「以后再说」变成「永远不做」。
原理:七级梯子与一条红线
ponytail 的核心是一段规则文本,加上把它送进每次对话的宿主钩子。
钩子在会话开始和每次提交提示词时注入规则集,
用一个小状态文件记录当前档位,
并针对不同宿主适配输出格式:
Claude Code 直接读原始标准输出,
Codex、Copilot、Qoder 走 hookSpecificOutput 的 JSON,
Cursor 需要 additional_context。
这就是它能横跨 20 个宿主、而不用为每个平台重写一遍逻辑的原因。
规则本身是一把七级梯子,停在第一个站得住的台阶:
1. 这件事需要存在吗?不需要就跳过。
2. 代码库里已经有?复用,别重写。
3. 标准库能做?用它。
4. 原生平台特性覆盖了?用它。
5. 已安装的依赖能解决?用它。
6. 能写成一行?就一行。
7. 都不行,才写最小可用代码。
梯子的前提常被忽略:它跑在「理解问题之后」。 在挑台阶之前,Agent 要先读被改动的代码、把真实调用链走通; 「没读懂就写小 diff」不叫懒,叫把 bug 藏得更深。 同一个逻辑也用在修 bug 上——先找出所有调用方, 在共享函数里加一道护栏,比分头补每个入口更小也更彻底。
它的创新点不是「最少 token」,而是「只写任务真正需要的」。 官方用真实 Claude Code 会话改一个 FastAPI + React 模板, 在 12 个功能任务上做了对照: 代码行数下降约 54%,token 降 22%,成本降 20%,耗时降 27%, 是唯一每项指标都下降的组; 而在本来就没有冗余的后端 CRUD 上,各组差距几乎为零。 这个「有冗余的地方大降、没冗余的地方打平」的分布, 比一个漂亮的总数字更能说明它的作用边界。
代价也要说清楚。 对有推理开销的模型,反复权衡台阶本身会消耗思考 token, 在某些模型上整体反而更贵; 把「少写」误读成「能省则省」的团队, 也会踩到它明确保护的那些红线。
落地:从省 token 到省评审
最直接的落地是在成熟仓库里做增量功能。 让 Agent 在第 2 级或第 5 级台阶就停下—— 复用仓库里已有的工具函数、复用已经装好的依赖—— 你拿到的是一个更小的 diff, 评审时间、合并冲突和后续维护面都会跟着缩小。
第二个场景是把它接进代码评审流程。
/ponytail-review 针对当前 diff、/ponytail-audit 针对整个仓库,
输出的是可执行的删除清单,
每条带删除、标准库、原生、YAGNI、精简五类标签和替换建议,
最后给出「净可减少 N 行」;
比「建议进一步简化」这种无法执行的评语有用得多。
再往上看,它的跨宿主设计意味着这份工程纪律可以跟着人走: 在 Claude Code 里定的规则,换到 Codex、Cursor 或 OpenCode 依然成立, 团队不必为每个 Agent 重新解释一遍「我们不要过度设计」。 当「少写多余的代码、但绝不少写校验与安全」变成可安装、可审计的默认, AI 编码的收益才真正从生成速度,落到可维护的代码上。