Ponytail 规则文件深度解读:让 AI Agent 像最懒资深工程师一样写代码
本文以仓库中的 .agents/rules/ponytail.md 规则文件为主体,完整拆解 Ponytail 项目的核心方法论:七级"懒惰阶梯"、根因修复原则、九条编码禁令与安全例外清单;并结合 scripts/check-rule-copies.js、hooks/ponytail-instructions.js、hooks/ponytail-config.js 等源码,说明这份仅 30 行的规则文本如何被复制、校验并注入到 20 多种 Agent 工具中。读完你可以直接复用这份规则文件到自己项目,并理解它的分发与校验机制。
一、这个文件是什么:一份跨 Agent 的"常驻人格"
.agents/rules/ponytail.md 是 Ponytail 项目面向支持 .agents/rules/ 约定的 Agent(如 Antigravity CLI)的规则文件。它的全文只有 30 行,却定义了 Ponytail 项目最核心的思想——让 AI Agent 扮演"团队里最懒的资深工程师":
You are a lazy senior developer. Lazy means efficient, not careless. The best code is the code never written. (你是懒惰的资深开发者。懒意味着高效,而非粗心。最好的代码是你根本没写的代码。)
这份文件不是孤立的。从 scripts/check-rule-copies.js 的源码可以看出,Ponytail 以根目录的 AGENTS.md 为规范来源(canonical),将同一份规则正文复制到各宿主工具各自的规则路径,并在 CI 中做字节级比对:
// scripts/check-rule-copies.js
const agents = read('AGENTS.md');
const canonical = agents.replace(/\n\n\(Yes, this file also applies[\s\S]*?\)$/, '').trim();
// Compact copies: same body as AGENTS.md, host-specific frontmatter stripped.
const copies = [
['.cursor/rules/ponytail.mdc', stripFrontmatter],
['.windsurf/rules/ponytail.md', text => text.trim()],
['.clinerules/ponytail.md', text => text.trim()],
['.agents/rules/ponytail.md', text => text.trim()],
['.qoder/rules/ponytail.md', text => text.trim()],
['.github/copilot-instructions.md', text => text.trim()],
['.kiro/steering/ponytail.md', stripFrontmatter],
];
任何一份副本与 AGENTS.md 正文出现漂移,脚本就会报错退出。脚本中还维护了一组"规则不变量"(如 in this codebase、ONE runnable check、input validation at trust boundaries 等短语),断言这些承重规则必须逐字存在于 skills/ponytail/SKILL.md 和 AGENTS.md 中——改一条规则的措辞就会触发失败,以此强制规则变更同步传播到所有副本。换句话说,.agents/rules/ponytail.md 是一个被脚本守护的"分发型"文件,理解它的规则正文就理解了 Ponytail 的全部方法论。
二、七级"懒惰阶梯":写代码前的强制检查序列
规则文件的核心是一条七级阶梯,要求 Agent 在写任何代码之前,从第一级开始逐级检查,停在第一个成立的那一级(原文:"stop at the first rung that holds"):
1. Does this need to be built at all? (YAGNI)
2. Does it already exist in this codebase? Reuse the helper, util, or pattern
that's already here, don't re-write it.
3. Does the standard library already do this? Use it.
4. Does a native platform feature cover it? Use it.
5. Does an already-installed dependency solve it? Use it.
6. Can this be one line? Make it one line.
7. Only then: write the minimum code that works.
逐级解读:
- YAGNI 检查:这个功能到底需不需要建?不需要就跳过;
- 仓库内复用:代码库里是否已有 helper、util 或模式?直接复用,绝不重写。这是与 skills/ponytail/SKILL.md 中更详细版本呼应的关键一级——SKILL.md 称"重新实现几格代码之外的现成函数"是最常见的低质代码来源;
- 标准库优先:标准库能做就用标准库;
- 原生平台能力:例如浏览器原生
<input type="date">替代日期选择器组件库、CSS 替代 JS、数据库约束替代应用层代码; - 已安装依赖:已经装好的依赖能解决就用,绝不为此新增依赖;
- 一行化:能写成一行就写一行;
- 最后手段:以上都不行时,才写"最小可工作代码"。
README.md 中的"Before / after"示例展示了这套阶梯的典型效果:用户要一个日期选择器,普通 Agent 会安装 flatpickr、写封装组件、加样式表;启用 Ponytail 后的产出是:
<!-- ponytail: browser has one -->
<input type="date">
更多前后对比案例可参考 examples/ 目录。
三、顺序原则:先理解问题,再爬阶梯
阶梯之后紧跟一句约束原文(这是文件中最容易被忽略、却最关键的一条):
The ladder runs after you understand the problem, not instead of it: read the task and the code it touches, trace the real flow end to end, then climb.
即:阶梯是在你理解问题之后运行的,而不是代替理解。正确顺序是——完整阅读任务、通读改动涉及的代码、端到端追踪真实流程,然后才从第一级开始爬。这条约束在后文"不懒惰清单"里被再次强调:"一个你并不理解的小 diff,只是把懒惰包装成了高效"(a small diff you don't understand is just laziness dressed up as efficiency)。
四、Bug 修复原则:修根因,不修症状
文件用一整段专门定义了修 Bug 的方法论:
Bug fix = root cause, not symptom: a report names a symptom. Grep every caller of the function you touch and fix the shared function once — one guard there is a smaller diff than one per caller, and patching only the path the ticket names leaves a sibling caller still broken.
拆解其逻辑:
- 工单/报告描述的是症状,不是根因;
- 动手前,grep 出你要改的函数的所有调用方;
- 在共享函数里一次性加防护:一处守卫的 diff 比每个调用方各加一处更小;
- 只修补工单点名的那条路径,会让兄弟调用方继续带着同样的 bug 运行。
这条原则把"最懒"与"最正确"统一了起来:修复根因恰好也是改动量最小的方案。
五、九条编码规则:逐条继承
文件的 Rules: 一节给出了九条硬性约束,完整列如下:
| # | 规则(原文要点) | 含义 |
|---|---|---|
| 1 | No abstractions that weren't explicitly requested | 未明确要求就不引入任何抽象层 |
| 2 | No new dependency if it can be avoided | 能避免就不新增依赖 |
| 3 | No boilerplate nobody asked for | 不写没人要的样板代码 |
| 4 | Deletion over addition. Boring over clever. Fewest files possible | 删优于增、无聊优于聪明、文件数最少 |
| 5 | Shortest working diff wins, but only once you understand the problem | 最短可工作 diff 获胜——但前提是先理解问题;改在错误位置的最小变更不是懒,而是第二个 bug |
| 6 | Question complex requests: "Do you actually need X, or does Y cover it?" | 对复杂需求主动质疑:"你真的需要 X,还是 Y 就够?" |
| 7 | Pick the edge-case-correct option when two stdlib approaches are the same size | 两个等长的标准库方案中,选边界情况正确的那个——"懒"意味着代码更少,而不是选更脆弱的算法 |
| 8 | Mark deliberate simplifications ... with a ponytail: comment naming the ceiling and upgrade path |
对确有上限的刻意简化(全局锁、O(n²) 扫描、朴素启发式)用 ponytail: 注释标出上限与升级路径 |
| 9 | (隐含在第 5 条)最短 diff 只在理解问题后才算"赢" | 防止"最小改动"被误用为"最小理解" |
其中第 8 条是全仓库统一的注释约定:# ponytail: global lock, per-account locks if throughput matters 这类注释既记录技术债,又给出升级方向。项目自己的 hooks/ponytail-config.js 中就有实例,例如 getDefaultMode() 里:
// ponytail: a default must be a runtime level (off/lite/full/ultra); review is
// a session-only mode, never a valid default (#377). Validate against
// RUNTIME_MODES so a stray env var or config can't make review the default.
仓库还提供 /ponytail-debt 命令,专门把这些 ponytail: 注释收割成债务清单,"让'以后再说'不至于变成'永远不说'"(见 README.md 的 Commands 一节与 commands/ponytail-debt.toml)。
六、"不懒惰"清单:规则的例外与下限
文件最后一段 Not lazy about: 划定了规则的边界——以下内容永远不能为了省事而简化:
- 理解问题本身:选阶梯前先完整阅读任务、追踪真实流程;
- 信任边界的输入校验(input validation at trust boundaries);
- 防止数据丢失的错误处理(error handling that prevents data loss);
- 安全(security);
- 可访问性(accessibility);
- 真实硬件需要的校准:平台从不是规格书上的理想状态,时钟会漂移、传感器读数会偏——要留下校准旋钮,而不只是"更少的代码";
- 任何被用户明确要求的东西(anything explicitly requested)。
这一段还包含一个重要的质量下限要求,原文:
Lazy code without its check is unfinished: non-trivial logic leaves ONE runnable check behind, the smallest thing that fails if the logic breaks (an assert-based demo/self-check or one small test file; no frameworks, no fixtures). Trivial one-liners need no test.
即:没有配套检查的懒代码是未完成的。非平凡逻辑(分支、循环、解析器、资金/安全路径)必须留下一个可运行的检查——一个会因逻辑破坏而失败的 assert 式自检,或一个小测试文件;不引入框架和 fixture。平凡的一行代码则无需测试(YAGNI 同样适用于测试)。注意 check-rule-copies.js 把 ONE runnable check 列为承重不变量之一,说明该要求在整个规则体系中的地位。
七、源码纵深:这份规则如何进入 Agent 的上下文
理解了规则正文后,再看它在仓库中的分发与注入机制,能验证"这份 30 行文本确实是项目灵魂"这一判断。
1. 运行时的完整版本在 SKILL.md
skills/ponytail/SKILL.md 是"运行时真相源"(runtime source of truth),内容比 .agents/rules/ponytail.md 更长,除同一套阶梯与规则外,还额外定义了强度分级:
| 级别 | 行为 |
|---|---|
| lite | 照做用户要求的,但用一行指出更懒的替代方案,由用户选 |
| full | 强制执行阶梯:标准库与原生存能力优先,最短 diff、最短解释。默认级别 |
| ultra | YAGNI 极端派:删除优先于添加,交付一行方案的同时质疑其余需求 |
README.md 给出了三个级别对同一请求("给这些 API 响应加缓存")的响应示例:lite 会说"functools.lru_cache 一行就能覆盖";full 直接交付 @lru_cache(maxsize=1000) 并声明"跳过了自定义缓存类,直到 lru_cache 被证明不够再加";ultra 则回"没有 profiler 数据之前不加缓存"。
2. 注入器:按模式过滤规则正文
hooks/ponytail-instructions.js 是 Claude Code / Codex hooks 与 Pi 扩展共用的指令构建器。它的 filterSkillBodyForMode() 函数按当前强度级别过滤 SKILL.md 正文——只保留当前级别的强度表格行和对应示例,其余规则逐字保留;读取 SKILL.md 失败时退回到内嵌的 getFallbackInstructions()(一份与本文第二、四、五、六节内容一致的紧凑版规则)。这解释了为什么规则文本可以在多个宿主间保持行为一致:正文单点维护,注入时按模式裁剪。
3. 默认级别的解析顺序
hooks/ponytail-config.js 的 getDefaultMode() 实现了三级解析(源码注释即文档):
1. PONYTAIL_DEFAULT_MODE 环境变量
2. 配置文件 defaultMode 字段:
- $XDG_CONFIG_HOME/ponytail/config.json(若设置)
- ~/.config/ponytail/config.json(macOS / Linux)
- %APPDATA%\ponytail\config.json(Windows)
3. 'full'
配置文件非必需:没有配置文件时默认 full。源码同时做了两处防御——只接受 off/lite/full/ultra 四个运行时级别作为默认值(review 是会话级模式,不能被设为默认),并在读 JSON 前剥离 UTF-8 BOM(Windows 下常见)。
八、实战用法:把这份规则装进你的 Agent
规则文件本身即是产品。以本仓库 README.md 的 Install 一节为准,主要用法分两类:
插件式安装(获得模式切换与 hook 注入),以 Claude Code 为例:
/plugin marketplace add DietrichGebert/ponytail
/plugin install ponytail@ponytail
(两条命令需分开发送;Codex、Copilot CLI、Devin CLI、OpenCode、Gemini CLI、Hermes 等均有对应安装命令,见 README.md。)
指令式安装(零依赖):把对应规则文件复制到目标项目的宿主规则路径。本仓库为各宿主备好了副本,映射关系可查 docs/agent-portability.md:
| 宿主 | 规则路径 |
|---|---|
.agents/rules/ 兼容工具 |
.agents/rules/ponytail.md(本文主体) |
| 通用 / Aider / Zed / Amp / Jules / Codex(VS Code 扩展) | AGENTS.md |
| Cursor | .cursor/rules/ 下的 ponytail.mdc |
| Windsurf | .windsurf/rules/ 下的 ponytail.md |
| Cline | .clinerules/ponytail.md |
| GitHub Copilot Chat / CLI 降级模式 | .github/copilot-instructions.md 或复制到 ~/.copilot/copilot-instructions.md |
| Kiro | .kiro/steering/ponytail.md(复制到 ~/.kiro/steering/ 可全局生效) |
| Qoder | .qoder/rules/ponytail.md |
安装后的常用命令(需要支持 skill 的宿主):/ponytail [lite|full|ultra|off] 切换强度、/ponytail-review 审查当前 diff 中的过度设计、/ponytail-audit 全仓审计、/ponytail-debt 收割 ponytail: 注释、/ponytail-help 查看速查。关闭方式:发送 "stop ponytail" / "normal mode"(从 hooks/ponytail-config.js 的 isDeactivationCommand() 可见,必须是整条消息本身,避免"加一个 normal mode 开关"这类普通请求误触关闭)。
九、方法论的可验证性:项目如何证明规则有效
规则的价值不能只靠口号。README.md 报告的 agentic 基准(方法、逐任务表格与局限见 benchmarks/results/2026-06-18-agentic.md):在真实 FastAPI + React 仓库上跑 12 个功能工单、同一 Agent 有/无该规则、n=4,ponytail 组相对无 skill 基线在 LOC、tokens、cost、time 四项指标同时下降,且在对抗性安全分层测试中保持与基线同级的安全性——而一个只说"YAGNI + 一行化"的裸 prompt 对照组在安全分层上丢了 5%。仓库强调的口径是:规则从来不是"最少 token",而是"只写任务需要的,且绝不砍校验、错误处理、安全与可访问性"。复现单发版基准可用 npx promptfoo eval -c benchmarks/promptfooconfig.yaml,完整基准脚本见 benchmarks/。
结语:30 行文本的完整闭环
回到 .agents/rules/ponytail.md 本身,它的设计可以概括为四件事:一条七级阶梯决定"写什么",一条顺序约束保证"先理解再懒",一条根因原则约束"修在哪",一份不懒惰清单守住安全下限。配合 check-rule-copies.js 的字节级一致性守护与 hooks 注入器,这 30 行文本既是给 Agent 的人格,也是可被脚本验证的工程制品——这正是 Ponytail 项目名那句座右铭的最佳注脚:The best code is the code you never wrote(最好的代码是你从没写的代码)。
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 StartedRust0623
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