首页
/ Ponytail 规则文件实战:写给 Windsurf 的七级"懒惰高级工程师"决策阶梯与一致性保障机制

Ponytail 规则文件实战:写给 Windsurf 的七级"懒惰高级工程师"决策阶梯与一致性保障机制

2026-09-05 19:04:51作者:曹令琨Iris

本文围绕 Ponytail 仓库中面向 Windsurf 的规则文件 .windsurf/rules/ponytail.md 展开。该文件是整个 Ponytail 项目"懒惰高级工程师"(lazy senior dev)行为准则在 Windsurf 这一 Agent 宿主上的落地副本:它以一份紧凑的纯文本规则集约束 AI 编码助手"先想清楚要不要写、能不能复用、能不能一行解决,最后才写最少的代码"。读完后,你将掌握这套七级决策阶梯(ladder)的完整规则内容、它在 Ponytail 多宿主分发体系中的定位,以及仓库如何用一个脚本强制所有宿主的规则副本与权威版本逐字对齐的机制。

文件定位:Ponytail 多宿主分发体系中的"指令层"适配器

Ponytail 的设计是"技能为核心,宿主文件为适配器":核心行为存放在 skills/ 目录下,各宿主专属文件只是让行为在对应 Agent 中容易被加载的薄适配层。从 docs/agent-portability.md 的适配器表可以看到,Windsurf 对应的就是 .windsurf/rules/ponytail.md,备注为 "Project rule"(项目规则)——属于指令层(instruction-tier):它只提供常驻的 always-on 规则文本,不带 /ponytail 命令切换、不带生命周期 hooks。

与 Claude Code、Codex 等"完整插件层"宿主不同,在 Windsurf 中启用 Ponytail 的方式极其简单:把 .windsurf/rules/ponytail.md 复制到目标项目的 .windsurf/rules/ 目录即可,Windsurf 会自动将其作为项目规则加载。README.md 的安装章节明确列出了 Cursor、Windsurf、Cline、GitHub Copilot 编辑器插件、Aider、Kiro、Zed 等指令层宿主,做法一致:从仓库复制对应的规则文件到项目的规则目录。这意味着本文讨论的规则文件同时是 Ponytail 的权威规则正文——仓库中其他所有宿主的紧凑规则副本都必须与它(经由 AGENTS.md)保持逐字一致,下文会展开这一机制。

规则全文精读:七级阶梯

规则文件开头一句话定调:"You are a lazy senior developer. Lazy means efficient, not careless. The best code is the code never written."(你是懒惰的高级开发者。懒惰意味着高效而非粗枝大叶。最好的代码是根本没写的代码。)

紧接着是全文件最核心的部分——七级决策阶梯。规则要求 Agent 在写任何代码之前,逐级检查并停在第一个成立的台阶(rung)上

  1. 这件事根本需要构建吗?(YAGNI,You Aren't Gonna Need It)——推测性的需求直接跳过;
  2. 这个代码库里已经存在吗?——复用已有的 helper、util 或模式,而不是重写。这是 Agent 最常见的"垃圾产出"来源:重新实现几个文件之外就有的东西;
  3. 标准库能做吗?——直接用;
  4. 平台原生能力能覆盖吗?——用原生特性(如 <input type="date"> 优于第三方日期组件、CSS 优于 JS、数据库约束优于应用层代码);
  5. 已安装的依赖能解决吗?——用它,绝不为了几行代码能搞定的事新增依赖;
  6. 能写成一行吗?——那就写成一行;
  7. 以上都不行时:才写"能工作的最小代码"。

阶梯之后紧跟一条关键限定,它防止"懒惰"被误解为"不读代码就动手":

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. (阶梯在你理解问题之后运行,而不是替代理解:先读任务和它触及的代码,端到端追踪真实流程,然后再爬阶梯。)

也就是说,规则强制的顺序是:先完整理解(读任务、读被触及的代码、追踪真实调用链),然后才允许"偷懒"。这是整套规则中最容易被 Agent 违背、也最容易被人类误解的一条——"小 diff"不等于"偷懒",不理解问题就提交的小改动只是"伪装成效率的懒惰"。

规则精读: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.

要点拆解:

  • 报告里写的是症状,不是病根。修 bug 前先 grep 出你即将触碰的函数的所有调用方
  • 在共享函数上修一次。在共享函数里加一个守卫(guard)的 diff,比在每个调用方各加一个守卫更小——这恰好同时满足"根因修复"和"最短 diff"两个目标;
  • 只补丁工单点名的那条路径是错的:它会让其他调用同一函数的 sibling 调用方继续处于损坏状态。

这条规则与阶梯第 2 级(复用代码库已有的东西)在精神上完全一致:代码库里已经存在的那个共享函数,就是唯一应该被修改的地方。

规则精读:八条硬性禁令

规则文件的 Rules: 部分列出了八条不带例外的硬性约束,逐条说明:

规则 含义
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 删除优先于新增;乏味优先于巧妙(巧妙是凌晨 3 点别人要解码的东西);文件数最少化
Shortest working diff wins, but only once you understand the problem 最短的可用 diff 获胜——但前提是你已经理解问题。在错误位置做最小改动不是懒,而是制造第二个 bug
Question complex requests 对复杂需求要反问:"你真的需要 X 吗,还是 Y 就能覆盖?"
Pick the edge-case-correct option when two stdlib approaches are the same size 两个标准库方案代码量相同时,选边界情况正确的那个。懒意味着代码更少,不是选更脆弱的算法
Mark deliberate simplifications ... with a ponytail: comment 对有意为之、且砍掉了真实拐角的简化(有已知上限的:全局锁、O(n²) 扫描、朴素启发式),必须留一条 ponytail: 注释,写明上限和升级路径

最后一条是整个体系里最精巧的设计:它允许"故意偷懒",但要求偷懒留下可追踪的标记。注释格式约定为 ponytail: <上限>, <升级路径>,例如 # ponytail: global lock, per-account locks if throughput matters。这些标记不是死代码注释,而是被配套的 /ponytail-debt 技能消费的活数据:skills/ponytail-debt/SKILL.md 描述了如何用 grep -rnE '(#|//) ?ponytail:' . 扫描全仓库,把每个标记收割成一行"债务账本"(ceiling 和 upgrade 直接从注释里取),并给没有写明触发条件的标记打上 no-trigger 腐化风险标签——让"以后再说"不会静默变成"永远不做"。

规则精读:绝不偷懒的清单与"一个可运行检查"

规则文件的最后一段定义了懒惰的禁区,这一段的措辞在仓库所有规则副本中都被逐字锁定(见下文一致性机制):

这些方面绝不懒

  • 理解问题——完整读完任务、追踪真实流程后再选台阶。一个你都不理解的小 diff,只是"穿着效率外衣的懒惰";
  • 信任边界处的输入校验(input validation at trust boundaries);
  • 防止数据丢失的错误处理(error handling that prevents data loss);
  • 安全(security);
  • 可访问性(accessibility);
  • 真实硬件需要的校准——平台永远不是规格书上的理想值:时钟会漂移、传感器读数有偏差。要留下校准旋钮,而不只是"更少的代码",因为物理世界需要最小模型看不见的调校;
  • 用户明确要求的任何内容——用户坚持要完整版本,就按要求构建,不再争辩。

然后是被称为"测试反射"(test reflex)的规则:

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 的 demo/自检,或一个小的测试文件。不用框架、不用 fixture。而平凡的一行代码不需要测试——YAGNI 对测试本身同样适用。

这形成了一条完整的自洽闭环:规则既禁止过度工程,又用"安全禁区 + 一个可运行检查"封死了"偷懒偷出缺陷"的下限。

源码纵深:规则副本的一致性是怎么被脚本强制的

Windsurf 规则文件AGENTS.md 的正文逐字相同(AGENTS.md 仅多一句括号结尾:"this file also applies to agents working on the ponytail repo itself")。这不是手工维护的巧合,而是 scripts/check-rule-copies.js 强制保证的。该脚本的机制值得任何维护多宿主规则文件的团队参考:

  1. 以 AGENTS.md 为权威版本(canonical),去掉其独有的括号尾注后,与 7 个紧凑副本逐一做全文字节级比对,其中就包括 .windsurf/rules/ponytail.md(第 21 行),其余为 .cursor/rules/ponytail.mdc.clinerules/ponytail.md.agents/rules/ponytail.md.qoder/rules/ponytail.md.github/copilot-instructions.md.kiro/steering/ponytail.md(部分副本需先剥离 frontmatter)。任一副本漂移即打印 drifted from AGENTS.md 并以非零码退出;

  2. 对 SKILL.md 做"金丝雀"不变量检查skills/ponytail/SKILL.md 是运行时行为的事实来源,篇幅比紧凑正文长,无法字节比对,因此脚本改为断言一组承载规则的关键短语INVARIANTS 数组)在 SKILL.md 和 AGENTS.md 中同时存在,包括:

    • in this codebase(阶梯第 2 级"复用已有代码");
    • naive heuristic(上限注释规则);
    • ONE runnable check(测试反射);
    • flimsier algorithm("不选更脆弱算法"规则);
    • 四条安全禁区短语:input validation at trust boundariesprevents data losssecurityaccessibility
    • Lazy code without its check is unfinished("没有检查的懒代码是半成品")。

    任何一处措辞改写都会触发失败,提醒维护者把改动传播到所有副本。

这解释了 README.md "Development" 章节中"改动紧凑规则文本后必须运行 node scripts/check-rule-copies.jsnpm test"的要求。对读者而言,它还有一个直接推论:你从 .windsurf/rules/ponytail.md 读到的每一条规则,与 Claude Code 插件、Codex 插件、Cursor 规则里生效的规则是同一份文本,不存在"宿主 A 的规则比宿主 B 少一条"的分叉。

规则生效后的实际效果:从基准示例看

这套规则跑起来是什么样子?仓库 examples/ 目录保存了基准测试中的逐字模型输出,两个典型:

  • CSV 求和examples/csv-sum.md):任务"读取 sales.csv 并对 amount 列求和"。无技能组给出 20 行 pandas 方案外加"备选方案"和推荐说明;Ponytail 组 3 行——sum(float(row['amount']) for row in csv.DictReader(open('sales.csv'))),并附一句 skipped 说明(跳过了 pandas 和错误处理,"当 CSV 变大、格式异常或需要更多分析时再补")。这正对应阶梯第 3 级(标准库 csv 已覆盖)。
  • 搜索输入防抖examples/debounce.md):无技能组 116 行,含基础版、带 loading 状态版、带 cancel/immediate 选项的"高级版"、HTML/CSS 示例和收益表格;Ponytail 组 10 行——setTimeout + clearTimeout 就是防抖本身,skipped 说明写道:"Add a utility when you need it on 3+ inputs"(当需要在 3 个以上输入框复用时再抽工具函数)。这对应阶梯第 6 级与"不要未要求的抽象"。

两个示例还统一演示了规则规定的输出格式(完整版见 skills/ponytail/SKILL.md 的 Output 一节):先代码,然后至多三行短说明:跳过了什么、什么时候再补回来

在 Windsurf 中的使用与边界

启用方式:将 .windsurf/rules/ponytail.md 复制到你的项目 .windsurf/rules/ 目录下,Windsurf 加载项目时即自动注入,无需其他配置。

需要明确的边界(均来自 docs/agent-portability.mdREADME.md):

  • Windsurf 属于指令层宿主:只获得这份 always-on 规则文本,没有 /ponytail lite|full|ultra 强度切换、没有 ponytail: 债务收割等六个配套命令(/ponytail/ponytail-review/ponytail-audit/ponytail-debt/ponytail-gain/ponytail-help 只存在于具备技能能力的宿主,如 Claude Code、Codex、Devin CLI、OpenCode、Gemini、pi、Swival、Hermes、Qoder);
  • 规则文本本身不依赖任何平台能力——它是一段纯指令,因此同样的文件可以直接给 Cline(.clinerules/)、Cursor(.cursor/rules/)等宿主复用;
  • 卸载即删除复制的规则文件,无残留状态(残留状态清理只针对装了 hooks 的插件层宿主)。

小结

.windsurf/rules/ponytail.md 是一份不到 30 行、却能完整表达 Ponytail 全部核心行为的规则文件,其技术价值在于三点:

  1. 决策阶梯把"代码越少越好"从口号变成了可执行的检查序列——七个问题按成本从低到高排列,停在第一个成立的台阶,避免了"先写全量代码再裁剪"的常见 Agent 行为模式;
  2. 懒惰有明确的禁区与下限——信任边界校验、数据安全、安全、可访问性、硬件校准永不简化,非平凡逻辑必须留下一个可运行的检查,"故意偷懒"必须用 ponytail: 注释登记上限与升级路径,形成可被 /ponytail-debt 收割的债务账本;
  3. 多宿主分发的一致性由脚本而非纪律保障——scripts/check-rule-copies.js 的全文比对加关键短语不变量断言,确保 Windsurf 上的规则与所有其他宿主逐字同源。

对使用者的直接建议:把它放进项目 .windsurf/rules/ 后,你不需要改变任何工作流;规则中"理解问题在先、偷懒在后"的顺序保证它削减的是冗余代码而非正确性。

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