首页
/ Ponytail 规则文件深度解读:让 AI Agent 像最懒资深工程师一样写代码

Ponytail 规则文件深度解读:让 AI Agent 像最懒资深工程师一样写代码

2026-09-03 15:21:36作者:凤尚柏Louis

本文以仓库中的 .agents/rules/ponytail.md 规则文件为主体,完整拆解 Ponytail 项目的核心方法论:七级"懒惰阶梯"、根因修复原则、九条编码禁令与安全例外清单;并结合 scripts/check-rule-copies.jshooks/ponytail-instructions.jshooks/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 codebaseONE runnable checkinput validation at trust boundaries 等短语),断言这些承重规则必须逐字存在于 skills/ponytail/SKILL.mdAGENTS.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.

逐级解读:

  1. YAGNI 检查:这个功能到底需不需要建?不需要就跳过;
  2. 仓库内复用:代码库里是否已有 helper、util 或模式?直接复用,绝不重写。这是与 skills/ponytail/SKILL.md 中更详细版本呼应的关键一级——SKILL.md 称"重新实现几格代码之外的现成函数"是最常见的低质代码来源;
  3. 标准库优先:标准库能做就用标准库;
  4. 原生平台能力:例如浏览器原生 <input type="date"> 替代日期选择器组件库、CSS 替代 JS、数据库约束替代应用层代码;
  5. 已安装依赖:已经装好的依赖能解决就用,绝不为此新增依赖;
  6. 一行化:能写成一行就写一行;
  7. 最后手段:以上都不行时,才写"最小可工作代码"。

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: 划定了规则的边界——以下内容永远不能为了省事而简化:

  1. 理解问题本身:选阶梯前先完整阅读任务、追踪真实流程;
  2. 信任边界的输入校验(input validation at trust boundaries);
  3. 防止数据丢失的错误处理(error handling that prevents data loss);
  4. 安全(security);
  5. 可访问性(accessibility);
  6. 真实硬件需要的校准:平台从不是规格书上的理想状态,时钟会漂移、传感器读数会偏——要留下校准旋钮,而不只是"更少的代码";
  7. 任何被用户明确要求的东西(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.jsONE 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.jsgetDefaultMode() 实现了三级解析(源码注释即文档):

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.jsisDeactivationCommand() 可见,必须是整条消息本身,避免"加一个 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(最好的代码是你从没写的代码)。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
504
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384