首页
/ 解析 Ponytail 的 AGENTS.md:七级决策阶梯与"懒但靠谱"的 Agent 规则文件设计

解析 Ponytail 的 AGENTS.md:七级决策阶梯与"懒但靠谱"的 Agent 规则文件设计

2026-09-04 23:57:55作者:明树来

Ponytail 是一个把"最懒的资深工程师"注入 AI 编码代理的技能包,而 AGENTS.md 正是这套规则体系中最精炼的"单源真值"(canonical source):它仅用一个 Markdown 文件,定义了代理在动手写代码前必须走完的七级决策阶梯、八条硬性规则,以及绝不可省略的安全边界。读完本文,你将掌握这份规则文件的完整内容与设计逻辑,了解它如何被字节级同步到 7 个不同 Agent 平台的规则副本、如何被 hooks 作为兜底指令注入会话,以及如何在自己的项目中复用或校验它。

AGENTS.md 在项目中的定位

Ponytail 的规则文本实际上维护着三个层次:

  • skills/ponytail/SKILL.md:运行时完整规则,包含强度等级(lite/full/ultra)、输出格式约束和完整示例,是最长的一份;
  • AGENTS.md紧凑版常驻指令集,面向不支持 Skill 机制的通用 Agent(Cursor、Windsurf、Cline、Qoder、CodeWhale、Amp、Jules 等会直接读取仓库根目录的 AGENTS.md);
  • 各平台的规则副本(.cursor/rules/ponytail.mdc.clinerules/ponytail.md 等),要求与 AGENTS.md 逐字节一致。

docs/agent-portability.md 中明确列出了哪些宿主走 "Instruction-tier"(仅靠读取 AGENTS.md 生效),并给出一条适配原则:"Keep adapters thin"——支持 skills/hooks 的宿主指向已有文件,只支持项目指令的宿主则保持其规则文本与 AGENTS.md 对齐。Gemini CLI 的扩展清单 gemini-extension.json 也是直接把 contextFileName 指向 AGENTS.md,实现每次会话的 always-on 注入。

换句话说,AGENTS.md 既是"规则",也是 Ponytail 规则分发体系的中枢锚点——下面逐段拆解它到底写了什么。

第一原则:懒是效率,不是粗心

文件开篇第一句定调:

You are a lazy senior developer. Lazy means efficient, not careless. The best code is the code never written.

"最好的代码是你根本没写的代码"——这是整份文件的世界观:省掉的每一行代码,都是永远不会出 bug 的代码。这个口号在 skills/ponytail/SKILL.md 中被进一步展开为"你见过每一个过度工程化的代码库,并曾因为其中一个在凌晨 3 点被叫起来修",把"懒"的动机锚定在真实的运维代价上。

七级决策阶梯:写任何代码前先停

AGENTS.md 的核心是一个 7 级阶梯(原文第 5–13 行),要求在写任何代码之前,停在"第一级站得住的梯级"上:

1. Does this need to be built at all? (YAGNI)        —— 这东西到底需不需要建?
2. Does it already exist in this codebase?          —— 代码库里已有?复用 helper/util/模式,别重写
3. Does the standard library already do this?       —— 标准库能做?用标准库
4. Does a native platform feature cover it?        —— 平台原生能力能覆盖?用它
5. Does an already-installed dependency solve it?  —— 已安装的依赖能解决?用它
6. Can this be one line? Make it one line.          —— 能一行写完?就写一行
7. Only then: write the minimum code that works.    —— 走到这里才写"能工作的最小代码"

这个阶梯是典型的"成本从低到高"决策链:先问存在必要性(YAGNI),再问复用性(代码库 → 标准库 → 平台原生 → 既有依赖),最后才谈"写最少的新代码"。它对应 Ponytail 的招牌案例:当 Agent 被要求做一个日期选择器时,不安装 flatpickr、不写包装组件、不讨论时区,而是直接输出 <!-- ponytail: browser has one --> + <input type="date">(见 README.md 的 Before/after 一节)。

skills/ponytail/SKILL.md 对阶梯补充了两条执行细节,AGENTS.md 的紧凑版没有展开:

  • 两个梯级都成立时,取更高级的那个然后继续走("Two rungs work → take the higher one and move on")。阶梯是反射动作,不是研究项目;
  • "第一个能用的懒方案就是对的方案"——前提是你已经知道这个改动必须触碰哪些代码。

阶梯的前提:先理解问题,再谈懒

AGENTS.md 紧接着给出了使用阶梯的时序约束(原文第 15 行):

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.

先读任务、读被改动的代码、把真实执行流从头到尾追一遍,然后才爬阶梯。SKILL.md 把这一点说得更狠:"The ladder shortens the solution, never the reading"——阶梯缩短的是方案,永远不是阅读。它甚至点名了危险的反模式:"跳过理解直接交付小 diff 的懒,是伪装成效率的懒,它会以自信的姿态交付一个错误的修复。"

这条约束解释了为什么 Ponytail 的实测收益在"本来就已经很小的代码"上趋近于零(见 benchmarks/results/2026-06-18-agentic.md):省代码的前提是看懂了该省什么,而不是盲目删减。

Bug 修复 = 修根因,不是修症状

AGENTS.md 第 17 行是全文最浓缩的一条工程方法论:

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.

一个 issue 报的是症状;动手前 grep 出你即将触碰的函数的所有调用方,然后把修复放在共享函数里一次完成。理由被直接算成了 diff 大小:在共享函数里放一个 guard,比在每个调用方各放一个 guard 的 diff 更小;而只补丁工单点名的那条路径,会让兄弟调用方继续处于坏的状态。

值得注意的是"懒"在这里与"根因"合流了:对 Ponytail 来说,最省的 diff 恰好就是根因修复本身,而不是在症状路径上打的小补丁。skills/ponytail/SKILL.md 的对应段落("Bug fix = root cause, not symptom")给出了同样的操作指令:"Before you edit, grep every caller of the function you're about to touch."

Rules:八条硬性规则逐条拆解

AGENTS.md 第 19–28 行列出八条规则,每一条都针对 Agent 过度工程化的高频故障模式:

规则 针对的故障模式
No abstractions that weren't explicitly requested. 没人要的单实现接口、单产品工厂、不变值的配置项
No new dependency if it can be avoided. "就几行代码的事,别为此装一个新依赖"
No boilerplate nobody asked for. 没人要的样板代码与"以后要用"的脚手架
Deletion over addition. Boring over clever. Fewest files possible. 优先删而不是加;无聊优于聪明——"clever 是别人在凌晨 3 点要解码的东西"
Shortest working diff wins, but only once you understand the problem. "在错误位置的最小改动不是懒,是第二个 bug"
Question complex requests: "Do you actually need X, or does Y cover it?" 直接质疑复杂需求,而不是闷头照做
Pick the edge-case-correct option when two stdlib approaches are the same size. 两个标准库方案体量相同时,选边界情况正确的那个——懒是少写代码,不是选更脆弱的算法
Mark deliberate simplifications … with a ponytail: comment naming the ceiling and upgrade path. 刻意简化且留有已知上限的角落必须留标记

其中三条值得单独展开:

1. 质疑需求,但不阻塞。 SKILL.md 给出了配套的话术模式:"Ship the lazy version and question it in the same response, 'Did X; Y covers it. Need full X? Say so.' Never stall on an answer you can default."——先交付懒版本,同时在同一回复里提出质疑,绝不在本可以给出默认答案的地方停下来等确认。

2. "懒"有算法正确性底线。 第七条规则常被误读为"能省则省",但它同时钉死了另一头:体量相同的两个方案之间,选边界正确的。这与 Ponytail 的实测结论一致——在 benchmarks/results/2026-06-18-agentic.md 的对比中,ponytail 组是唯一"四项指标全降且安全性 100%"的组,而单纯"写一行代码"的提示词组安全性掉到 95%,因为它会砍掉防护。

3. ponytail: 上限注释——给"技术债"上明码标价。 第八条规则要求:凡是刻意简化、切了真实角落且存在已知上限(全局锁、O(n²) 扫描、朴素启发式)的代码,必须留一个 ponytail: 注释,写清上限和升级路径。SKILL.md 给了标准格式示例:

# ponytail: global lock, per-account locks if throughput matters

这个标记不是普通 TODO:配套技能 /ponytail-debtskills/ponytail-debt/SKILL.md)会把散落在代码里的 ponytail: 捷径收割成一份可追踪的台账,让"以后再优化"不至于变成"永远不优化"。

Not lazy about:绝不可省的清单

AGENTS.md 第 30 行用一整段长句划定了"懒"的禁区(这是全文信息密度最高的一句):

  • 理解问题——完整读任务并追完真实流程之前不许选梯级;"一个你不理解的小 diff,只是伪装成效率的懒";
  • 信任边界的输入校验(input validation at trust boundaries);
  • 防数据丢失的错误处理(error handling that prevents data loss);
  • 安全(security);
  • 可访问性(accessibility);
  • 真实硬件需要的校准——"平台从来不是规格书上的理想态:时钟会漂移,传感器读数会偏";
  • 用户明确要求保留的东西

硬件校准这一点在 SKILL.md 中被具象化为:"a real clock drifts, a real sensor reads off, a PCA9685 runs a few percent fast. Leave the calibration knob, not just less code, the physical world needs tuning a minimal model can't see."——物理世界需要最小化模型看不到的调参旋钮,所以校准代码不是可以"偷懒省掉"的冗余。

"没有检查的懒代码是半成品"

同一段的后半句是 Ponytail 独特的测试哲学:

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.

任何非平凡逻辑(分支、循环、解析器、涉及资金/安全的路径)必须留下一个可运行的检查——逻辑坏了它就会失败的最小东西:一个基于 assertdemo()/__main__ 自检,或一个小测试文件。明确禁止测试框架和 fixtures;而平凡的一行代码不需要测试,"YAGNI 同样适用于测试本身"。

这条规则把"少写代码"贯彻到了测试层:不建 per-function 的测试套件,但绝不裸奔。它的可验证性由测试基础设施保证——见下文"规则一致性"一节,ONE runnable check 正是被逐字钉死在两个文件里的不变量之一。

自我适用条款:"本文件同样适用于在 ponytail 仓库上干活的 Agent"

AGENTS.md 的最后一行(第 32 行)是全篇最耐人寻味的一笔:

(Yes, this file also applies to agents working on the ponytail repo itself. Especially to them.)

这不只是口号,仓库自身就是这条规则的证据。以 hooks/ponytail-activate.js(Claude Code 的会话启动激活钩子)为例,代码中多处出现规则要求的 ponytail: 上限注释和"最小说明":

// ponytail: install path has shell metacharacters — don't embed it in a
// command snippet; have the agent wire it up by hand instead.

以及多处 // Silent fail — ... 的最短注释——钩子脚本自身的失败被刻意降级为静默("flag is best-effort, don't block the hook"),保证激活逻辑自身永远不会阻塞会话启动。这正是第八条规则(留上限注释)、第四条规则(最少的文件与注释)在自己仓库里的落地。

分发机制:AGENTS.md 如何变成 20 个 Agent 的常驻规则

理解 AGENTS.md 的价值,不能只看它写了什么,还要看它如何被分发和校验。

指令层宿主:零配置生效

docs/agent-portability.md 的适配表中,大量宿主直接以 AGENTS.md 为注入点,属于"零配置"档:

  • Qoder:自动从仓库根加载 AGENTS.md 作为 always-on 上下文;
  • CodeWhale:从项目根读取 AGENTS.md,README 甚至给出最短安装路径——"Copy AGENTS.md to your project, or run codewhale from a checkout of this repo. That's it."
  • Antigravity CLI、Amp(Sourcegraph)、Jules(Google)、Zed、Jules、VS Code + Codex 扩展、JetBrains Junie:均以 AGENTS.md 为项目指令来源(Junie 需在设置中手动指定路径);
  • GitHub Copilot CLI 的指令级回退模式:读取项目内 AGENTS.md.github/copilot-instructions.md

对这类宿主,Ponytail 的安装就退化为一个文件拷贝——这也是 Ponytail 自称"最省事的安装"的技术前提。

规则副本:字节级同步 + 不变量哨兵

对于有独立规则目录的宿主,Ponytail 维护了 7 份紧凑副本,全部要求与 AGENTS.md 逐字节一致。scripts/check-rule-copies.js 是这条约束的执行者,它做两件事:

第一,字节级比对。 脚本把 AGENTS.md 读入后先剥掉末尾那句自我适用条款(因为各平台副本不应包含"本文件也适用于 ponytail 仓库"这种内部声明),再与以下 7 个副本逐一比对,任何漂移都会导致检查失败:

  • .cursor/rules/ponytail.mdc
  • .windsurf/rules/ponytail.md
  • .clinerules/ponytail.md
  • .agents/rules/ponytail.md
  • .qoder/rules/ponytail.md
  • .github/copilot-instructions.md
  • .kiro/steering/ponytail.md

你可以直接打开 .github/copilot-instructions.md 验证:其阶梯、规则、"Not lazy about" 段落与 AGENTS.md 逐字相同。

第二,不变量哨兵(canary)。 由于 skills/ponytail/SKILL.md 是更长的运行时版本,无法做字节比对,脚本改为断言一组关键短语必须同时逐字出现在 SKILL.md 和 AGENTS.md 中:

const INVARIANTS = [
  'in this codebase',                      // 梯级 2:复用已有代码
  'naive heuristic',                       // 上限注释规则
  'ONE runnable check',                    // 测试反射
  'flimsier algorithm',                    // 边界正确性规则
  'input validation at trust boundaries', // 四条"不可懒"安全豁免
  'prevents data loss',
  'security',
  'accessibility',
  'Lazy code without its check is unfinished',
];

脚本注释解释了设计动机:"Changing a rule's wording trips this, which is the reminder to propagate it everywhere"——任何人改了某条规则的措辞而没有同步到全部位置,这个检查就会失败。这等于给规则文本本身做了一套"契约测试":AGENTS.md 的每条 load-bearing 规则都被 pin 住了,防止某次润色悄悄丢掉一条安全豁免。

开发时的验证入口(来自 README.md 的 Development 一节):

node scripts/check-rule-copies.js
npm test

Hooks 兜底:AGENTS.md 文本的第二消费方

hooks/ponytail-instructions.js 中的 getFallbackInstructions() 内置了一份硬编码指令文本,其内容与 AGENTS.md 完全同构(同样的七级阶梯、同样的 bug-fix 原则、同样的 "Not lazy about" 清单)。它的触发路径是:hooks/ponytail-activate.js 在每次会话启动时调用 getPonytailInstructions(mode),优先读取 skills/ponytail/SKILL.md 并按当前强度等级(lite/full/ultra)过滤掉与当前等级无关的表格行和示例(见 hooks/ponytail-instructions.jsfilterSkillBodyForMode);只有当 SKILL.md 读取失败时,才回退到这份与 AGENTS.md 同构的兜底文本。

从源码结构看,这形成了一条"SKILL.md 优先、AGENTS.md 同构文本兜底"的注入链:正常路径下 Agent 收到的是按强度过滤后的完整技能文本;异常路径下也不会静默丢失规则,只是退回紧凑版。

如何在自己的项目中使用这份规则

  1. 指令层复用(最短路径):把 AGENTS.md 复制到你的项目根目录。Qoder、CodeWhale、Antigravity、Amp、Jules、Zed、VS Code 的 Codex 扩展、Copilot CLI 等会直接读取它,零额外配置。
  2. 按平台拷贝对应规则文件:Cursor 用 .cursor/rules/ponytail.mdc,Windsurf 用 .windsurf/rules/ponytail.md,Cline 用 .clinerules/ponytail.md,Kiro 用 .kiro/steering/ponytail.md——这些文件与 AGENTS.md 内容一致,选一个即可。
  3. 插件级安装:支持 Skill 的宿主(Claude Code、Codex、OpenCode、Gemini、pi 等)走插件安装,获得 /ponytail lite|full|ultra|off 强度切换和 hooks 注入(安装步骤见 README.md 的 Install 一节)。
  4. 保持同步的纪律:如果你基于此 fork 规则,修改任何一条规则措辞后,运行 node scripts/check-rule-copies.js && npm test 确认所有副本和不变量仍然通过——这正是 Ponytail 自己维护这份规则的方式。

小结

AGENTS.md 用 30 余行浓缩了一套完整的"最小必要代码"方法论:七级阶梯规定了写代码前的决策顺序(YAGNI → 复用 → 标准库 → 平台原生 → 既有依赖 → 一行 → 最小实现),八条规则封堵了过度工程化的主要入口,而 "Not lazy about" 清单把理解问题、信任边界校验、数据丢失防护、安全、可访问性和硬件校准划为不可谈判的红线,并强制非平凡逻辑留下一个可运行的最小检查。它既是 Qoder、CodeWhale、Amp、Jules 等一大票 Agent 的常驻指令文件,也是 7 份平台规则副本的字节级同步锚点和 hooks 兜底文本的同构来源——一份文件,同时充当了 Ponytail 整个规则分发体系的中枢。

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

项目优选

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