公司里那个一言不发的马尾辫大叔,现在被装进了你的 AI agent 里

公司里那个一言不发的马尾辫大叔,现在被装进了你的 AI agent 里

原文:DietrichGebert/ponytail


1. 前言:那个扎马尾辫的男人

每个有点年头的公司里都有这么一个人。

后脑勺一束花白的马尾辫,鼻梁上架副椭圆眼镜,工龄比版本控制系统还长。他平时不太说话,午饭一个人坐窗边吃。新人兴冲冲拉着他 review 自己刚写的五十行精巧代码,他看一眼,沉默两秒,伸手在键盘上敲了一行——跑通了。然后起身去倒水,什么都没解释。

He says nothing. He writes one line. It works.

(他不说话。他写一行。它能跑。)

GitHub 上最近爆火的一个项目 ponytail(马尾辫),名字就是这么来的——把这位神秘大叔做成了一个 AI agent 插件。一个月之内冲到 55.1k stars,Trendshift 日榜周榜挂着不下来,定位也很骚:它不是又一个 agent 框架,也不是又一个 IDE 插件,而是给你的 AI agent 强行塞进去一个”扎马尾辫的资深工程师人格”

ponytail logo

为啥这玩意儿一夜爆火?

因为现在用 Claude Code、Cursor、Copilot 的人都被同一个问题折磨:AI agent 写代码默认就是过度工程化。你让它”写个日期选择器”,它给你装 flatpickr、写 wrapper 组件、配样式表、还要和你讨论时区——五十行起步。其实浏览器自带一个 <input type="date"> 就完事了。能写一个 class 绝不写一个函数,能引入一个新依赖绝不翻 stdlib——这帮 agent 训练语料里塞满了 over-engineered 的”最佳实践”,所以默认行为就是把简单问题搞复杂。

而马尾辫大叔的存在意义就是治这个病。他不会教你架构,他只会沉默地把你那五十行换成一行。

今天想和大家聊聊这个项目:它为什么火、效果到底有多猛、以及——重点——它的实现到底有什么巧妙之处。读完你会发现,ponytail 真正有意思的不是那段”一行胜过五十行”的口号,而是它通过一组 hook 把这位大叔的人格持久化注入到 agent 每一次会话里的工程实现。


2. Ponytail 是个啥

简单粗暴一句话:ponytail 是一个跨平台的 agent skill/plugin,强行让 AI agent 走”懒人路径”写代码

支持的平台离谱地多,目前覆盖 Claude Code、Codex、GitHub Copilot CLI、Cursor、Windsurf、Cline、OpenCode、Gemini CLI、Aider、Kiro、Zed、CodeWhale、Swival、OpenClaw、Antigravity CLI、Pi agent harness 等 14+ 个主流 agent 宿主。在 Claude Code 里装它就一行:

/plugin marketplace add DietrichGebert/ponytail
/plugin install ponytail@ponytail

装完之后,每一次 session 启动它都会向 agent 注入一份精心设计的 ruleset,让 agent 在写任何代码之前先在心里走一遍它定义的”七阶梯(the ladder)”:

1. 这玩意儿真的需要存在吗?             → 不需要就跳过 (YAGNI)
2. 当前代码库里已经有了吗?             → 有就复用,别重写
3. 标准库能做吗?                       → 能就用
4. 平台原生特性能搞定吗?               → 能就用
5. 已经装了的依赖里有现成的吗?         → 有就用
6. 能写成一行吗?                       → 一行
7. 实在不行:写满足需求的最小代码

整套思路就是奥卡姆剃刀在工程实践上的极端化版本:最好的代码是你没写的代码

它还提供了几个不同”强度”档位:

  • lite:温和版,正常实现需求,但会顺便提一句”其实有更懒的写法”
  • full(默认):严格执行 ladder
  • ultra:YAGNI 极端主义者,能删就删,先质疑需求合不合理再写
  • off:关闭

以及一组配套的 slash 命令:/ponytail-review(审计当前 diff 里的过度工程)、/ponytail-audit(审计整个 repo)、/ponytail-debt(追踪你延后掉的简化项)、/ponytail-gain(看影响指标)。


3. 看一下效果,吸引你继续读下去

光说不练假把式。作者用 Claude Code 在一个真实的开源项目(tiangolo 的 full-stack-fastapi-template,FastAPI + React 的全栈模板)上跑了 12 个真实 feature ticket,每个任务做 4 次取均值,模型用 Haiku 4.5。对比对象包括”不开 skill 的 baseline”、ponytail、以及两个其他 prompt-engineering 流派(caveman 和 “YAGNI + one-liners” prompt)。

结果如下图,ponytail 是唯一在每一个指标上都压过 baseline、并且 100% 保持安全检查的方案

ponytail vs baseline agentic 评测

数字层面:

vs no-skill baseline LOC tokens cost time safe
ponytail -54% -22% -20% -27% 100%
caveman(terse prose 对照组) -20% +7% +3% +2% 100%
“YAGNI + one-liners” prompt -33% -14% -21% -30% 95%

注意第二、第三行:caveman 这种只是让模型说话更简洁的 prompt,tokens 和 cost 反而涨了——因为模型话少了,但行为没变,反复试错反而更贵。”YAGNI + one-liner” 这种激进 prompt 虽然便宜,但安全检查掉了 5%——这就是为啥 ponytail 在 README 里反复强调 “lazy means efficient, not careless”,它的 ruleset 里专门有”绝对不能省”的章节(输入校验、错误处理、安全、可访问性)。

最戏剧化的案例是 README 里那个 日期选择器:从 404 行被砍到 23 行。砍法不是用更短的 JS,而是直接换成浏览器原生 <input type="date">,这就是 ladder 第 4 级”原生平台特性”的胜利。

之前还有一个旧版的 single-shot benchmark(一次性生成场景),跨三个模型对比,结论是 80-94% 的 LOC 削减——不过作者也很诚实地在 README 里说,这个数字”夸大了”,因为 baseline 是裸模型,会自带很多 prose 解释,所以差距被放大了。新的 agentic benchmark 才是更公允的对比。

single-shot 跨模型对照

到这里你可能会想:不就是一段写得很好的 prompt 吗?为啥还能搞成 5w 星的项目?

接下来我们就钻进它的代码里,看看它到底是怎么做的。


4. 源码深扒:ponytail 到底怎么工作的

我去看完整个 repo 的代码(其实也不多,加起来千把行 JS),最让我眼前一亮的不是那段七阶梯的 prompt 本身——那段 prompt 任何人都能写——而是它把这段 prompt 可靠地、持久地、按需地塞进 agent 每一次会话的工程实现。

整个机制可以拆成三层:Hook 注册层 → Hook 执行层 → 配置/模式持久层。我们一层一层看。

4.1 第一层:Hook 注册——告诉 Claude Code 在什么时候触发我

Ponytail 整个 plugin 的”入口”是 hooks/claude-codex-hooks.json,注册了三个 hook:

{
  "hooks": {
    "SessionStart": [{
      "matcher": "startup|resume|clear|compact",
      "hooks": [{
        "type": "command",
        "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/ponytail-activate.js\"; exit 0",
        "timeout": 5,
        "statusMessage": "Loading ponytail mode..."
      }]
    }],
    "SubagentStart": [{
      "hooks": [{ "type": "command", "command": "node ...ponytail-subagent.js" }]
    }],
    "UserPromptSubmit": [{
      "hooks": [{ "type": "command", "command": "node ...ponytail-mode-tracker.js" }]
    }]
  }
}

三个 hook 各管一摊:

  • SessionStart:会话启动(包括新开、resume、clear、compact 后)时跑——负责把 ruleset 注入到 agent 的初始上下文里。
  • SubagentStart:subagent 启动时跑——保证你 spawn 的子 agent 也继承 ponytail 模式(这点很重要,后面讲)。
  • UserPromptSubmit:用户每次回车提交 prompt 时跑——用来监听用户是不是输入了 /ponytail ultra 这种切换命令。

关键 insight:Claude Code 的 hooks 机制本质就是它在特定时机会调用你的脚本,并允许你的脚本通过 stdout 向 agent 的上下文里塞东西。Ponytail 把这个机制用到了极致——它不是”传统插件”那种修改 UI 或者加新 tool,而是用 hook 在每一次推理之前往上下文里偷偷加一段 system message。这其实是个非常薄但非常聪明的杠杆。

4.2 第二层:SessionStart 干了什么

会话启动时跑的是 hooks/ponytail-activate.js,核心逻辑精简下来是这样:

// hooks/ponytail-activate.js(精简版)
const { getDefaultMode } = require('./ponytail-config');
const { getPonytailInstructions } = require('./ponytail-instructions');
const { setMode, writeHookOutput } = require('./ponytail-runtime');

const mode = getDefaultMode();    // 读取当前模式

if (mode === 'off') {
  clearMode();
  process.exit(0);                // off 模式直接跳过
}

setMode(mode);                    // 把当前模式写到状态文件

// 关键一步:把 ruleset 写到 stdout,Claude Code 会把它注入上下文
let output = getPonytailInstructions(mode);
writeHookOutput('SessionStart', mode, output);

整个文件就干三件事:

  1. 读当前模式fullliteultra 还是 off
  2. 写状态文件:把当前模式持久化到 ~/.claude/.ponytail-active,statusline 那个角标会读它
  3. 生成 ruleset 并通过 stdout 喷出去:Claude Code 见到 stdout 输出就会把它作为额外 context 塞给 agent

第三步是整个机制的核心。你不需要修改 Claude Code 本身,你只需要让你的脚本输出一段文字——这段文字就会作为隐藏的 SessionStart context 出现在 agent 看到的 prompt 里。

4.3 第三层:ruleset 是怎么按 mode 过滤的

getPonytailInstructions(mode) 这个函数才是 prompt 工程的精华。它做的事情是:skills/ponytail/SKILL.md 这份完整的规则文档,按当前 mode 把多余的部分剔掉

源码(精简后):

// hooks/ponytail-instructions.js(精简版)
function filterSkillBodyForMode(body, mode) {
  const effective = normalizeMode(mode) || DEFAULT_MODE;
  return body
    .replace(/^---[\s\S]*?---\s*/, '')   // 去 frontmatter
    .split(/\r?\n/)
    .filter(line => {
      // 表格行:| **lite** | ... | 这种,只保留当前 mode 那一行
      const m1 = line.match(/^\|\s*\*\*(.+?)\*\*\s*\|/);
      if (m1) {
        const labelMode = normalizeMode(m1[1].trim());
        if (labelMode) return labelMode === effective;
      }
      // 示例行:"- lite: 'Done, cache added. FYI...'" 同理
      const m2 = line.match(/^-\s*([^:]+):\s*/);
      if (m2) {
        const labelMode = normalizeMode(m2[1].trim());
        if (labelMode) return labelMode === effective;
      }
      return true;
    })
    .join('\n');
}

function getPonytailInstructions(mode) {
  try {
    const skill = fs.readFileSync(SKILL_PATH, 'utf8');
    return 'PONYTAIL MODE ACTIVE — level: ' + mode + '\n\n' +
           filterSkillBodyForMode(skill, mode);
  } catch (e) {
    return getFallbackInstructions(mode);   // 兜底:硬编码版
  }
}

短短二十几行,做了一件很聪明的事:把”通用规则”和”mode-specific 规则”放在同一份 SKILL.md 里维护,渲染的时候按 mode 过滤多余内容。这样 prompt token 不浪费,三个模式之间的差异也容易 review。

比如 SKILL.md 里有这么一段表格:

| Level | What change |
|-------|------------|
| **lite**  | Build what's asked, but name the lazier alternative.
| **full**  | The ladder enforced. Stdlib and native first.
| **ultra** | YAGNI extremist. Deletion before addition.

如果当前是 full,过滤完只剩 full 那一行;其他 mode-specific 的解释也被剔掉。配合那段 fallback——万一 SKILL.md 文件读不到(比如装出问题了),还有一份硬编码的 instructions 兜底,保证 hook 不会因为文件 IO 失败而瘫掉。这是工程上很务实的设计,作者明显跑过线上场景,知道一定会有奇奇怪怪的安装环境。

4.4 第四层:UserPromptSubmit 怎么追踪模式切换

用户输入 /ponytail ultra 时是谁负责切换的?是 ponytail-mode-tracker.js,它注册在 UserPromptSubmit 这个 hook 上——也就是说,每次你按回车之前,这个脚本都会跑一次,检查你输入的内容。

精简后的源码:

// hooks/ponytail-mode-tracker.js(精简版)
let input = '';
process.stdin.on('data', chunk => { input += chunk; });
process.stdin.on('end', () => {
  const data = JSON.parse(input);
  const prompt = (data.prompt || '').trim().toLowerCase();

  // 1. 匹配 /ponytail 类命令
  if (/^[/@$]ponytail/.test(prompt)) {
    const [cmd, arg] = prompt.split(/\s+/);
    let mode = null;
    if (cmd.endsWith('ponytail-review')) mode = 'review';
    else if (cmd.endsWith('ponytail')) {
      if (['lite','full','ultra','off'].includes(arg)) mode = arg;
      else mode = getDefaultMode();
    }
    if (mode && mode !== 'off') {
      setMode(mode);
      writeHookOutput('UserPromptSubmit', mode,
        'PONYTAIL MODE CHANGED — level: ' + mode);
    } else if (mode === 'off') {
      clearMode();
    }
  }

  // 2. 自然语言关闭:识别 "stop ponytail" / "normal mode"
  if (isDeactivationCommand(prompt)) {
    clearMode();
    writeHookOutput('UserPromptSubmit', 'off', 'PONYTAIL MODE OFF');
  }
});

注意第二个判断的实现细节——在 ponytail-config.js 里:

// 早期实现只用 includes("stop ponytail") 匹配,结果出过 bug:
// 用户说 "add a normal mode toggle",包含 "normal mode" 子串,
// 就把 ponytail 关掉了。修复方式是要求整条 prompt 严格等于命令。
function isDeactivationCommand(text) {
  const t = String(text || '').trim().toLowerCase().replace(/[.!?\s]+$/, '');
  return t === 'stop ponytail' || t === 'normal mode';
}

代码里的注释就是这个 bug 的”案发现场”——作者踩过坑,所以现在的实现是完整匹配 + 去掉尾部标点,避免在普通对话里误伤。这种小地方反映了项目的工程成熟度,比那段 prompt 本身更有学习价值

4.5 第五层:配置解析的优先级

ponytail-config.js 里负责”我现在该用什么模式”的判断,优先级很清晰:

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' (硬编码默认)

跨平台、可覆盖、有默认——这套设计就是标准的 12-factor 思路。再加一个小细节,它用了一个 isShellSafe() 函数防止把含特殊字符的路径直接拼进 shell 命令:

function isShellSafe(p) {
  return typeof p === 'string' && /^[A-Za-z0-9 _.\-:/\\~]+$/.test(p);
}

注释里特别说:”An allowlist beats escaping every shell’s metacharacters“——白名单优于对每种 shell 都做转义,因为转义规则太多易错。这种小决策又一次反映了作者经验:在安全和便利之间,宁可保守拒绝处理也不要写一个错误的转义器

4.6 串起来:为什么这套机制有效

整个 ponytail 的工程实现,本质上是用 hook 把一段精心设计的 prompt 绑在每一次 agent 推理之前。它有效的原因可以拆成三点:

第一,持久性。普通的 system prompt 注入只在会话开始时生效,但 ponytail 通过 SessionStart + SubagentStart + UserPromptSubmit 三个 hook 形成一个”全包围”——新会话、子 agent、每次切换模式,ruleset 都会被重新写入。SKILL.md 里那句 “ACTIVE EVERY RESPONSE. No drift back to over-building.” 不是说说而已,是有工程兜底的。

第二,可调档lite/full/ultra 三档不是噱头,而是真的对应三种不同的注入内容。作者明白一刀切的 prompt 会让某些场景下 agent 太过保守——所以用过滤器在同一份 SKILL.md 里维护三个变体,按需注入。

第三,可关闭+可观测。一句自然语言 “stop ponytail” 就能关,statusline 上能看到当前 mode([PONYTAIL][PONYTAIL:ULTRA]),用户始终知道自己在哪个状态。这一点对 agent 类工具尤其重要——用户对”AI 后台行为不可见”非常敏感,可观测性能极大降低焦虑。


5. 为什么这套 prompt 真的有效

代码层面讲清楚了,回到更上层的问题:为什么这段 prompt 真的能让模型行为变化这么大

我自己做 LLM 推理优化,对模型怎么”听话”是有些观察的。Ponytail 这套 prompt 的有效性,我觉得主要来自三个设计:

第一,它给了一个明确的决策树,而不是抽象指令

很多人写 prompt 喜欢用 “be concise”、”avoid over-engineering” 这种笼统词,模型会理解但很难落实。Ponytail 的 ladder 是一个可枚举、可验证、有顺序的判断流程——”先看 stdlib,再看 native,再看依赖,再看一行解决”。这对 LLM 来说接近一个算法描述,比抽象指令好执行得多。本质上还是把”判断”具体化成”步骤”。

第二,它显式划定了”不能省”的领域

如果你只告诉模型”写最少的代码”,模型确实会照做,但代价就是 benchmark 表里 “YAGNI + one-liners” prompt 那一行——safe 掉到 95%。Ponytail 专门有 “When NOT to be lazy” 章节明确列出输入校验、错误处理、安全、可访问性、硬件校准这些不能动的东西。这个”边界”是它能保持 100% safety 的关键。

第三,它要求模型把”简化”显式标注出来

SKILL.md 里有一条规则我特别欣赏:

Mark deliberate simplifications with a ponytail: comment… Shortcut with a known ceiling? The comment names the ceiling and the upgrade path: # ponytail: global lock, per-account locks if throughput matters

这其实是把模型的”偷懒决策”变成了代码里的可审计痕迹。后面 /ponytail-debt 命令就是去 grep 这些注释,做成一份”延后债务清单”。这就把”偷懒”从一个不可控的行为变成了一个可追踪的工程实践。说人话就是:你可以偷懒,但你得留个证据,方便以后回来还债。

把这三点合起来看,ponytail 实际上不是在写一个 prompt,而是在写一个微型的”代码评审 SOP”。它把一个资深工程师审 code 时的判断过程拆解、形式化、塞进 agent 上下文里。这就是为什么它比单纯 “be concise” 这种 prompt 有效得多——它把隐性的工程审美变成了显式的可执行流程。


6. 我的 take:ponytail 火背后的一些观察

最后说点个人私货。

首先,ponytail 火的根本原因,不是它的 prompt 写得多好,而是它精准戳中了当前 AI 编码工具的一个普遍痛点:模型默认会过度工程化。这个问题 Cursor 用户、Claude Code 用户、Copilot 用户都在抱怨,但之前没人把”反过度工程”做成一个标准化、跨平台、可装可卸的产品。ponytail 把行业心照不宣的”最佳实践”产品化了,这本身就是一个被严重低估的机会

其次,从工程实现角度,ponytail 给了我一个启示:agent 时代的 plugin 不一定要做 tool

我们看到的大部分 agent plugin(MCP server、tool 注入)都是在给 agent 加新能力。但 ponytail 走的是另一条路——它不给 agent 加任何新能力,而是修剪 agent 的默认行为。这种”减法插件”在 agent 生态里是个新方向,门槛更低,普适性更强。任何能用 hook 注入 prompt 的 agent 宿主都可以装它,所以它能轻松扩展到 14+ 个平台。

第三,它的 benchmark 设计本身值得学习

之前那个 single-shot benchmark 报了 80-94% 的削减,结果作者在 issue #126 被人指出 “你这个 baseline 不公平,因为裸模型会自带 prose”。作者没死扛——直接承认问题,重新设计 agentic benchmark,公开旧数据但标注 “这是单次生成的天花板,不是均值”。这种 benchmark 透明度在开源社区其实不多见,很多项目被指出问题第一反应是删帖或者无视。这种实事求是的态度大概也是它能上 Trendshift 周榜的原因之一——technical community 是闻得出味儿的。

第四,从我的研究方向(LLM 推理优化)来看,ponytail 还有一个被忽略的价值:省 token 就是省钱、省时间、省碳排

benchmark 里 -22% tokens、-20% cost、-27% time 这几个数字看着不起眼,但你乘上一个公司每天的 agent 调用量,这就是真金白银。我们这帮做推理优化的天天卷 KV cache、卷 batching、卷 quantization,结果在 prompt engineering 这一层一段 ruleset 就能砍 20%+——这告诉我们效率优化不止在 kernel level,应用层有时候收益更猛。这也是整个行业需要重新评估的核心矛盾:底层优化的边际收益递减,而上层 prompt/agent 行为的优化还有大量未挖掘的空间


7. 最后

ponytail 这个项目,技术上不复杂,千把行 JS + 一份精心设计的 SKILL.md。但它把一个”看起来人人都能写的 prompt”做成了一个跨 14+ 平台、有完整工程实现、可调档可关闭可观测、还有公开 benchmark 的产品。这个从”能写”到”做出来还能用”的差距,就是真本事

装一下试试,看你的 agent 会不会从此沉默寡言,扎起马尾辫(笑)。

/plugin marketplace add DietrichGebert/ponytail
/plugin install ponytail@ponytail

repo:https://github.com/DietrichGebert/ponytail

欢迎评论区交流你装上以后的体验,特别是它在你常用的 agent 上有没有翻车。