一個 coding agent 最貴的預設值,是它以為你要的是程式碼。

你跟它說「加一個日期選擇器」。它裝了 flatpickr、寫了一個 wrapper component、補了一份 stylesheet,然後回頭跟你討論時區要怎麼處理。整個過程它都很努力,也沒有做錯任何一件你交代的事。

ponytail 對同一句話的回答是這樣:

1
2
<!-- ponytail: browser has one -->
<input type="date">

這個 repo 在 2026 年 6 月 12 日建立,到今天 97,239 顆星、5,341 個 fork,MIT 授權。不到兩個月。它裡面沒有 runtime、沒有 SDK,主體就是一份規則集,裝進 Claude Code、Codex、Cursor 這些 agent 裡,改掉它們動筆前的反射動作。

為什麼一份「叫你少寫」的規則會紅

先想清楚 agent 為什麼會走到 404 行那條路。

它不是想炫技。它是在猜你要什麼,而它手上唯一能拿來證明自己有在做事的東西就是輸出。吐 23 行看起來像沒認真看,吐 404 行看起來像把邊界情況都想過了。同一個機制在人身上也成立。你 review PR 的時候,一個 800 行的 PR 讓你覺得作者這週很拚,一個 3 行的 PR 你會多看兩眼問「這樣就夠了嗎」。

所以問題不在模型不夠聰明。問題在沒有人告訴它「停下來」長什麼樣子。

ponytail 給的就是一個停止條件。它把動筆前的決策排成一條階梯,agent 從上往下走,停在第一個成立的那一階:

1
2
3
4
5
6
7
1. 這東西需要存在嗎?   → 不需要就跳過(YAGNI)
2. 這個 codebase 已經有了? → 用現成的,不要重寫
3. stdlib 有嗎? → 用它
4. 平台原生功能有嗎? → 用它
5. 已經裝的依賴解得掉? → 用它
6. 能一行嗎? → 就一行
7. 到這裡才輪到:寫剛好能跑的最小量

第二階是我覺得最實用、也最常被跳過的一階。重新實作一個三個檔案外就有的 helper,是 agent 最常見的浪費,而且它產生的程式碼通常還會通過測試——所以你不會發現。

階梯有個限制條件寫在 AGENTS.md 裡,講得比階梯本身重要:階梯跑在「你已經讀懂問題」之後,不是取代它。原文的說法是「Lazy about the solution, never about reading」。它甚至補了一句:放錯位置的最小改動不叫懶,那叫第二個 bug。

那份數字,跟它被打回來重做的過程

這個 repo 最值得抄的地方,不是它的規則,是它處理自己 benchmark 的方式。

早期版本報「少 80% 到 94% 的程式碼」。做法是給三個模型五個日常任務,每個跑十次,數答案的行數。數字很漂亮,然後 issue #126 指出一件事:裸模型的 baseline 會在答案裡塞散文、塞替代方案、塞注意事項,所以那個差距有一部分只是「對話腔 vs 程式碼」的差別,不是設計帶來的。

作者的處理方式是重做一份,而且把舊的收進折疊區保留,沒有刪掉。

新版改成讓 headless Claude Code session 去真的改一個真的 repo(fastapi/full-stack-fastapi-template,FastAPI + React),十二張 feature 工單,同一個 agent 跑有 skill 和沒 skill 兩組,n=4,Haiku 4.5,用它留下的 git diff 計分。結果是這樣:

對照沒裝 skill 的基準 行數 token 成本 時間 安全
ponytail -54% -22% -20% -27% 100%
caveman(只讓文字變簡潔的對照組) -20% +7% +3% +2% 100%
「YAGNI + 寫一行」的手寫 prompt -33% -14% -21% -30% 95%

54% 是十二個任務的平均。它在 agent 真的會過度建構的地方最猛(日期選擇器 404 行變 23 行,顏色選擇器 287 行變 23 行,因為它去拿原生 <input> 而不是刻一個 component),在程式碼本來就已經很精簡的任務上趨近於零。

從 94% 縮到 54%,還主動說明為什麼縮,這件事比 94% 本身有說服力。

它也誠實寫了自己什麼時候會反過來

省 token 這件事有個前提:模型要照階梯走,而不是坐在那裡斟酌自己該停在第幾階。

README 直接寫了反例:一個簡潔的推理模型如果把 thinking token 花在推敲那七階上,成本和延遲會往反方向跑,「在 GPT-5.5 上就是這樣」。

這句話對我來說比那張表有用。它把這個工具的適用邊界標出來了:ponytail 省的是「少寫」,不是「少想」,所以它在傾向多寫的模型上收益最大,在本來就話少、但會為選擇糾結的模型上可能倒賠。

真正的設計重點在「不准省」那份清單

如果 ponytail 只是「叫 agent 寫少一點」,上面那張表裡的第三列就夠用了——自己寫一句 prompt,說 YAGNI,說盡量一行。它的行數也少了 33%,token 和時間甚至跟 ponytail 差不多。

差別在最後一欄。那組的安全性掉到 95%,ponytail 是 100%。

意思是那句手寫 prompt 在對抗測試裡漏掉了一道防護。這是「少」這個目標本身帶的副作用:你叫模型追求短,它會從最容易砍的地方開始砍,而輸入驗證、錯誤處理、權限檢查剛好就是那種砍掉之後功能照樣跑、測試照樣綠的東西。

ponytail 的規則裡有一份明確的禁區,寫在 SKILL.md 的「When NOT to be lazy」:信任邊界上的輸入驗證、防止資料遺失的錯誤處理、安全措施、無障礙基本要求、以及使用者明確要求的東西,一律不准簡化。加上一條:理解問題本身永遠不能偷懶。

所以這份規則真正在做的事情,是把「精簡」跟「省事」拆開。前者是刻意的取捨,後者是沒看完就動手。一個只寫「少寫程式」的 prompt 沒辦法區分這兩件事,因為在字面上它們產生的 diff 都很小。

兩個我打算抄進自己流程的設計

第一個是 ponytail: 註解。當它刻意做了一個有已知天花板的簡化(全域鎖、O(n²) 掃描、粗糙的啟發式),它要留一行註解,寫清楚天花板在哪、以後怎麼升級。像這樣:

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

這解掉一個很煩的問題:三個月後你看到那把全域鎖,分不出來是當初想清楚才這樣選,還是隨手寫的。註解裡的「升級路徑」把這個判斷寫在現場了。

第二個是 /ponytail-debt。它把對話過程中被推遲的簡化收進一份帳本,讓「等一下再做」有個地方可以查。另外幾個指令是 /ponytail-review(在你的 diff 裡找可以刪的東西)、/ponytail-audit(掃整個 repo 的過度設計,不只 diff)、/ponytail-gain(顯示實測影響)。強度分 lite、full、ultra 三檔,預設 full;ultra 的定位它自己寫得很好笑,「for when the codebase has wronged you personally」。

裝法在 Claude Code 是兩行:

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

Cursor、Windsurf、Cline、Copilot 這類只吃規則檔的工具沒有指令,但可以直接把對應的規則檔複製過去,repo 裡每家一份。

誠實講一句:我還沒把它放進日常流程,上面所有數字都是它 benchmark 目錄裡的結果加上我讀規則檔的判斷,不是我自己跑出來的。它給的重製指令是 npx promptfoo eval -c benchmarks/promptfooconfig.yaml(舊版單次生成那組),agentic 那組的方法和逐任務表格在 benchmarks/results/2026-06-18-agentic.md

帶走的框架

寫規則給 agent 的時候,「少一點」是個很糟的目標,因為它沒有停止條件,模型只能猜你覺得夠少了沒有。

有用的規則長成兩半:一條有順序的階梯讓它知道什麼時候可以停手,一份禁區清單讓它知道停手的時候不能順便丟掉什麼。ponytail 的階梯有七階、禁區有六項,比例大概就是這樣。

你自己的 CLAUDE.mdAGENTS.md 裡,那兩半齊了嗎?我回去翻了自己的,階梯有,禁區只寫了一半。


來源DietrichGebert/ponytail(README、AGENTS.md、skills/ponytail/SKILL.md,2026-08-06 讀取)。Repo 數據取自 GitHub API:97,239 stars、5,341 forks、建立於 2026-06-12、最後推送 2026-07-15。benchmark 數據取自 repo 內 benchmarks/results/2026-06-18-agentic.md 的摘要表。