到昨天為止,這一整套開發流程:TDD、收工前測試、CI 閘門,以及交付收尾清單——都還只存在於我的本機。接下來進入 Part 4,目標是讓 AI 真正成為開發流程的一部分,而不只是我自己使用的工具。
指令只有自己用,不叫規範;規範必須能被別人安裝、使用,並且在開發過程中持續生效。
Claude Code 的 Plugin 正是為了這件事而存在。它可以把 Skill、Command、Hook,甚至 MCP 設定打包在一起,讓其他人透過一行指令就能安裝。
不過,今天真正值得探討的,不只是如何把這些東西打包,而是在打包之前,我們得先確認:哪些東西真的值得成為規範?
我把兩個 repo 的 .claude/ 目錄全部攤開,重新盤點了一次:
| 東西 | 數量 | 備註 |
|---|---|---|
| 權限 allowlist | 25 條 | 其中 17 條含絕對路徑、6 條是一次性長指令 |
additionalDirectories |
6 條 | 全部是我這台機器的絕對路徑 |
| Stop hook | 1 支 | 收工前跑測試 |
CLAUDE.md 的開發規則 |
一節 | TDD 節奏、假綠守門 |
| CI workflow | 1 份 | 昨天前天建的 |
接著,我一條一條問自己:「這個東西搬到別的專案,還能用嗎?」,答案大致分成三類:
可以直接重用:TDD 的節奏、假綠的守門方式、交付收尾清單。這些是經過實作驗證的工作方法,不依賴特定語言、框架或專案。
可以重用,但需要調整:Stop hook。它的目的是通用的,但實際執行方式藏著原專案的假設,搬出去之前必須重新設計。
不適合直接搬移:權限設定、additionalDirectories,以及描述專案現況的 CLAUDE.md。這些都和特定環境或專案有關,不能直接套用到別人身上。
打包的價值不在最後那個資料夾,而在它逼你對每一條設定問:「這到底是規範,還是我的殘渣?」
如果不打包,這些設定可能一直留在原本的環境裡,沒有人會回頭檢查它們是否還有價值。
25 條權限設定裡,有一條長這樣:
Bash(cd "<專案路徑>/backend"; sed -n '70,110p' CLAUDE.md;
echo "=== notes/ 有沒有 d15 素材 ==="; ls "<另一個專案路徑>/notes/")
這是一條某天執行過一次的指令,卻被完整保存在權限設定裡,成為一條永久規則。它不但包含兩個專案的絕對路徑,內容也只對當時那次操作有用,幾乎不可能再被使用第二次。
原因很單純:每按一次「允許」,就可能多一條設定;但沒有機制定期檢查、刪除已經不需要的項目。
這幾天我已經第三次遇到類似的問題:測試跑完留下 455 個沒人讀的 warning、CLAUDE.md 連續幾輪沒有更新,現在則是只增不減的 allowlist。
這些問題看起來不同,背後卻有相同的特徵:
只增不減的東西,最後都可能變成沒有人讀的東西。
而 allowlist 還有另一層風險:把它打包出去,等於替別人決定要信任什麼。
在這次盤點的項目中,Stop hook 是最接近通用規範的一個。
它要解決的問題很單純:避免開發者忘記在結束工作前跑測試。這個需求不依賴特定專案,也不需要知道程式的業務邏輯。但原本的 Hook 開頭是這樣:
TEST_CMD = ["uv", "run", "pytest", "-q"]
BACKEND = "backend"
在原本的 repo 裡,這兩行看起來完全沒問題,因為專案使用 uv、測試放在 backend/,這些假設一直都成立。
直到要把 Hook 搬到 Plugin 裡,我才發現:
它不是一條通用規則,而是一條規則加上兩個專案特定的假設。
因此,我把執行方式改成三個階段:
第三個階段是刻意設計的。
偵測不到測試環境,不一定代表發生錯誤,也可能是使用者把 Plugin 安裝在尚未建立測試的專案裡。如果 Hook 因此不斷報錯,使用者很可能第一天就把它移除。
但找到測試指令後,測試失敗就不能直接放行。
所以我沿用前幾天建立的原則:每加一道閘門,就要刻意讓它失敗一次。
我餵了一個必定失敗的測試指令,確認 Hook 的行為:
第一次 exit=2
測試未通過,先不要收工。
3 failed
請修好再結束。
第二次 exit=0
測試仍未通過,但本 session 已提醒過一次,放行。
第一次確實擋住了,第二次則依照設計放行。
這個設計是為了避免另一種問題:Stop hook 回傳 2,會要求 Claude 繼續工作。如果測試因為環境問題而一直無法通過,Claude 就可能陷入反覆執行、反覆被擋的循環,導致 session 無法正常結束。
因此,我選擇只擋一次。
擋一次,足以提醒使用者;擋到無法結束,反而可能讓使用者直接移除整個 Plugin。
這次搬移也讓我發現,真正值得重用的不是原本那幾行程式碼,而是「結束前要確認測試結果」這個工作原則。至於測試指令和執行目錄,則應該交由各專案自行決定。
經過盤點和調整,最後真正放進 Plugin 的只有三項:
| 內容 | 是什麼 |
|---|---|
skills/red-green |
實作節奏:RED → GREEN → IMPROVE,含「斷言不存在要先守門」的寫法 |
commands/closeout |
交付收尾四問 + 逐句文件對照 |
hooks/stop-run-tests.py |
收工前跑測試,沒過擋一次 |
這三項有個共同點:它們不是在描述某個專案目前的狀態,而是在定義可以重複使用的工作方法。
這也讓我重新理解前一天整理出的原則:
適合跨專案重用的,通常不是某個專案的現況,而是經過驗證的工作方法。
不過,能重用不代表永遠不需要更新。當工具版本或開發流程改變時,這些規則仍然需要重新檢查。
除了 Plugin 本身,我也在 README 裡增加了一節「刻意不包含」,列出這次沒有打包的權限設定、CI workflow,以及專案專屬的 CLAUDE.md,並說明原因。
這一節和 Plugin 本體同樣重要。
因為使用者安裝 Plugin 後,必須知道哪些能力已經提供,哪些仍然需要依照自己的專案設定。否則很容易誤以為安裝完成,就代表整套開發流程都已經準備好了。
CLAUDE.md 跟 plugin 的界線在哪盤點過程中,最難判斷的其實是:哪些規則應該留在 CLAUDE.md,哪些適合放進 Plugin?
兩邊都可以放開發規則,但我最後找到一個簡單的判斷方式:
這條規則換到另一個專案,還成立嗎?
例如:
-「測試要先紅過,再實作讓它變綠」:換到其他專案仍然成立,適合放進 Plugin。
-「後端指令必須從 backend/ 執行,因為 pythonpath 設定在那裡」:只適用於目前這個 repo,應該留在專案的 CLAUDE.md。
兩者的差別,不在於哪一種比較重要,而在於規則依賴的上下文不同。
CLAUDE.md 描述的是這個 repo 的現況與專案慣例,因此會隨著專案改變而更新;Plugin 則提供跨專案可重用的工作方法,不應該綁定某個專案的目錄結構或工具指令。
這也解釋了為什麼 CI workflow 不能直接整份搬進 Plugin。
CI 的檢查方式可以分成兩個部分:
通用的檢查原則: 例如每加一道閘門,就要刻意驗證它能不能擋住錯誤。這種方法可以寫進 Plugin。
專案實際執行的指令: 例如要執行哪些測試、使用什麼工具、在哪個目錄執行,則應該留在各自的專案設定中。
所以這次我把通用的檢查原則整理進 Skill,具體指令則留在各專案,沒有把整份 CI workflow 硬塞進 Plugin。
經過這次整理,我發現打包並不是把現有設定全部搬到另一個資料夾,而是重新確認每一條規則的適用範圍。
真正值得打包的,是換一個專案仍然有用的工作方法;需要依賴特定環境的設定,則應該留給專案自己管理。
明天:盤點成本。這 28 天下來,AI 到底省了什麼、哪些環節反而變貴。