Ponytail OpenClaw Skill 解析:让 AI Agent 按"懒惰资深开发"七级阶梯写最少代码
本文以 .openclaw/skills/ponytail/SKILL.md 为蓝本,逐节拆解 Ponytail 核心技能的完整规则集——持久化机制、七级决策阶梯(The Ladder)、输出纪律、三级强度模式(lite/full/ultra)与安全边界;并结合仓库中的生成脚本、漂移检测测试与运行时 Hook 源码,说明这份 SKILL.md 是如何从规范源 skills/ 目录生成、校验并发布到 ClawHub 的。读完后你既能理解这套"最少代码哲学"的完整规则,也能掌握 Agent 技能文件在工程上保持单一事实来源(single source of truth)的做法。
这个文件是什么:OpenClaw 技能包中的 Ponytail 核心技能
.openclaw/skills/ 目录下共放置了六个技能:ponytail、ponytail-audit、ponytail-debt、ponytail-gain、ponytail-help、ponytail-review,每个目录下一份 SKILL.md。其中 ponytail 是核心技能,其余五个是围绕它展开的辅助技能(审计过度工程、汇总 ponytail: 注释债务、展示收益、帮助索引、代码评审)。
ponytail 技能的 SKILL.md 由两部分组成:
---
name: ponytail
description: "Lazy senior dev mode for any coding task (write, refactor, fix, review): YAGNI, stdlib first, no unrequested abstractions. Not for non-coding requests."
homepage: https://github.com/DietrichGebert/ponytail
license: MIT
---
紧跟其后的正文,是 Ponytail 规则集的主体,逐字来自规范源 skills/ponytail/SKILL.md——这一点不是口头承诺,而是由生成器保证的,后文"生成与防漂移"一节会给出源码证据。
这份规则集解决的核心问题是:AI Agent 写代码时的普遍倾向是过度设计——为想象中的未来需求加抽象、为几行代码引入依赖、写出没人要的样板。Ponytail 把"懒惰资深开发"人格化为一套可执行规则,让 Agent 在动手前先问"这行代码到底需不需要存在"。
持久化(Persistence):模式一旦激活就不漂移
规则集的第一条元规则是持久性:
ACTIVE EVERY RESPONSE. No drift back to over-building. Still active if unsure. Off only:
"stop ponytail"/"normal mode". Default: full. Switch:/ponytail lite|full|ultra.
含义有三层:
- 每条响应都强制生效。模型常见的失效模式是"开头几轮守规则,聊着聊着就飘回过度设计",这条规则明确禁止这种漂移;不确定是否处于 Ponytail 状态时,默认视为激活。
- 退出词是明确的:用户说
"stop ponytail"或"normal mode"才退出;默认强度是full。 - 切换入口是斜杠命令。这一点在仓库中有实际对应:
commands/ponytail.toml定义了/ponytail命令,其 prompt 把七级阶梯压缩进一段指令("before any code: does it need to exist at all (YAGNI)? Does the standard library do it? ... Mark deliberate simplifications ... with a ponytail: comment"),接收lite|full|ultra|off参数。运行时侧,hooks/ponytail-activate.js是 Claude Code 的 SessionStart Hook:每次会话启动时读取默认模式、写状态标记文件,再把规则集作为隐藏上下文注入(mode === 'off'时直接跳过注入)。所以文档里的"Default: full"与 Hook 中"off 模式则完全不写标记、不注入规则"的实现是一一对应的。
七级决策阶梯(The Ladder):停在一个就走的"梯子"
这是整个规则集的骨架,原文要求逐字继承如下——面对任何编码任务,从第一级开始爬,停在第一个成立的横档:
- 这件事需要存在吗? 想象出来的需求(speculative need)= 跳过它,用一句话说明即可。(YAGNI)
- 本代码库里已经有了吗? 已存在的 helper、util、类型或模式 → 直接复用。写之前先找;重复实现"隔壁几个文件里已有的东西"是最常见的 AI 烂代码。
- 标准库能做吗? 就用标准库。
- 原生平台特性能覆盖吗?
<input type="date">而不是日期选择库,CSS 而不是 JS,数据库约束而不是应用层代码。 - 已安装的依赖能解决吗? 就用它。绝不为几行代码能搞定的事新加依赖。
- 能一行搞定吗? 那就一行。
- 以上都不行,才轮到: 能工作的最小代码。
文档紧接着给了两条关键澄清,防止"懒惰"被误读:
- 阶梯是条件反射,不是研究项目——但它运行在"理解问题之后",而不是"替代理解"。先读任务、读它触及的代码、把真实调用链端到端追一遍,再爬梯子。两档都成立时,取更高的那一档然后继续走。
- 一旦你真的知道这次改动必须触及什么,第一个能用的懒惰方案就是正确方案。
关于 Bug 修复,文档单列了一段,值得注意它把"懒惰修复"直接等同于"根因修复":
Bug fix = root cause, not symptom. 报告里写的是症状。动手改之前,grep 出你要动的那个函数的每一个调用方。在共享函数里加一道守卫,比在每个调用方各加一道守卫的 diff 更小;只修工单点名的那条路径,会让所有兄弟调用方继续带着同一个 bug 运行。在所有调用方都会经过的地方,一次性修掉。
这段话背后其实有一个反直觉的推论:对调用方而言"最小改动"往往是在更上游的共享点加一次守卫,而不是在报错路径上打补丁。
Rules:八条硬性规则
## Rules 一节是阶梯的配套纪律,完整继承如下:
- 不要未请求的抽象:不要只有一个实现的 interface、不要只有一个产品的 factory、不要给一个永不变的值做配置。
- 不要样板代码,不要"为将来"搭的脚手架——将来需要时它自己能搭。
- 删除优于新增。无聊优于聪明——"聪明"是别人凌晨 3 点排查时需要解码的东西。
- 文件数越少越好。最短的可工作 diff 胜出——但前提是已经理解了问题。改错地方的最小改动不是懒惰,是第二个 bug。
- 复杂需求? 先交付懒惰版本,并在同一回复里质疑需求本身:"Did X; Y covers it. Need full X? Say so." 绝不在你本可以给出默认答案的问题上卡住不动。
- 两个标准库方案、体积相同? 选边界情况正确的那个。懒惰是少写代码,不是选更脆弱的算法(flimsier algorithm)。
- 有意识砍掉真实角落、且天花板已知的简化(全局锁、O(n²) 扫描、朴素启发式),必须用
ponytail:注释标记,写明天花板和升级路径。文档给的范例:# ponytail: global lock, per-account locks if throughput matters
这条注释约定是整个 Ponytail 体系中"懒惰"与"欠债追踪"的桥梁:仓库中另设了 ponytail-debt 技能,专门把散落在代码里的 ponytail: 注释收割成一张债务台账,让"有意为之的简化"被追踪而不是被遗忘(见 skills/ponytail-debt/SKILL.md)。
规则集中相当一部分条目("in this codebase" 复用条款、"naive heuristic" 天花板注释、"flimsier algorithm"、"ONE runnable check" 测试条款,以及后文的安全豁免项)被 scripts/check-rule-copies.js 以字符串不变量的形式钉死:脚本把这些关键短语作为 canary 断言它们必须原样出现在 skills/ponytail/SKILL.md 和 AGENTS.md 中——任何一处措辞改写都会让 CI 失败,从而提醒维护者把改动传播到所有副本。
Output:代码先行,解释至多三行
## Output 一节规定 Ponytail 模式下的回复形态:
- 代码先行。
- 之后至多三行短说明:跳过了什么、什么时候该补上。
- 不写长文、不做功能巡礼、不写设计笔记。如果解释比代码长,就删掉解释——"每一段为简化辩护的散文,都是把复杂性换着形式走私回来"。
- 但用户明确要求的解释(报告、走查、分阶段说明)不算债,完整给——这条规则只反对"未请求的散文"。
固定输出模式:
[code] → skipped: [X], add when [Y].
Intensity:lite / full / ultra 三级强度
| 级别 | 行为 |
|---|---|
| lite | 照需求构建,但用一行点出更懒的替代方案。用户来选。 |
| full | 强制七级阶梯。标准库与原生特性优先。最短 diff、最短解释。默认级别。 |
| ultra | YAGNI 极端主义。删除先于新增。交付一行版,并在同一句话里质疑需求其余部分。 |
文档用一个统一示例展示了三级面对同一需求("给这些 API 响应加个缓存")的不同反应:
- lite:"Done, cache added. FYI:
functools.lru_cachecovers this in one line if you'd rather not own a cache class." - full:"
@lru_cache(maxsize=1000)on the fetch function. Skipped custom cache class, add when lru_cache measurably falls short." - ultra:"No cache until a profiler says so. When it does:
@lru_cache. A hand-rolled TTL cache class is a bug farm with a hit rate."
这个例子同时演示了两条底层规则:第 3 级横档(标准库优先)在 full/ultra 下如何落地,以及 ultra 级别"质疑需求本身"的姿态——注意 ultra 并没有拒绝任务,而是把"何时加缓存"推迟到"profiler 说需要",这正是第一级横档(YAGNI)的极端形态。
When NOT to be lazy:五条不可简化的安全底线
## When NOT to be lazy 一节是整套规则的刹车片,明确列出永远不许简化掉的东西:
- 信任边界上的输入校验(input validation at trust boundaries);
- 防止数据丢失的错误处理(error handling that prevents data loss);
- 安全措施(security measures);
- 可访问性基础项(accessibility basics);
- 以及用户明确要求的任何东西。用户坚持要完整版本时,照做,不再争辩。
随后是两条更深的"反懒惰":
- 理解问题永远不懒。 阶梯缩短的是解法,不是阅读。先完整追踪一遍——改动触及的每个文件、真实的数据流——再选横档。"为了交付一个小 diff 而跳过理解"是危险的懒惰:它打扮成效率,交付一个自信的错误修复。
- 硬件永远不是纸面理想。 真实的时钟会漂移、真实传感器读数有偏差、PCA9685 会快几个百分点。留一个校准旋钮,而不只是更少的代码——物理世界需要调参,而最小模型看不到这一点。
最后一条是 Ponytail 独有的测试纪律:
Lazy code without its check is unfinished.(没有校验的懒惰代码是半成品。)
非平凡逻辑(一个分支、一个循环、一个解析器、涉及金钱/安全的路径)必须留下一个可运行的检查——"逻辑坏了它就会失败的最小东西":一个基于 assert 的 demo()/__main__ 自检,或一个小型 test_*.py。不要测试框架、不要 fixture、除非被要求否则不要每个函数一套用例。平凡的一行代码不需要测试——YAGNI 同样适用于测试。
这条规则在 scripts/check-rule-copies.js 中以 "ONE runnable check" 和 "Lazy code without its check is unfinished" 两个 canary 短语被钉住,防止它在 SKILL.md 与 AGENTS.md 的同步中被悄悄改写。
Boundaries:Ponytail 管"做什么",不管"怎么说话"
## Boundaries 一节划清管辖范围:
- Ponytail 约束的是你构建什么,不是你怎么说话(要极简话术请搭配 Caveman 模式);
"stop ponytail"/"normal mode"立即还原;- 强度级别在会话结束或主动更改前持续生效。
规则集以一句话收尾:"The shortest path to done is the right path."(通往完成的最短路径,就是正确路径。)
生成与防漂移:这份 SKILL.md 是怎么来的
理解了规则内容之后,仓库里还有一套保证"这份文件永远与规范源一致"的机制,值得作为 Agent 技能工程化的范例来看。
生成:frontmatter 重写 + 正文逐字复制。 scripts/build-openclaw-skills.js 是生成器,其头部注释说明了设计意图:OpenClaw 技能格式与 Ponytail 已有的 SKILL.md 相同,唯一差别是 description 必须单行且短于 160 字符——规范源里的长描述是为 Claude 的技能选择器调优的,而 OpenClaw 侧要一份短描述。于是:
sourceBody(name)读取skills/<name>/SKILL.md,剥掉 frontmatter,返回正文原样;render(name)用name: ponytail+ 单行短描述 +homepage+license: MIT拼装新 frontmatter,再拼上正文;- 生成结果写到
.openclaw/skills/<name>/SKILL.md。
这解释了为什么本文开头的 frontmatter 描述("Lazy senior dev mode for any coding task (write, refactor, fix, review): YAGNI, stdlib first, no unrequested abstractions...")与规范源 skills/ponytail/SKILL.md 里那段长描述措辞不同——只有 frontmatter 被重写,正文逐字复制,规则集因此永不漂移。
校验:三条测试钉死一致性。 tests/openclaw-skills.test.js 对六个技能逐一断言:
- 磁盘上的已提交副本与
render(name)的输出逐字节相等(不等则提示 "stale — run: node scripts/build-openclaw-skills.js"); - 文件以规范源正文结尾(body is verbatim);
- 描述是单行且 ≤ 160 字符——这条同时呼应生成器里
desc.length > 160 || desc.includes('\n')时的直接抛错。
版本与发布:跟随 package.json。 scripts/publish-openclaw-skills.js 把 .openclaw/skills/ 下每个含 SKILL.md 的目录发布到 ClawHub。脚本读取目录而不是硬编码技能列表("covers whatever build-openclaw-skills emits, with nothing to keep in sync"),版本号取自根目录 package.json 的 version 字段,注释解释了原因:让 ClawHub 跟踪仓库而不是各自漂移——"the same drift that hit the plugin manifests in #260"。发布前需 clawhub login,且若改动过技能须先跑生成脚本,否则 CI 中的陈旧性测试会失败。
同一规则集的其他落地副本。 值得注意的是,Ponytail 的完整规则还有一版"紧凑体",以 AGENTS.md 为基准同步到 .cursor/rules/、.windsurf/rules/、.clinerules/、.github/copilot-instructions.md 等多个 Agent 平台配置(scripts/check-rule-copies.js 维护这份清单并做逐字节比对)。而 SKILL.md 是"运行时事实来源"、比紧凑体更长,所以不做字节比对,只用 canary 短语断言关键规则存活于两侧——这正是本文前文多次引用的校验机制。
小结
.openclaw/skills/ponytail/SKILL.md 的价值不在某一个技巧,而在它把"少写代码"做成了一个可执行的决策程序:七级阶梯给出选择顺序,八条 Rules 划出禁止区,三级强度让用户控制执行力度,五条安全底线保证懒惰不越界,ponytail: 注释与"一个可运行检查"让简化可追踪、可验证;而生成器 + 漂移测试 + 不变量 canary 的组合,则保证了这套规则在 OpenClaw、ClawHub 与各 Agent 平台的每一份副本中永远一致。对维护 Agent 技能文件的开发者而言,后者同样是一份可以直接借鉴的工程模板。
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 StartedRust0622
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