本文根據 Claude Code 官方文檔《Automate actions with hooks》《Hooks reference》《Best practices for Claude Code》《Tools reference》整理,資料核對於 2026-11-05。配圖為本站整理的示意圖,不是介面截圖。本站(bigolab.com)不是 Anthropic 官方網站。
適用於誰
- 已經知道 Hooks 是什麼,想要一個能直接套用的實戰例子的人;
- 總擔心 Claude 沒跑測試就提交了的人;
- 配了鉤子卻發現沒生效、不知從哪查的人。
鉤子的基礎概念和事件列表,站內已有 /guides/claude-code-hooks,本文只做一個例子:提交前自動跑測試。
結論先說
- 用
PreToolUse事件。 官方說它在工具調用執行之前觸發,可以阻止。Claude 要運行git commit的那條 Bash 命令,就是被攔的對象。 - 阻止的辦法是退出碼 2。 官方:腳本往 stderr 寫原因並以退出碼 2 結束,Claude Code 會取消這次調用,並把 stderr 的內容作為反饋交給 Claude,讓它調整做法。
- 退出碼 0 不等於批准,只是「沒有意見」,調用仍走正常的權限流程。
- 別的退出碼(比如 1)一般不會攔截,只是個非阻塞的錯誤提示,操作照常進行。所以腳本里測試失敗時必須明確寫
exit 2,不要讓腳本靠測試命令自己的退出碼「碰巧」失敗。 - 用
if字段縮小範圍:官方的if用權限規則語法,只有命令匹配時才啟動鉤子進程,不用每條 Bash 命令都跑一遍。

圖:本站根據 Claude Code 官方文檔:Hooks 整理的示意圖
第一步:寫腳本
在項目裏建 .claude/hooks/test-before-commit.sh。思路沿用官方「保護文件」例子的結構:從標準輸入讀 JSON,取出 tool_input.command,決定放行還是攔截。
bash
#!/bin/bash
# .claude/hooks/test-before-commit.sh
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
# 只在命令裏確實有 git commit 時才跑測試
case "$COMMAND" in
*"git commit"*) ;;
*) exit 0 ;;
esac
cd "$CLAUDE_PROJECT_DIR" || exit 2
OUTPUT=$(npm test 2>&1)
STATUS=$?
if [ $STATUS -ne 0 ]; then
echo "測試沒有通過,已阻止這次提交。請先修復失敗的測試再提交。測試輸出的最後 40 行:" >&2
echo "$OUTPUT" | tail -n 40 >&2
exit 2
fi
exit 0
說明:
- 官方的 Bash 鉤子輸入裏,
tool_input.command就是 Claude 要運行的命令;用jq取出來是官方示例的做法。如果你的機器沒有jq,官方排錯裏說可以安裝它,或用 Python、Node.js 解析 JSON。 npm test換成你項目的測試命令。想只跑快的那部分測試,用你項目裏對應的命令。- 在 macOS 和 Linux 上,官方說鉤子腳本必須有可執行權限:
chmod +x .claude/hooks/test-before-commit.sh。 - 測試輸出只回傳最後 40 行,避免把大量日誌灌進上下文,這是本站的做法。
第二步:註冊鉤子
在項目的 .claude/settings.json 裏加入(提交進倉庫就是全隊共享;只想自己用,放 .claude/settings.local.json):
json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash|PowerShell",
"hooks": [
{
"type": "command",
"if": "Bash(git commit *)",
"timeout": 300,
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/test-before-commit.sh"
},
{
"type": "command",
"if": "PowerShell(git commit *)",
"timeout": 300,
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/test-before-commit.sh"
}
]
}
]
}
}
對照官方文檔:
matcher區分大小寫,按工具名匹配;Bash|PowerShell是官方在講 PowerShell 工具時給的寫法,因為 Windows 上 Claude 可能走 PowerShell 工具而不是 Bash 工具,只匹配Bash是不夠的。- 官方說,要匹配多個工具名,可以分成幾個處理器,各帶自己的
if,所以這裏寫了兩條。 timeout單位是秒;官方說命令類鉤子預設是 10 分鐘。測試跑得久就按需調大,太小會被取消。官方說多數事件裏超時的鉤子不產生任何決定,也就是說超時不會攔截,提交會照常進行,所以別把超時設得比測試耗時還短。"$CLAUDE_PROJECT_DIR"/.claude/hooks/...是官方「保護文件」例子裏引用腳本的寫法。
第三步:不靠 Claude,自己先測腳本
官方排錯裏給了辦法:用管道把一段示例 JSON 餵給腳本,再看退出碼。
bash
# 不是提交命令:應當直接放行,退出碼 0
echo '{"tool_name":"Bash","tool_input":{"command":"git status"}}' | .claude/hooks/test-before-commit.sh; echo $?
# 是提交命令:測試通過返回 0,不通過返回 2
echo '{"tool_name":"Bash","tool_input":{"command":"git commit -m test"}}' | .claude/hooks/test-before-commit.sh; echo $?
故意把一個測試改壞,再跑第二條,應該看到失敗輸出和退出碼 2;改回來後應該是 0。
第四步:在 Claude Code 裏驗證
- 輸入
/hooks,確認PreToolUse下有這個鉤子。官方說如果剛改了設定文件、幾秒後還沒出現,重啟會話。 - 故意讓測試失敗,然後說:「請提交當前改動,提交資訊寫 test」。
- 按
Ctrl+O打開會話記錄,看鉤子的結果。官方說被阻止時通常會看到隨阻止一起給出的資訊。 - 再讓它修好測試後重新提交,這次應當放行。
提示詞 1:讓 Claude 幫你寫鉤子
text
請為這個項目寫一個 Claude Code 鉤子:每次 Claude 要執行 git commit 前,先運行【npm test】;測試失敗就阻止提交,並把輸出的最後 40 行作為原因反饋給 Claude。
要求:1)用 PreToolUse,只針對 git commit 命令;2)腳本放 .claude/hooks/,註冊到 .claude/settings.json;3)測試失敗必須明確 exit 2;4)寫完後用管道喂 JSON 的方法測試放行和攔截兩種情況,把結果給我。
寫完用 /hooks 讓我確認。
提示詞 2:被攔截之後
text
剛才提交被鉤子攔下了,請讀鉤子給出的測試輸出,找出失敗原因並修復。
修好後重新運行測試,通過了再提交。不要為了讓測試通過而刪除測試或修改它的預期結果,除非先告訴我原因。
提示詞 3:讓 Claude 審查鉤子的漏洞
text
請審查 .claude/hooks/test-before-commit.sh 和 .claude/settings.json 裏的鉤子配置,列出它攔不住或會誤攔的情況,例如:
1)git commit --amend、git commit -a、先 git add 再 && git commit 的組合命令;
2)git -C 某目錄 commit 這類帶參數的寫法;
3)測試命令不存在、測試超時、jq 沒安裝時腳本會怎樣(是放行還是攔截);
4)在 Windows 上由 PowerShell 工具發起的提交能否被攔住。
對每一項說明現狀和建議的改法,先只報告,不要修改文件。

圖:本站根據官方文檔整理的示意圖
排錯對照(官方「Limitations and troubleshooting」)
- 鉤子沒有觸發:
/hooks裏是否在PreToolUse下;matcher 是否完全匹配工具名(區分大小寫);事件類型對不對,PreToolUse在執行前、PostToolUse在執行後,而後者無法撤銷已發生的動作。 - 看到
PreToolUse hook error:腳本意外返回了非零退出碼。用上面的管道辦法手動測試,看是不是jq沒裝、路徑找不到,或腳本沒有可執行權限。 - 想看細節:官方說用
claude --debug啟動,或會話中運行/debug打開日誌。
Windows 的兩處坑
- 需要有 Bash 來運行這個腳本。官方說,Windows 上沒有 Git Bash 時,shell 形式的鉤子預設用 PowerShell 運行,Bash 寫的腳本可能失敗;安裝 Git for Windows,或用
CLAUDE_CODE_GIT_BASH_PATH指向 Git Bash,然後開新會話。另外官方還提醒:Windows 沒有 Git Bash 時,PreToolUse的鉤子失敗或超時可能直接阻止工具調用,錯誤訊息裏會寫着blocking because Git Bash wasn't found。 - 路徑帶反斜槓。官方說,Windows 上文件工具傳給鉤子的路徑是反斜槓,用正斜槓寫的比較永遠匹配不上,鉤子會「什麼也沒攔」。本例只看命令文本,不受影響;如果你改寫成按路徑攔截,務必先把反斜槓換成正斜槓。
更多 Windows 上的使用細節見 /guides/claude-code-windows-pitfalls-paths-git-bash-powershell。
另一種思路:Stop 鉤子
官方最佳實踐裏有一個相近的例子:Stop 鉤子在 Claude 想結束回覆時運行檢查,退出碼 2 會讓它回去繼續幹活,官方示例寫的是 pnpm tsc --noEmit 1>&2 || exit 2。把測試命令放進去,就是「每次回覆結束前測試必須通過」。注意官方說:連續阻止八次、中間沒有工具調用時,Claude Code 會放行;腳本里應讀取輸入裏的 stop_hook_active 字段,已在續跑時提前退出。兩種方式可以按需選:想在「提交」這個節點把關用本文的方法,想要「每一輪結束都驗證」用 Stop。
它攔不住什麼
PreToolUse 鉤子只管 Claude 發起的命令。你自己在終端裏手敲的 git commit、別的編輯器裏的提交,都不經過它。想對所有提交生效,要用 Git 自帶的 pre-commit 鉤子,那是 Git 的機制,不屬於 Claude Code。另外官方明確說 if 過濾是盡力而為的,要硬性禁止某類命令,應該用權限規則,見 /guides/claude-code-permission-modes。
訂閱和額度
鉤子本身不佔額度,但每次被攔截後 Claude 會讀測試輸出並重試,測試輸出越長越占上下文,所以只回傳末尾幾十行。訂閱選擇見 /chongzhi/claude-code,價格和額度以官方頁面當前顯示為準。
相關教學
- /guides/claude-code-hooks:Hooks 鉤子基礎
- /guides/claude-code-custom-skill-slash-command-example:自定義 Skill 實戰
- /guides/claude-code-git-commit-pr-merge-conflict:提交、PR 與合併衝突
參考資料
- Claude Code 文檔:Automate actions with hooks — https://code.claude.com/docs/en/hooks-guide
- Claude Code 文檔:Hooks reference — https://code.claude.com/docs/en/hooks
- Claude Code 文檔:Best practices for Claude Code — https://code.claude.com/docs/en/best-practices
- Claude Code 文檔:Tools reference — https://code.claude.com/docs/en/tools-reference
0 條評論
還沒有評論,來搶沙發~