unlazy 評測:用 GATES.md 把「做完了」變成可執行的驗收條件
Anti-laziness skill for AI agents. Core: the Depth Tree method, which splits a task N layers deep and gives every leaf the full time budget of the whole task, so effort multiplies with depth. Grounded in 2025-2026 research on model laziness, underthinking and premature completion.
秒懂
- 它是什麼?
- unlazy 是給 AI agent 用的完成度紀律工具,核心是把驗收條件寫成可執行的 gate 並用 gate-check.mjs 逐一跑過。它的價值不在提示詞技巧,而在把「自稱完成」換成退出碼與輸出比對,代價是你要先寫出夠好的 oracle。
- 適合誰用?
- 如果你的 agent 任務有可寫成命令的驗收條件,例如跑測試腳本、檢查產物內容、量測某個數字,unlazy 值得裝進 ~/.claude/skills/unlazy 或 ~/.codex/skills/unlazy 試一輪,先從 templates/gates-leaf.md 複製一份 GATES.md,用 node scripts/gate-check.mjs --status GATES.md 確認解析結果,再決定是否 --approve。若你的任務驗收主要靠人眼判斷、或執行環境裡根本沒有可用的檢查工具鏈,這套 gate 只會變成形式主義,不要用。
- 可以商用嗎?
- 可以。MIT 是寬鬆授權:你可以使用、修改並販售以它為基礎的軟體,只需保留著作權與授權聲明。
- 還在維護嗎?
- 有在維護。儲存庫最近一次提交在 13 天前。
- 用什麼語言寫的?
- 主要是 JavaScript(依據 GitHub 的語言統計)。
以上回答依據專案的 GitHub 資料(最近同步於 2026年9月15日)與我們的分析,不構成法律意見。
開源專案深度解析
unlazy 想修的是「提早宣布完成」這個毛病
AI agent 做長任務時最常見的失敗不是寫不出程式碼,而是寫到一半就說完成了。README 把這個問題描述為 completion discipline,並宣稱背後有 2025 至 2026 年關於 model laziness、underthinking 與 premature completion 的研究支撐。研究細節不在這份材料裡,我無法核實它引用了哪些論文,也無法判斷那些研究的結論是否真的支持它的設計。這是這篇文章要說清楚的第一件事:unlazy 的技術主張可以從程式碼與文件驗證,它的學術背書不行。
它針對的使用者是已經在用 Claude Code 或 Codex CLI 跑實質工程任務的人。任務規模要夠大,大到「跑個測試就知道有沒有壞」這種直覺不夠用。README 的觸發範例是一行 `/unlazy tree 5 refactor the payment module and verify every migration path`,tree 後面接的數字代表拆解深度,數字越大代表把任務切得越細,每個葉節點都拿到整份任務的時間預算。這是 Depth Tree 方法的操作定義,文件沒有給出深度與實際耗時的對應關係,也沒有說明什麼深度算合理,只給了一個可調的參數。
對小型任務來說,寫 GATES.md 的成本高於收益。你為一個改三行設定檔的任務寫一份 gate 帳本,檢查器的解析開銷加上審批流程,比直接人工確認慢得多。這個工具的前提是任務本身值得被驗證,而不是任務本身很簡單。
GATES.md 的 CHECK、EXPECT、CWD 三件套
gate 帳本是一份 Markdown 檔案,結構是清單項目加上縮排的鍵值對。README 給的範例裡,G1 的 CHECK 是 `node scripts/verify-pricing.mjs`,EXPECT 是一行成功訊息,EVIDENCE 初始為 pending。G2 多了 CWD,指向 packages/checkout。
判定規則很硬:一個可執行的 gate 只有在行程退出碼為 0,而且 EXPECT 字串出現在合併輸出中時才算通過。兩個條件缺一不可。這代表你的驗證腳本必須在成功時印出一段可辨識的字串,失敗時要嘛非零退出,要嘛不印那段字串。這個設計把「驗證邏輯」和「驗證判定」分開:驗證邏輯寫在 Node 腳本裡,判定交給 gate-check.mjs。
輸出有 1 MiB 的上限,而且限制同時套用在捕獲的 stdout/stderr 內容,以及 EXPECT 比對與指紋計算所用的 UTF-8 合併字串。README 明確寫道,檢查器不會把過大的比對字串截斷成成功。這是防止「輸出太長所以只比對開頭」這類漏洞的設計,但也意味著如果你的驗證腳本會吐出大量日誌,你得自己想辦法在腳本裡把輸出收斂到成功標記附近。
自動證據的格式是:先放一段帶版本資訊的完整 SHA-256 摘要,涵蓋解析後的 CHECK、EXPECT 與原始 CWD 定義,然後才是退出碼與成功輸出的指紋,最後是截斷過的環境細節。README 對這套機制的定位說得很直白:它偵測的是結構漂移,不是帳本竄改。任何人只要改得動帳本,就能偽造看起來像樣的證據。這段話值得記住,它同時是這個工具的能力邊界。
gate-check.mjs 的四種執行模式與它們的差別
安裝用 skills CLI:`npx skills add Leonxlnx/unlazy`,加 `-g` 裝在使用者層級,加 `--all` 裝到所有偵測到的 agent。手動路徑是 `~/.claude/skills/unlazy` 與 `~/.codex/skills/unlazy`。呼叫方式依 agent 而異,Claude Code 用 `/unlazy`,Codex 用 `$unlazy`,或者靠技能描述觸發。
檢查器有四種模式,差別在於會不會真的執行 shell。`--status` 是唯一保證不執行的模式,而且 README 特別強調「唯一」這兩個字。它會解析帳本並偵測定義漂移,但不解析 shell、不跑檢查。
不帶參數的正常模式在新 oracle 上、還沒有精確審批記錄時,會印出解析後的命令、期望、工作目錄、shell 與 PATH,然後停在那裡不執行。這很容易被誤讀成永久的 dry run。README 直接警告:一旦那個 oracle 被審批過,正常模式就會執行它。這個警告很重要,因為它意味著同一條命令在審批前後的行為不同。
`--approve` 是審批並執行整本帳本。文件要求你在批准之前讀過每一條命令與被呼叫的腳本。`--reverify` 會重跑所有可執行 gate,包括已經標記完成的那些。父層驗證用的就是這個模式,因為舊證據不等於重新執行。
還有一個輔助工具 `scripts/gate-lint.mjs`,用於抓出機械上偏弱的帳本寫法,加 `--strict` 時警告會直接判定失敗。它是非執行、建議性質的。
shell 與 PATH:Windows 上最容易踩的坑
shell 的解析順序是:命令列 `--shell` 優先,其次是環境變數 `UNLAZY_SHELL`,最後是 Node 的平台預設值。Unix 上是 `/bin/sh`,Windows 上是 `process.env.ComSpec` 加上平台後備。檢查會繼承啟動環境,包含 PATH。
README 點出的具體情境是:從 Git Bash 啟動的檢查器可能看得到 Unix 風格工具,但從 PowerShell 啟動的同一個檢查器看不到。`--shell` 換的是解譯器,不會幫你裝 grep、tail、tr 或其他外部程式。文件建議可攜的範例改呼叫 repository 自己擁有的 Node 腳本,這個建議很實際,因為它把外部工具鏈的依賴降到最低。
還有一條容易被忽略的規則:父層重新驗證應該使用相同的宣告 shell 與必要工具鏈。shell 或 PATH 不一致被視為驗證失敗,必須解決,而不是當成通過的證據。這條規則把環境本身納入驗證範圍,代價是跨機器重現時要更小心。
審批是同意,不是沙箱
審批記錄預設放在 `~/.unlazy/approved`。可以用 `UNLAZY_APPROVAL_DIR` 換到別的目錄,但有兩個硬條件:必須是擁有者私有、必須是真實目錄,而且正規化後的目標必須留在被檢查的 repository 之外。符號連結的存放區、被連結或替換的記錄、非私有的記錄,都會 fail closed。
每筆記錄綁定的東西相當細:絕對路徑的帳本與 gate、精確的 CHECK 與 EXPECT、解析後的 CWD 與 shell、逾時、輸出與正則上限、正則 worker 上限、平台,以及完整的繼承 PATH。任何一項被改動,就要重新審批。
README 對這套機制的定位同樣直白:審批是同意,不是沙箱。而且審批不會雜湊被呼叫的腳本、fixture、依賴或其他遞移輸入。`--status` 與 Stop 會驗證記錄下來的定義綁定,但不會檢查那些產物。這是一個明確的缺口:如果你的驗證腳本本身被改過,而 CHECK 那一行沒變,審批記錄不會發現。文件給的補救方式是重新檢查變更過的依賴並執行 `--reverify`,以及參考 SECURITY.md 裡針對使用者自訂依賴身分的有界摘要模式。
Stop 的行為也值得一提。合法的 abandonment 被視為終端交接而不是成功,檢查器會以退出碼 1 結束並印出 HANDOFF REQUIRED,Stop 允許離開但會回報被標記的 id。這表示放棄是被支援的,但必須留下理由與 gate id,否則解析器會直接拒絕。
好 gate 的判準,以及它不適合的任務
README 列了幾條寫好 gate 的原則:讀取結果所指向的產物或服務;在所有斷言通過後才印出成功專用標記;用已知的正向控制來測缺席檢查;量測被提供的數字而不是把它複製進 EXPECT;對有後果的人工結果,用與風險相稱的證據來審查。
最後一條最容易被忽略。工具支援人工 gate,既有的人工證據格式也保持相容。但人工 gate 的證據品質完全取決於寫的人,檢查器無法替你判斷。如果你的任務驗收主要靠主觀判斷,例如「這段文案讀起來對不對」,gate 能做的只是記錄你聲稱檢查過了,這跟沒有檢查差別不大。
檢查器能證明的只有你宣告的那個命令 oracle。README 用一句話點破:它無法推斷一個英文標題和一段任意 shell 程式碼是同一件事。所以 G1 寫「pricing fixtures render the expected tiers」,而 CHECK 跑的是 `node scripts/verify-pricing.mjs`,這兩者之間的對應關係是人的責任,不是工具的能力。
什麼情況下不該用?驗收條件寫不成命令的時候。或者執行環境裡沒有可用的工具鏈、而你又不想為此寫 repository 專屬的 Node 腳本的時候。還有一種情況:任務短到寫帳本比做事還久,這時候 Depth Tree 的拆解與 gate 的審批流程都是純開銷。
版本狀態與維護成本
目前原始碼指向 2.1.0,README 明確說它「在這裡不被標示為已打標籤的 GitHub release」。CHANGELOG.md 裡是未發布的變更集。要可重現的安裝就得鎖定特定 commit。這對需要審計的團隊是實質限制:你沒辦法用版本號溝通你裝的是哪一版。
依賴面很窄。核心是 SKILL.md,檢查器與選用 hook 需要 Node 16 或以上,不使用任何第三方執行期套件。這表示升級的風險主要來自你自己的 gate 定義,而不是上游依賴樹。反過來說,當檢查器的判定規則改變,你的帳本可能需要重寫,而因為沒有 tagged release,你很難從版本號判斷這種變更發生了沒有。
授權是 MIT。這對商業使用與修改都相對寬鬆,但授權不會替你解決審批記錄的保管問題。審批記錄綁定了 PATH、shell、平台與逾時,這意味著把它們簽進版本控制再跨機器共用,大概率會因為 PATH 不同而全部失效。比較合理的做法是每台機器各自審批,代價是團隊成員要各自讀過每一條 CHECK 命令。
還有一個維護面的細節:`--reverify` 會重跑已完成的 gate,這是刻意的設計,因為舊證據不等於重新執行。在 CI 或交付前把這個模式接進流程,會讓每次驗證的耗時等於全部 gate 的總和。任務越大、gate 越多,這個成本越明顯。
跟直接寫測試的差別在哪裡
最直接的替代方案是專案自己的測試套件,例如 pytest、Jest 或 Go 的 testing 套件。差別在於驗證的對象。測試套件驗證的是程式行為,它假設你已經知道要測什麼,而且測試是隨程式碼一起演進的長期資產。unlazy 的 gate 驗證的是「這次任務聲稱做到的事」,它是一份跟著任務走的臨時契約,任務結束後帳本的價值就大幅下降。
第二個差別是執行者。測試套件由開發者或 CI 執行,unlazy 的 gate 由 agent 在任務流程中執行,而且審批記錄綁定了具體的命令、PATH 與平台。這讓 gate 更適合「agent 說它做完了,我要一個獨立於它的判定」這個場景,而不適合當成回歸測試的替代品。
第三個差別是失敗的處理方式。測試失敗就是紅燈。gate 的失敗有兩種:檢查真的沒過,或者證據被判定為 stale。後者包括缺少證據、只有普通散文、legacy 格式、格式錯誤,或定義不匹配。把 stale 跟失敗分開,是為了讓「沒跑過」不要混進「跑過了但沒過」。這個區分在人工 gate 上尤其明顯,因為人工 gate 的證據本來就不是機器產生的。
如果你的團隊已經有成熟的測試套件,unlazy 的定位應該是在既有測試之上補一層任務層級的驗收,而不是取代它。把既有的測試命令直接寫進 CHECK 是可行的,前提是那個命令會印出可辨識的成功標記,而且輸出不會超過 1 MiB。
編輯結論
如果你的 agent 任務有可寫成命令的驗收條件,例如跑測試腳本、檢查產物內容、量測某個數字,unlazy 值得裝進 ~/.claude/skills/unlazy 或 ~/.codex/skills/unlazy 試一輪,先從 templates/gates-leaf.md 複製一份 GATES.md,用 node scripts/gate-check.mjs --status GATES.md 確認解析結果,再決定是否 --approve。若你的任務驗收主要靠人眼判斷、或執行環境裡根本沒有可用的檢查工具鏈,這套 gate 只會變成形式主義,不要用。導入前務必確認三件事:你的 agent 是否支援 skills CLI、Node 是否為 16 以上、以及審批目錄能否落在被檢查的 repository 之外。
社群筆記