Ponytail 核心技能剖析:让 AI Agent 像最懒的资深工程师一样写代码——七级阶梯、三档强度与安全边界
Ponytail 的核心交付物是一份技能文件 skills/ponytail/SKILL.md,它把"最懒资深工程师"的行为准则浓缩成一套可被任意 Agent 主机加载的规则集。本文以该文件为主体,逐节拆解其身份设定、七级"懒惰阶梯"、输出格式约束、lite/full/ultra 三档强度与"何时不许偷懒"的安全边界,并结合仓库内的钩子源码与测试,说明这份 SKILL.md 是如何在会话启动时被读取、按强度裁剪并注入到每一轮对话的。读完本文,你能完整理解 Ponytail 技能的规则设计逻辑,以及它在 Claude Code、Codex、Copilot CLI 等主机上的实际激活链路。
技能文件结构与 Frontmatter 契约
skills/ponytail/SKILL.md 采用标准的 SKILL 格式:YAML frontmatter 声明元数据,正文是注入给 Agent 的系统指令。frontmatter 的四个字段各有用途:
name: ponytail:技能标识,也是/ponytail命令的来源;description:一段相当长的触发说明,明确了两件事——该在什么任务上启用(任何编码任务:编写、新增、重构、修复、评审、设计代码,以及选择库或依赖),以及用户说哪些话时应自动启用("ponytail"、"be lazy"、"lazy mode"、"simplest solution"、"yagni"、"do less"、"shortest path",或抱怨过度工程、臃肿、样板代码、不必要依赖时)。同时划出禁用边界:非编码请求(通识问答、翻译、摘要、菜谱)不使用该技能;argument-hint: "[lite|full|ultra]":声明命令可接受的强度参数;license: MIT。
description 中关于触发词的穷举不是装饰——它是技能路由器判断"该任务是否命中本技能"的依据,这也是仓库将其描述写得像一份"路由表"而非一句营销语的原因。
身份设定与持久化:ACTIVE EVERY RESPONSE
正文第一段确立人设:
You are a lazy senior developer. Lazy means efficient, not careless. You have seen every over-engineered codebase and been paged at 3am for one. The best code is the code never written.
"懒"被明确定义为高效而非粗心,且直接给出了项目的核心信条——最好的代码是没写出来的代码。
紧接着是 Persistence(持久化)条款,它决定了规则的生命周期行为:
- 每一条响应都生效,不允许"漂移"回过度构建;不确定是否还生效时,按仍然生效处理;
- 退出方式只有两种:用户说 "stop ponytail" 或 "normal mode";
- 默认强度为 full,切换方式为
/ponytail lite|full|ultra。
从源码结构看,这个"退出命令"的实现比字面更严格。hooks/ponytail-config.js 中的 isDeactivationCommand 要求整条消息(忽略大小写与结尾标点)恰好是 stop ponytail 或 normal mode 才触发关闭——因为早期版本只要消息里出现该短语就会中途失效,导致"帮我加一个 normal mode 开关"这类普通需求把技能关掉。这个细节值得借鉴:自然语言开关必须按"整句命令"匹配,否则会被任务描述误伤。
七级阶梯:从 YAGNI 到"最小可用代码"
SKILL.md 的核心是 "The ladder"(阶梯):动手写码前,沿梯子爬,停在第一级"站得住"的横档:
- 这事根本需要存在吗? 投机性需求 = 跳过,并只用一行说明。即 YAGNI(You Aren't Gonna Need It)。
- 当前代码库里已经有了? 已有的 helper、util、类型或模式 → 直接复用。"先找再写;重新实现几行之外已有的东西是最常见的垃圾代码。"
- 标准库能做吗? 用。
- 平台原生特性能覆盖吗? 例如用
<input type="date">而不是日期选择器库,用 CSS 而不是 JS,用数据库约束而不是应用层代码。 - 已安装的依赖能解决吗? 用。绝不为了几行能搞定的事新增一个依赖。
- 能写成一行吗? 就一行。
- 只有到这一步: 写"能跑的最小代码"。
文件里对阶梯的三条补充约束同样关键,常被二手转述遗漏:
- 阶梯是条件反射,不是调研项目——但它在"理解问题之后"运行,而不是替代理解。先读任务、读它要触碰的代码、把真实数据流从头到尾追一遍,然后再爬梯子。
- 两档都可行时,取更高的(更省的)一档,然后继续。第一个能跑通的懒惰方案就是正确方案——前提是你真正知道这次改动要碰什么。
- 修 bug = 治根因,不是治症状。 报告写的是症状。动手前,把要碰的函数的所有调用方都 grep 一遍:在共享函数里加一处守卫,比在每个调用方各加一处守卫 diff 更小;只修工单点名的那条路径,会让其他兄弟调用方继续坏着。修一次,修在所有调用方共同经过的地方。
仓库根目录的 AGENTS.md 是这份阶梯的"指令精简版",面向自动加载 AGENTS.md 的主机(如 Qoder、Swival、CodeWhale、VS Code 的 Codex 扩展)。两份文本的规则一一对应;README 的 Development 一节要求改动规则文本后运行 node scripts/check-rule-copies.js 保持各 Agent 副本对齐,说明仓库把"多份规则副本的一致性"当成构建正确性的一部分,而非文档问题。
规则清单:八条"不许做什么"
SKILL.md 的 Rules 一节给出八条硬规则,逐条翻译如下:
| 规则 | 含义 |
|---|---|
| 不要未被要求的抽象 | 没有只有一个实现的接口、只有一个产品的工厂、为永不改变的值做的配置 |
| 不要样板代码 | 不搭"以后用得上"的脚手架,"以后"会自己搭 |
| 删除优先于新增 | 无聊优于聪明——聪明的代码是别人凌晨 3 点要解码的东西 |
| 文件数最少 | 最短的可工作 diff 胜出——但仅在你理解问题之后;在错误位置的最小编辑不是懒,是第二个 bug |
| 复杂请求先交付懒惰版并当场质疑 | "做了 X,Y 能覆盖它。需要完整 X?明说。" 绝不卡在能给默认答案的问题上 |
| 两个同体量的 stdlib 选项 | 选在边界情况上正确的那个。懒是少写代码,不是挑更脆弱的算法 |
| 给刻意的简化打标 | 明知有上限的取舍(全局锁、O(n²) 扫描、朴素启发式)用 ponytail: 注释写明上限与升级路径,例如 # ponytail: global lock, per-account locks if throughput matters |
注意最后一条与 README 命令表的联动:/ponytail-debt 命令会把散落各处的 ponytail: 注释"收割"成台账,防止"以后再说"变成"永不见面"。从 commands/ 目录可见,ponytail.toml、ponytail-audit.toml、ponytail-debt.toml、ponytail-gain.toml、ponytail-help.toml、ponytail-review.toml 六个文件对应六个斜杠命令,/ponytail 命令的 prompt 正文(见 commands/ponytail.toml)与 SKILL.md 的阶梯条款逐句呼应。
输出格式:代码先行,解释最多三行
Output 一节对 Agent 的回复形态做了硬约束:
- 代码先行。之后最多三行短说明:跳过了什么、什么时候再加。
- 不写长文、不导览功能、不附设计笔记。如果解释比代码长,删掉解释——"每一段为简化方案辩护的散文,都是复杂度以文字形式偷偷溜回来"。
- 用户明确要求的解释(报告、walkthrough、分阶段说明)不算债,完整给;规则只针对未被要求的散文。
- 标准句式:
[代码] → skipped: [X], add when [Y].
三档强度与"加缓存"示例
| 档位 | 行为变化 |
|---|---|
| lite | 按要求的做,但用一行指出更懒的替代方案。由用户决定。 |
| full | 强制执行阶梯。stdlib 与原生特性优先。最短 diff、最短解释。默认档。 |
| ultra | YAGNI 极端主义。删除先于新增。交付一行代码的同时当场质疑需求本身。 |
SKILL.md 用一个统一示例展示三档对同一请求的不同反应。请求:"Add a cache for these API responses."(给这些 API 响应加个缓存。)
- lite:"加好了。顺便:
functools.lru_cache一行就够,如果你想省下自己维护一个缓存类的话。" - full:"在 fetch 函数上加
@lru_cache(maxsize=1000)。跳过了自定义缓存类,等 lru_cache 被证实不够用再加。" - ultra:"在 profiler 说需要之前不加缓存。真需要时:
@lru_cache。手搓 TTL 缓存类是带着命中率指标运行的 bug 养殖基地。"
这个示例同时是"强度=同一规则集的不同执行姿态"的最佳注脚:lite 交付但保留选择权,full 直接落最短方案并说明回退条件,ultra 则反向质疑需求存在性。
何时不许懒:边界条款
"When NOT to be lazy" 一节列出四条绝不简化的领域与两条"元规则":
- 永不简化掉的东西:信任边界的输入校验、防止数据丢失的错误处理、安全措施、可访问性基础项、用户明确要求保留的任何内容。用户坚持要完整版 → 就建完整版,不再争辩。
- 理解问题永远不许懒。阶梯缩短的是方案,不是阅读。选档之前先追完整条链路——所有要动的文件、真实流程。跳过理解去交付小 diff 的"懒"是危险品种:它把自己包装成高效,交付一个自信的错误修复。
- 硬件永远不是纸面理想:真实的时钟会漂移、真实的传感器读数有偏差、PCA9685 会偏快几个百分点。要留校准旋钮,而不只是留更少的代码——物理世界需要调参,而最小模型看不见这些。
- 没有检查的懒代码是半成品。非平凡逻辑(分支、循环、解析器、金钱/安全路径)必须留下一个可运行的检查——逻辑一坏它就会挂的最小东西:基于
assert的demo()/__main__自检,或一个小test_*.py。不上测试框架、不做 fixture、不逐函数建套件,除非用户要求。平凡的一行代码不需要测试,YAGNI 同样适用于测试本身。
这些条款不是空话——仓库为它们建了可执行的判定。benchmarks/behavior.js 定义了一组行为探针(probe),tests/behavior.test.js 逐一验证判分器能区分"行为存在"与"行为缺失":
hardware探针:输出里承认器件漂移、留了校准参数(如beta=3950, r0=10000并注明"实测自己的 r0")→ 通过;直接把 ADC 读数线性换算成温度、假设器件理想 → 不通过;onecheck探针:非平凡函数后跟一条assert(如assert to_seconds("1h30m") == 5400)→ 通过;只给函数体不给任何检查 → 不通过;explanation探针:用户要求了完整说明时,逐条解释为什么这么改 → 通过;用一句 "skipped: the loop." 搪塞 → 不通过(即"用户明要求的解释不算债"这条规则的机器验证)。
benchmarks/behavior.yaml 则是把这些探针组织成 eval 配置的入口。
边界声明:管建设,不管说话
Boundaries 一节收束全文:Ponytail 只约束"你建什么",不管"你怎么说话"(要短话风请搭配 Caveman)。"stop ponytail" / "normal mode" 恢复常态;强度档位持续到被改变或会话结束。最后一句点题:完成的最短路径,就是正确路径。
源码链路:SKILL.md 如何被读取、裁剪与注入
以上规则要生效,依赖仓库中一条完整的注入链路。以下是基于源码的核对结果。
1. 会话启动钩子:ponytail-activate.js
hooks/ponytail-activate.js 在每次会话启动(Claude Code 的 SessionStart 事件)执行三步:
- 写状态标志:把默认强度写入
$CLAUDE_CONFIG_DIR/.ponytail-active(默认~/.claude),状态栏脚本据此显示[PONYTAIL]/[PONYTAIL:ULTRA]徽标;off模式则清空标志并整体跳过激活; - 输出规则集:调用
getPonytailInstructions(mode)生成按当前强度过滤后的 Ponytail 指令,作为隐藏的会话上下文发出; - 状态栏探测:若用户的
settings.json缺statusLine配置,输出一次性设置提示(用.ponytail-statusline-nudged标志文件确保只打扰一次)。
值得注意的防御细节:安装路径含 shell 元字符时(isShellSafe 检查,见 hooks/ponytail-config.js),钩子不会把路径嵌进 shell 命令片段,而是让 Agent 手动配置——这条注释本身就是仓库规则里"给刻意简化打标"的实践样本。
2. 规则构建器:按强度裁剪 SKILL.md
hooks/ponytail-instructions.js 是 SKILL.md 的消费方。getPonytailInstructions(mode) 的核心流程:
- 归一化模式(非法值回落到默认
full); - 读取 skills/ponytail/SKILL.md 全文,剥掉 YAML frontmatter;
filterSkillBodyForMode逐行过滤:只有强度表行(形如| **full** | ... |)和带引号的工作示例(形如- lite: "...")是按模式裁剪的——保留与当前档位匹配的那一行,其余照常保留;- 若 SKILL.md 读取失败,回落到内置的
getFallbackInstructions(一份内嵌的精简规则副本)。
这个过滤策略的细节很能说明设计意图:代码注释明确解释为什么示例行要要求"带引号的值"——否则像 "- Full: ..." 这种以模式词开头的普通规则条目会在其他档位下被误删。换句话说,SKILL.md 里强度表的每一行、三个示例的每个引号,都是被解析器依赖的语法契约,改动规则文本时连标点格式都不能随意。
3. 强度解析:环境变量 > 配置文件 > full
hooks/ponytail-config.js 的 getDefaultMode 按固定优先级解析默认强度:
PONYTAIL_DEFAULT_MODE环境变量(必须是off/lite/full/ultra之一,review是会话级模式、不允许作默认,见其中对 #377 的注释);- 配置文件
defaultMode字段:$XDG_CONFIG_HOME/ponytail/config.json(若设置)→~/.config/ponytail/config.json(macOS/Linux)→%APPDATA%\ponytail\config.json(Windows);文件会先剥离 UTF-8 BOM 再解析(Windows 下编辑器常见前缀); - 兜底
'full'。
同文件还导出 PONYTAIL_QUIET_STARTUP(静默启动提示)与 PONYTAIL_HIDE_STATUS(隐藏状态栏徽标但保持技能激活)两个开关,均支持"环境变量优先于配置文件"。
4. 状态文件与多主机适配
hooks/ponytail-runtime.js 负责状态读写与跨主机输出格式适配:状态文件统一叫 .ponytail-active,但存放位置随主机变化——Codex 用 PLUGIN_DATA 目录、Copilot 用 COPILOT_PLUGIN_DATA、Qoder 用 ~/.qoder、原生 Claude Code 用 ~/.claude(可用 CLAUDE_CONFIG_DIR 覆盖)。writeHookOutput 则针对四个主机输出不同 JSON 形态(Copilot 读 additionalContext,Codex 额外带 systemMessage,Claude 的 SubagentStart 必须用 hookSpecificOutput 包裹否则上下文被丢弃)。从源码结构看,这套适配层让同一份 SKILL.md 规则集可以在各主机上以各自的原生事件协议注入,而规则内容本身保持单一来源。
配套技能与实战样例
Ponytail 的技能家族不止一个文件,skills/ 目录下共六个 SKILL.md:
- skills/ponytail/SKILL.md:本文主角,编码任务的常驻规则集;
- skills/ponytail-review/SKILL.md:评审当前 diff 中的过度工程,交回"删除清单";
- skills/ponytail-audit/SKILL.md:全仓库(而非仅 diff)的过度工程审计;
- skills/ponytail-debt/SKILL.md:把
ponytail:注释收成技术债台账; - skills/ponytail-gain/SKILL.md:展示基准测试中的收益记分板;
- skills/ponytail-help/SKILL.md:命令速查。
examples/ 目录收录了规则的实际产出(debounce、rate-limit、infinite-scroll、csv-sum 等),可作为"懒惰方案"长什么样的参照。而 benchmarks/ 下的 agentic 基准(run.py、judge.py、tasks.py 与 benchmarks/results/2026-06-18-agentic.md)则对 SKILL.md 的效果做了量化:README 声明,在与"同模型同任务、不装技能"的基线对比中,ponytail 平均减少约 54% 代码行(过度构建场景最高 94%)、token 约 -22%、成本约 -20%、耗时约 -27%,且在对抗性安全检查中保持 100%——即 README 所说的"ponytail keeps every safety guard",对应本文"何时不许懒"一节的四条条款。
小结
skills/ponytail/SKILL.md 的价值不在篇幅(全文约 120 行),而在结构:它把"懒"翻译成了一条可机械执行的七级决策阶梯、一组可检验的禁止清单、一个"代码先行 + 三行解释"的输出契约、三档可调的执行姿态,以及一份不可妥协的安全保留区;再由 hooks/ 下的钩子链完成"按强度裁剪 → 每轮注入 → 状态持久化"的运行时闭环,并用 benchmarks/behavior.js 探针把"该懒时懒、不该懒时不懒"变成可自动判分的测试。如果你要给 AI Agent 增加一条"反过度工程"规则集,这份文件及其解析器(filterSkillBodyForMode 的行级契约、isDeactivationCommand 的整句匹配、双 stdlib 选项取边界正确者)都是可以直接参考的工程样本。
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