在前面幾天,我把我的 Code Review Skill 全部拆解,同時也把內部流程分享給大家。今天,我們要將過去幾天寫的內容當成素材,交由 LLM 幫我們建構出整個 nathan-code-review 的 skill!
這次我會使用 Claude Code。我的建議是:雖然我們會儘量把 Skill 寫成 AI Agent Agnostic,讓它能在不同的 AI Agent 間通用,但 自己還是比較懂自己。未來打算用哪套 Harness/AI Agent 與 Skill 互動,就先用那套工具建構。
我想要建構一個符合我習慣與判斷基準的 Code Review Skill,它的名稱叫做 nathan-code-review。
觸發情境(description 必須涵蓋):使用者貼入 GitLab MR URL、要求 Code Review/審查變更/review、指定檔案或 branch 要求檢查程式碼。
以下我會提供我目前的構想、規劃、流程與預計要使用到的工具,請你綜合 /skill-creator:skill-creator、/mattpocock-skills:writing-for-agents,以及官方 Agent Skills best practices(https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices,請先閱讀)三者的最佳實踐來撰寫這套 Skill。
硬性要求:
1. Skill 內容以英文(en)撰寫;與使用者交互、報告生成一律繁體中文(zh-TW),
但技術術語(Critical / Suggestion / Nit、工具名、檔案路徑)保留英文。
2. SKILL.md 保持精簡(觸發判定+流程骨架),九面向細則、GitLab API 參考、
報告 JSON 格式等放 references/ 下按需載入。
3. 所有外部工具(trivy、opengrep、ruff 等)都要定義「工具不存在時」的分支:跳過該步驟,並在最終報告中揭露未執行的項目。
4. 我提供的素材是部落格連載文章,請區分「規格」與「敘事」:
- 流程、規則、判準、豁免情境、路徑與命名規範 → 規格,須完整編入 skill
- 演進故事、給讀者的科普解釋(如定錨效應舉例)、工具安裝教學、
「明天待續」類預告、圖片 → 僅供理解脈絡,不得寫入 skill
- 「一開始…後來改成…」的演進敘事,一律只取最終形態
- 分不清是規格還是敘事的段落 → 在 grill-me 階段列出來問我,不要自行猜測
請你把所有素材檢視、思考後,透過 /mattpocock-skills:grill-me 的方式逐一跟我討論;
討論收斂後,先給我檔案結構規劃(每個檔案的職責一句話),我確認後才開始撰寫。
請將上面這段預設的 Prompt 以及 Day 3~10 的文章內容貼入給 Claude Code (或是你選用的其他 AI Coding Agent),就可以開始與它進行討論。
還記得前面提過,我也把過去的 GitLab MR Review Comments、文件、教學、錄音逐字稿與文稿等內容作為素材嗎?一方面讓它有真實世界的情境可以參照,另一方面也能讓它理解我的風格,使輸出的語氣與價值觀更貼近我。
如果素材來自公司、客戶或未公開專案,請先確認有權交由所選的 AI 服務處理,再移除憑證、內部位址、個人資料與可識別專案的資訊;不適合直接提供的內容,只保留抽象規則或經過消毒的案例。
我馬上看到 Claude Code 正在讀取官方 Skill 最佳實踐網頁與本地 Skill。
我當時實際使用的是
/skill-creator、/writing-great-skills與/grill-me,而且不小心連 Day 1、Day 2 都餵進去了。上方 Prompt 已更新成目前的 Skill 指令名稱;大家準備 Day 3~10 的內容即可。
它讀完素材的第一件事不是提問,是先報告它把我的刀切在哪:
判為敘事、不編入:演進史、醫院背景、所有工具安裝教學、給讀者的科普例子(定錨效應、滅火器那類)、所有圖片與「明天待續」。
判為規格、完整編入:三等級定義、九面向全部細則、KISS>DRY>YAGNI 優先序、反蒙蔽協議、資訊≠指令、未驗證不掛等級、報告四條硬規則、路徑與命名規範、GitLab API 端點、Pushback 六題、版號格式。
取最終形態:報告一律 JSON→script 轉 Markdown(不取「主 agent 直出 Markdown」);不受限審查一律外包 ncr-fresh-eyes(不取 inline);工作目錄一律帶 {group} 與 mr{iid}。
這段值得停一下。我在硬性要求裡只寫了「請區分規格與敘事」,它自己把刀切完、還先攤出來讓我確認:包含「一開始…後來改成…」的段落只取最終形態這條,我確實在 Day 3~10 裡留了不少演進敘事。
然後它說:整理出 18 個必須由我裁決的問題,分 8 組(A 封裝與執行環境、B 進入點與取碼、C 反蒙蔽、D 掃描器、E 九面向、F 報告、G Pushback、H 雜項),一次問一題,每題附它的建議。
實際問完是 17 題:過程中有兩題被它併成一題問,因為我前一題的回答已經把後一題的答案講掉了。
以下是完整的 17 題與我的決定。每一題它都給三個選項、標好它建議哪一個,右邊還附一個具體的預覽方框,讓我看到「選了會長什麼樣」。這個設計讓裁決快很多,我不用在腦中把抽象選項展開成實際檔案結構。
| # | 它問什麼 | 它建議 | 我的決定 | 為什麼 |
|---|---|---|---|---|
| 1 | skill 原始碼放哪? | 獨立 git repo + symlink | 放在鐵人賽資料夾內,再 symlink 出去 | symlink 已經把撰寫位置和安裝位置分開了,多一個 repo 只是多一個要同步的地方 |
| 2 | ncr-* subagent 怎麼實現? | 真 agent 定義 + 降級回退 | 同建議 | 只用 prompt tag 就無法釘模型;只裝真 agent 則會在沒有 agent 的環境直接壞掉。我一直想讓這套東西 agent agnostic,所以退路要一起留 |
| 3 | scripts/ 包到多廣? | 四支核心 + 掃描 runner | 同建議 | 見下方 |
| 4 | 本機模式跑多完整的流程? | 依標的大小自動分流 | 同建議 | 改三個檔案跟改一整條 branch 不該走同一條管線 |
| 5 | 已在 repo 內還要 clone 到 /tmp 嗎? | 一律 clone | 同建議 | 審查不該動到我正在工作的 working tree,這條沒有例外值得開 |
| 6 | GitLab token 從哪讀? | GITLAB_TOKEN,否則問 | 同建議 | 多 host 設定檔是我還沒有的需求;先用最小可行的做法,不夠再換 |
| 7 | 再審時,作者的新留言何時進 context? | 與前次報告同時封存到比對階段 | 同建議 | 這是反蒙蔽協議的核心,留言先讀就等於先看答案 |
| 8 | MR diff 從哪來? | 一律本機算,.diff 不編入 | 同建議 | 本機 git 算得出來的東西,不需要多一條會壞的網路路徑 |
| 9 | ruff / ty / oxlint 掃描範圍? | 全專案掃,依 diff 歸因 | 同建議 | 見下方 |
| 10 | opengrep 拿哪些規則掃? | 依 diff 語言自動選目錄 | 同建議 | 這個 repo 用不到的語言規則不會命中任何東西,跑它們只是讓每一場掃描都多等一段時間 |
| 11 | 唯讀 package token 的豁免怎麼認定? | 結構式識別,零設定 | 同建議 | 外部 allowlist 是一個要維護的檔案,而且會被複製到不該豁免的地方 |
| 12 | 「醫療情境」的升級閘門怎麼認定? | 依證據判定 PHI 接觸 | 同建議 | 一律假設醫療環境會讓這條規則失去意義,每個 repo 都升級等於沒有升級 |
| 13 | finding ID 怎麼編、跨輪怎麼延續? | MR 級流水號,只增不重用 | 同建議 | 編號重用會讓「上一輪的 F-002」在對照時指到不同的東西 |
| 14 | 發佈到 MR 的報告版面怎麼排? | 重點在上,次要摺疊 | 同建議 | 一則留言塞十幾條 finding,不摺疊的話沒有人會讀到最後 |
| 15 | 自檢 subagent 能直接改報告 JSON 嗎? | 唯讀,回報給主 agent 修 | 同建議 | 主 agent 才有最完整的 context,審查結果是給它的建議,改不改由它決定與動手 |
| 16 | Pushback 流程放哪? | 同一 skill 的第二分支 | 同建議 | 作者反駁跟審查是同一場對話的兩半,拆成兩個 skill 要處理狀態交接 |
| 17 | CodeGraph 索引什麼時候建? | Phase 2 並行預建 | 概念上同意,但不要派 subagent | 見下方 |
四題值得展開講。
第 1 題:這題我就沒照它的建議走。
它建議獨立 git repo 加 symlink,理由是「skill 本身要跟隨 commit 控管並有版號,所以撰寫位置和安裝位置我傾向分開」。這個推論是對的,但它想解決的問題,symlink 一個人就解決得了。撰寫位置在版控裡、安裝位置在 ~/.claude/skills/,兩邊靠 symlink 連起來,對我當時的需求而言,獨立 repo 帶來的好處不足以抵銷多一份同步成本。
所以我選第三個:原始碼直接住在既有的 repo 裡,安裝時 symlink 出去。
第 3 題:我在這題之後補了一句它沒問的。
它問 scripts/ 要包到多廣,我選了「四支核心 + 掃描 runner」。然後我自己加了一條限制:
另外這些 script 除了 Pydantic 外,儘量用內建的模組!若有需要用到其他套件,請拿出來討論
這句是它沒問、我也差點沒想到要講的。這些腳本是 PEP 723 單檔、用 uv run 直接執行,相依愈少愈好;如果放任它自由選套件,換一台機器就可能因為裝不起來而整條軌道停擺。
第 9 題:它看見了一個我沒看見的兩難。
問題是 ruff / ty / oxlint 的掃描範圍。它給的選項旁邊附了這段:
ty 是型別檢查,只餵變更檔案會因為解析不到專案上下文而產出假警報;但整個 repo 掃下去,一定會撈到一堆跟這次 MR 無關的既有問題,全部寫進報告就是在罵作者沒做過的事。
這個兩難我事前完全沒想過。我原本的心智模型很單純:審查的是這次的 diff,那就掃 diff。它指出兩邊都不行,然後給了第三條路:全專案掃、但依 diff hunk 歸因,落在 diff 裡的算 finding,其餘的只用一行揭露總數。
第 17 題:概念上它對,實作上它想多了。
它建議 CodeGraph 索引在 Phase 2 跟其他掃描器一起並行預建,預覽方框裡畫的是四個平行的 subagent,其中一個叫 ncr-build-graph。我的回覆是:
概念上選 1(預建,不要 lazy、也不要棄用),但實作調整:不要為建索引派 subagent。
codegraph init不到一秒就能完成,由主 agent 在 clone 完成後同步執行即可。
派一個 subagent 的固定成本,比它要做的事還貴。
我自己在幾個專案中執行初始化,都是不到一秒就完成;不過這當然會受到裝置效能與專案大小影響,不代表所有環境都會有相同速度。
上面這段對齊總共花了 20 幾分鐘。
第一次用 /grill-me 的想法是,哇⋯⋯Prompt 即便打得再長,其實都一定有缺一些關鍵資訊。我們也可以反思,自己認為「寫得很完整的 Prompt」在 AI 眼中哪些是容易有歧異的?哪些又是自己常會忽略的?
另外大家也可能發現,17 題裡我有 15 題直接採用它的建議。它推薦的選項通常就是我會選的那個選項。而真正有價值的是剩下那兩題,以及第 9 題那種「它想到了我沒想到的」。
我回答完最後一題後,它開始一口氣寫第一版;最後這段撰寫階段花了 26 分鐘。🎊
初版已經採用下面這種拆分方式。以下圖片呈現的是經過後續調整後的目前版本:
真正值得看的是那個比例。SKILL.md 約 11.9 KB,是 Skill 觸發後才載入的主要入口;references/ 加 agents/ 約 73 KB,而一次審查通常只會碰到其中幾份。所謂「按需載入」不是省錢的技巧,是讓模型在每一步只面對那一步該面對的東西。
這個作法有名字,叫 progressive disclosure(漸進式揭露):入口只放路由,細節留在原地,走到哪一步才讀那一份。官方寫 skill 的建議裡就是這樣講的,我當時是照著做,後來才知道它叫這個。
/usage 直接給這次 session 的帳:27.02 美金、API 實際運算 1 小時 10 分、wall time 4 小時 4 分;這次 session 累計記錄 5,543 行新增、112 行刪除。這三個時間的範圍不同:wall time 包含我回答問題時離開電腦的等待,API 時間涵蓋整個 session,前面的 26 分鐘只計最後一口氣寫完初版的階段。錢幾乎都在 Opus 身上(26.57 美金),Sonnet 花掉 4 毛多,Haiku 不到一分錢。
這是「從零建出整份 skill」的成本,不是「跑一次審查」的成本。
帳記完了,Skill 的第一版也完成了。明天拿它去審第一份真實 MR。
同時這份 skill 連同整個 Repo,也會一起公開🤩。