
Claude Code Hooks:完整開發者指南與生產級範例
Claude Code 非常擅長撰寫程式碼,但它本質上仍是一個機率系統。你可以要求它在每次編輯檔案後執行 Prettier,也可以把這條指令寫進你的 CLAUDE.md。然而有時,它就是會……忘記。Claude Code hooks 透過提供確定性、有保證的控制機制來解決這個問題,讓你掌控 Claude 在每個動作之前、期間與之後所發生的一切。
過去幾個月,我在數十個專案中設定 hooks,它們已悄然成為我 Claude Code 設定中最重要的一環。本指南涵蓋從基礎到生產級入門套件的所有內容,你今天就能將它放入任何專案中使用。如果你曾用過 Claude Code 搭配 Cursor 或 Copilot 等工具,你應該已經了解自訂的價值,而 hooks 更將此提升到另一個層次。
什麼是 Claude Code Hooks(為什麼你該關心)?
Claude Code hooks 是使用者自訂的 shell 指令、HTTP 端點或 LLM 提示,會在 Claude Code 生命週期的特定節點自動執行。根據 Anthropic 官方文件,與 Claude 可能會忽略的提示指令不同,hooks 每次都會確定性地觸發,讓你能確實掌控格式、安全性、通知與工作流程自動化。
機率性問題
CLAUDE.md 的指令有個特點:它們是建議,而非合約。你可以在專案情境中寫下「編輯 TypeScript 檔案後一律執行 npx prettier --write」,而 Claude 大部分時候確實會照做。但當你需要在整個團隊中強制執行程式碼格式化、阻擋推送至生產環境,或是為安全稽核記錄每一條 shell 指令時,「大部分時候」可就遠遠不夠了。
這就是所有 AI 程式設計工具的核心矛盾。Claude 是語言模型,它的運作基於機率。你的情境工程可以引導行為,卻無法保證行為。
Hooks 如何解決這個問題
Hooks 完全繞過了 LLM。它們是在特定生命週期事件中觸發的 shell 腳本、HTTP 呼叫或 AI 評估——在工具執行之前(PreToolUse)、工具完成之後(PostToolUse)、通知出現時、工作階段開始時,或是 Claude 停止時。你可以把它們想像成 Git hooks,只不過是為你的 AI 編程助手而設的。
目前有四種 hook 類型:command(shell 腳本)、HTTP(webhook POST 請求)、prompt(單輪 Claude 是/否評估)以及 agent(產生一個具有工具存取權限的子代理)。我們稍後會逐一說明,不過 command hook 大約能涵蓋你 90% 的需求。
Claude Code Hooks 的運作方式:生命週期流程
Claude Code hooks 會在一套定義明確的生命週期中執行:系統觸發事件(例如 PreToolUse),比對器檢查該 hook 是否適用,接著執行 hook 腳本並透過 stdin 接收 JSON,最後由退出碼決定後續動作。退出碼 0 表示繼續執行,退出碼 2 表示封鎖該操作。無論你使用的是哪種 hook 類型,這個流程都相同。
事件 -> 匹配器 -> Hook -> 結束碼(四步驟流程)
以下是每個 Hook 執行的運作方式:
1. EVENT FIRES e.g., PreToolUse(Write)
|
2. MATCHER CHECKS Does "Write" match the hook's matcher pattern?
|
3. HOOK EXECUTES Shell script runs, receives JSON via stdin
|
4. EXIT CODE DECIDES 0 = proceed | 2 = block | other = error透過 stdin 傳入的 JSON 包含了事件的所有資訊:tool_name、tool_input(檔案路徑、內容、指令),以及工作階段的中繼資料。你的腳本會讀取這個 JSON,執行所需的邏輯,然後以適當的結束碼退出。
對於 PreToolUse Hook 而言,結束碼 2 是最關鍵的一個,它會完全阻擋該動作,並將你的 stdout 訊息作為回饋傳回給 Claude。Claude 會看到你的訊息,並據此調整做法。
設定範圍:使用者、專案與本機
Hooks 存放在三個層級的 settings.json 中:
| 範圍 | 檔案 | 是否提交至 Git? | 使用情境 |
|---|---|---|---|
| 使用者 | ~/.claude/settings.json | 否 | 個人預設值(通知、格式偏好設定) |
| 專案 | .claude/settings.json | 是 | 團隊共用的 hooks(檔案保護、測試執行器、程式碼檢查) |
| 本機 | .claude/settings.local.json | 否(已加入 gitignore) | 此專案的個人覆寫設定 |
專案設定對團隊來說最為實用。只要將 hooks 放入 .claude/settings.json 並提交,團隊中的每位開發者就能自動獲得相同的防護機制。
if 欄位:細粒度篩選
自 Claude Code v2.1.85 起,hooks 支援了 if 欄位,讓你不僅能依工具名稱篩選,還能依工具參數進行篩選。根據 Anthropic hooks 參考文件 的說明,這代表你可以撰寫一個 hook,只在 Bash 指令符合 git push 時才觸發,而不是在每次 Bash 呼叫時都觸發。
{
"matcher": "Bash",
"if": "tool_input.command matches 'git push'",
"hooks": [{ "type": "command", "command": "./scripts/check-branch.sh" }]
}這是一項重大改進。在 if 出現之前,你要么比對範圍過廣(所有 Bash 指令),要么就得在腳本內部自行篩選(雜亂)。
所有 Claude Code Hook 事件:快速參考表
Claude Code 在其生命週期中提供了超過 20 個 hook 事件,詳見官方 hooks 參考文件與 Claude Code 更新日誌。最常用的是 PreToolUse、PostToolUse、Notification 和 Stop,但像 ConfigChange 和 FileChanged 這類較新的事件,則開啟了進階自動化的可能性。
以下是完整的參考表:
| 事件 | 觸發時機 | 能否阻擋? | 常見用途 |
|---|---|---|---|
| PreToolUse | 工具執行之前 | 可以(exit 2) | 阻擋危險指令、保護檔案 |
| PostToolUse | 工具執行完成之後 | 否 | 自動格式化、執行測試、記錄操作 |
| Notification | Claude 發送通知時 | 否 | 桌面提醒、Slack 訊息 |
| Stop | Claude 完成回應時 | 否 | 清理作業、產生摘要 |
| SessionStart | 工作階段初始化時 | 否 | 注入上下文、設定環境 |
| UserPromptSubmit | 使用者提交提示詞時 | 可以(exit 2) | 輸入驗證、內容過濾 |
| PreCompact | 上下文壓縮之前 | 否 | 在記憶被裁剪前儲存狀態 |
| PostCompact | 上下文壓縮之後 | 否 | 重新注入關鍵上下文 |
| ConfigChange | 設定變更時 | 否 | 熱重載環境變數 |
| FileChanged | 被監控的檔案變更時 | 否 | 觸發重新建置、使快取失效 |
| TaskCreated | 新任務產生時 | 否 | 任務追蹤、資源配置 |
| PermissionDenied | 權限檢查失敗時 | 否 | 稽核記錄、對被封鎖的操作發出警示 |
| WorktreeCreate | 建立新的 Git worktree 時 | 否 | 初始化該 worktree 專屬的設定 |
| SubagentStart | 子代理啟動時 | 否 | 監控子代理活動 |
| SubagentStop | 子代理完成時 | 否 | 驗證子代理輸出 |
專業提示: 你的 hook 有 80% 都會用到 PreToolUse 和 PostToolUse。其次是 SessionStart,它非常適合用來注入 Claude 在每個工作階段開始時所需的專案上下文。
Claude Code 的四種 Hook 類型詳解
Claude Code 支援四種 hook 處理程式類型:command hook 會執行 shell 腳本、HTTP hook 會向 URL 發送 POST 請求、prompt hook 會向 Claude 提出是/否的問題,而 agent hook 則會產生一個具有工具存取權限的子代理。根據我們的經驗,command hook 可以涵蓋 90% 的使用情境。HTTP 適用於外部整合,prompt 和 agent hook 則適用於需要 AI 判斷的細微決策。
| 類型 | 速度 | 複雜度 | 最適合 | 範例 |
|---|---|---|---|---|
| Command | 快 | 低 | 格式化、封鎖、記錄 | 在檔案編輯後執行 Prettier |
| HTTP | 中 | 中 | 外部服務、webhook | 完成時向 Slack 發送 POST |
| Prompt | 慢 | 中 | 主觀決策 | 「這段程式碼可以安全執行嗎?」 |
| Agent | 最慢 | 高 | 複雜的檔案感知驗證 | 檢查新程式碼是否遵循專案模式 |
命令掛鉤(主力工具)
命令掛鉤會執行一個 shell 指令,並透過結束碼來判定結果。它們會透過 stdin 接收事件的 JSON 資料。
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "jq -r '.tool_input.command' | grep -q 'rm -rf /' && exit 2 || exit 0"
}]
}]
}
}這是你用於格式化、檔案保護、通知以及大多數自動化工作的工具。快速、簡單且可預期。
HTTP Hooks(外部整合)
HTTP Hook 會將事件 JSON 作為請求主體,以 POST 請求傳送至指定 URL,並由回應的狀態碼決定處理結果(200 = 繼續執行,403 = 封鎖)。
{
"hooks": {
"Stop": [{
"matcher": "",
"hooks": [{
"type": "http",
"url": "https://your-api.com/claude-webhook"
}]
}]
}
}非常適合將事件傳送至 Slack、Discord、PagerDuty 或自訂儀表板。你也可以運用這個機制,在允許工具執行前先查詢外部政策引擎。
Prompt Hooks(AI 驅動的決策)
Prompt hooks 會將事件資料傳遞給 Claude 本身,進行單輪的是/否評估。Claude 會回傳一個 JSON 回應,其中包含 "decision": "allow" 或 "decision": "block" 以及推理說明。
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "prompt",
"prompt": "Is this bash command safe to run in a production environment? Consider: does it modify system files, delete data, or access sensitive credentials?"
}]
}]
}
}請謹慎使用這些功能。它們會增加延遲(每次 hook 執行都需要一次完整的 LLM 呼叫)與成本。但對於真正主觀性的安全檢查,例如「這個資料庫遷移看起來是否具有破壞性?」,它們幾乎無可取代。如果你對切換 Claude Code 模型感到好奇,prompt hooks 所使用的模型會跟隨你目前的工作階段模型。
Agent Hooks(工具輔助驗證)
Agent hooks 會產生一個可存取 Read、Grep 與 Glob 工具的子代理。子代理能在做出決定前先檢查檔案。
{
"hooks": {
"PreToolUse": [{
"matcher": "Write",
"hooks": [{
"type": "agent",
"prompt": "Check if the file being written follows the project's naming conventions and import patterns. Read .claude/CONVENTIONS.md for the rules."
}]
}]
}
}這是最強大的 hook 類型,但也是最慢的。請將其保留給需要檔案脈絡才能做出良好判斷的高風險檢查。
7 個可直接用於生產環境的 Claude Code Hook 範例(複製貼上即可使用)
最實用的 Claude Code Hook 包括:在檔案編輯後使用 Prettier 或 Black 自動格式化、封鎖對受保護檔案的寫入、在任務完成時發送桌面通知、在工作階段開始時注入專案情境、在程式碼變更後執行測試、強制執行分支保護,以及稽核所有工具的使用情況。過去三個月來,我一直在每個專案中執行這些 Hook 的各種變化版本。
以下每個範例都是一段完整的 settings.json 程式碼片段,你可以直接放入你的 .claude/settings.json 中。像 awesome-claude-code 這類社群收藏集還收錄了更多使用模式。
1. 儲存時自動格式化
{
"hooks": {
"PostToolUse": [{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // .tool_input.file' /dev/stdin); case \"$FILE\" in *.ts|*.tsx|*.js|*.jsx) npx prettier --write \"$FILE\" 2>/dev/null;; *.py) black \"$FILE\" 2>/dev/null;; esac; exit 0"
}]
}]
}
}這個 hook 會在每次 Write 或 Edit 之後觸發,從 stdin JSON 中提取檔案路徑,並執行對應的格式化工具。結尾的 exit 0 可確保這個 hook 絕不會造成阻擋——格式化失敗不應該擋住 Claude。
專業提示: 如果你同時使用多種語言開發,可以加入 *.go 搭配 gofmt、*.rs 搭配 rustfmt。
2. 封鎖對受保護檔案的寫入
{
"hooks": {
"PreToolUse": [{
"matcher": "Write|Edit",
"if": "tool_input.file_path matches '(\\.env|\\.env\\.local|package-lock\\.json|yarn\\.lock|pnpm-lock\\.yaml)'",
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"BLOCKED: This file is protected. Edit it manually.\"}' && exit 2"
}]
}]
}
}結束代碼 2 會封鎖該動作,並將 JSON 訊息傳回給 Claude。Claude 會看到回饋並進行調整,通常它會告訴你它想修改該檔案,並請你手動執行。if 欄位可避免這在每次 Write 時都被觸發。
3. 完成時顯示桌面通知
{
"hooks": {
"Notification": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "MSG=$(jq -r '.message // \"Claude Code task finished\"' /dev/stdin); if [ \"$(uname)\" = 'Darwin' ]; then osascript -e \"display notification \\\"$MSG\\\" with title \\\"Claude Code\\\"\"; else notify-send 'Claude Code' \"$MSG\"; fi; exit 0"
}]
}]
}
}適用於 macOS(osascript)和 Linux(notify-send)。空的匹配器(matcher)代表它會對所有通知觸發。當你啟動一個需時較長的任務並切換到其他視窗時,這個功能真的非常實用。
4. 會話開始時注入上下文
{
"hooks": {
"SessionStart": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"Project: '\"$(basename $(pwd))\"' | Branch: '\"$(git branch --show-current 2>/dev/null || echo none)\"' | Last commit: '\"$(git log --oneline -1 2>/dev/null || echo none)\"'\"}'; exit 0"
}]
}]
}
}這會在每個會話中自動注入目前的專案名稱、Git 分支與最近一次 commit。Claude 會自動接收這些上下文,不需要特別告訴它你目前在哪個分支上。
5. 程式碼變更後自動執行測試
{
"hooks": {
"PostToolUse": [{
"matcher": "Write|Edit",
"if": "tool_input.file_path matches '\\.(ts|tsx|js|jsx|py)$'",
"hooks": [{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path' /dev/stdin); TEST_FILE=$(echo \"$FILE\" | sed 's/\\.[^.]*$/.test&/'); if [ -f \"$TEST_FILE\" ]; then npx jest \"$TEST_FILE\" --no-coverage 2>&1 | tail -5; fi; exit 0",
"timeout": 30000
}]
}]
}
}如果存在對應的測試檔案,Claude 編輯原始碼後便會自動執行該測試。tail -5 可讓輸出保持簡潔,而逾時機制則能防止測試套件執行失控。這很適合搭配 AI 驅動的程式碼審查工作流程。
6. 強制執行分支保護(進階)
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"if": "tool_input.command matches 'git push.*(main|master|production)'",
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"BLOCKED: Direct push to protected branch. Use a feature branch and open a PR.\"}' && exit 2"
}]
}]
}
}這會封鎖任何指向 main、master 或 production 分支的 git push。Claude 會收到回饋,並建議改為建立功能分支。
7. 安全稽核記錄(進階)
{
"hooks": {
"PostToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "INPUT=$(cat /dev/stdin); CMD=$(echo \"$INPUT\" | jq -r '.tool_input.command'); echo \"[$(date -u +%Y-%m-%dT%H:%M:%SZ)] BASH: $CMD\" >> .claude/audit.log; exit 0"
}]
}]
}
}將 Claude 執行的每一條 Bash 指令記錄到稽核檔案中,並附上 UTC 時間戳記。這對於安全審查以及瞭解 Claude 在工作階段中實際執行了哪些操作來說,非常實用。請將 .claude/audit.log 保留在你的 .gitignore 中。
Hooks、MCP、Skills 與 CLAUDE.md:何時該用哪個
Hooks 用於必須一律執行的確定性自動化(格式化、封鎖、通知)。MCP 用於讓 Claude 存取外部工具與資料。Skills 用於可重複使用的提示套件。CLAUDE.md 用於行為指引與專案背景。Hooks 是有保證的;其他一切都是機率性的。這是最重要的一項區別,也是我在為團隊提供建議時反覆回過頭來談的重點。
決策矩陣
| 機制 | 是否具確定性? | 何時執行 | 最適合 | 範例 |
|---|---|---|---|---|
| Hooks | 是 | 在生命週期事件發生時自動執行 | 強制執行、自動化、通知 | 自動格式化、封鎖檔案寫入 |
| MCP | 否(由 Claude 決定) | 當 Claude 呼叫 MCP 工具時 | 新功能、存取外部資料 | 查詢資料庫、搜尋 Notion |
| Skills | 否(由使用者觸發) | 當使用者執行斜線指令時 | 可重複使用的指令集 | 以 /review 進行程式碼審查流程 |
| CLAUDE.md | 否(指引性質) | 在工作階段開始時讀取 | 專案情境、程式碼規範 | 「使用 Tailwind,並為所有新程式碼撰寫測試」 |
若要深入瞭解 MCP,請參閱我們的 MCP 指南。如果你原本使用 Cursor,Cursor 的規則系統大致相當於 CLAUDE.md,但 Cursor 沒有類似 hooks 的功能。
當它們重疊時(以及如何選擇)
以下是我使用的流程圖:
- 「這件事是否必須每次都執行,毫無例外?」,Hook。格式化程式碼、封鎖受保護的檔案、傳送通知。零模糊空間。
- 「Claude 是否需要一項它目前沒有的新能力?」,MCP 伺服器。存取資料庫、呼叫 API、搜尋外部文件。
- 「我想要針對特定工作流程的可重複使用指令嗎?」,Skill(斜線指令)。程式碼審查範本、部署檢查清單。
- 「我想要在這個專案中塑造 Claude 的行為嗎?」,CLAUDE.md。編碼規範、架構決策、偏好的函式庫。
一些能釐清界線的實際範例:
- 「一律使用 Prettier 格式化」= Hook(它必須每次都執行)
- 在 CLAUDE.md 中寫「使用 Prettier 進行格式化」= 指引(Claude 可能會忘記)
- 「搜尋我們公司的文件」= MCP(新能力)
- 「審查程式碼時遵循我們的風格指南」= Skill 或 CLAUDE.md
正如 Anthropic 的外掛公告 所述,hooks 是更廣泛外掛生態系的一部分,該生態系還包含 MCP 與 Skills。它們的設計目的是相輔相成,而非相互競爭。
入門套件:適用於任何專案、即插即用的 Claude Code Hooks 設定
Claude Code 的入門 hooks 設定應包含:檔案編輯時自動格式化、任務完成通知、敏感檔案保護、工作階段情境注入,以及用於清理的 stop hook。這正是我在每個新專案中直接沿用的設定,會依技術棧調整,但結構維持不變。
設定檔
{
"hooks": {
"SessionStart": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"Project: '\"$(basename $(pwd))\"' | Branch: '\"$(git branch --show-current 2>/dev/null)\"' | Node: '\"$(node -v 2>/dev/null)\"'\"}'; exit 0"
}]
}],
"PreToolUse": [{
"matcher": "Write|Edit",
"if": "tool_input.file_path matches '(\\.env|\\.env\\..+|.*lock\\.json|.*lock\\.yaml)'",
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"Protected file. Edit manually.\"}' && exit 2"
}]
}],
"PostToolUse": [{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // .tool_input.file' /dev/stdin); case \"$FILE\" in *.ts|*.tsx|*.js|*.jsx) npx prettier --write \"$FILE\" 2>/dev/null;; *.py) black \"$FILE\" 2>/dev/null;; *.go) gofmt -w \"$FILE\" 2>/dev/null;; esac; exit 0"
}]
}],
"Notification": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "MSG=$(jq -r '.message // \"Done\"' /dev/stdin); osascript -e \"display notification \\\"$MSG\\\" with title \\\"Claude Code\\\"\" 2>/dev/null || notify-send 'Claude Code' \"$MSG\" 2>/dev/null; exit 0"
}]
}],
"Stop": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "echo '[STOP] '\"$(date +%H:%M:%S)\"'' >> .claude/session.log; exit 0"
}]
}]
}
}如何針對你的技術棧進行客製化
| 技術棧 | 格式化指令 | 測試指令 | 監聽副檔名 |
|---|---|---|---|
| Node/TypeScript | npx prettier --write | npx jest --no-coverage | .ts, .tsx, .js, .jsx |
| Python | black | pytest -x | .py |
| Go | gofmt -w | go test ./... | .go |
| Rust | rustfmt | cargo test | .rs |
將上方設定中的格式化與測試指令替換為符合你技術棧的版本即可。整體結構保持不變。
驗證您的 Hook 是否正常運作
有三種方式可以確認 Hook 已啟用:
/hooks指令,在 Claude Code 中輸入/hooks,即可查看所有已註冊的 Hook、其比對器(matcher)以及狀態。- 檢視對話紀錄,在 Hook 觸發後,檢查該工作階段的對話紀錄。Hook 的執行結果會連同其輸出內容與結束代碼(exit code)一併顯示。
- 快速切換開關,在 settings.json 中加入
"disableAllHooks": true,即可暫時停用所有 Hook,而無需刪除設定檔。將其移除(或設為false)即可重新啟用。
CI/CD 整合:無頭模式下的 Claude Code Hooks
Claude Code hooks 可在無頭模式(claude -p)下運作,但有一些差異:Notification hooks 仍然會觸發,但你應該將其重新導向至記錄檔,而非桌面通知。Exit code 為 2 的 PreToolUse hooks 可以暫停無頭工作階段,以供人工審查。GitHub Actions 搭配 hooks 使用 anthropics/claude-code-action@v1 來實現自動化工作流程。
無頭模式行為
| Hook 事件 | 互動模式 | 無頭模式(-p) | CI 建議做法 |
|---|---|---|---|
| PreToolUse(結束碼 2) | 封鎖操作並顯示訊息 | 暫停並等待 --resume | 用於必要的人工核准 |
| PostToolUse | 正常執行 | 正常執行 | 保留格式化器與記錄器 |
| Notification | 桌面通知 | 仍會觸發(無 UI) | 重新導向至記錄檔或 Slack webhook |
| Stop | 執行清理作業 | 執行清理作業 | 適合用於 CI 產出物收集 |
| SessionStart | 注入情境資訊 | 注入情境資訊 | 注入 CI 環境變數 |
無頭模式中最令人意外的地方:以結束碼 2 結束的 PreToolUse hook 並不會只是默默失敗。它們會暫停工作階段,讓你透過 --resume 接續執行,這為 CI 管線提供了一種人在迴路(human-in-the-loop)的實作模式。
GitHub Actions 整合
以下是一個使用 Claude Code 搭配 hooks 的精簡 GitHub Actions 工作流程。如官方 GitHub Actions 指南所述:
- name: Run Claude Code
uses: anthropics/claude-code-action@v1
with:
prompt: "Review this PR and suggest improvements"
allowed_tools: "Read,Grep,Glob"
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}你的 .claude/settings.json hooks 會隨儲存庫一起運作,因此在 CI 中觸發的行為與本機完全一致。只需確認任何依賴桌面專屬工具(例如 osascript)的 hooks 都有備用方案或條件判斷即可。
團隊 Hook 管理
一個很適合團隊使用的模式:
.claude/settings.json(已提交),團隊共享的 Hook:檔案保護、格式化工具、分支保護。所有人都會套用這些設定。.claude/settings.local.json(已加入 gitignore),個人 Hook:通知偏好設定、自訂日誌、實驗性 Hook。~/.claude/settings.json(使用者全域),適用於你所有專案的預設值:通知樣式、個人格式化偏好設定。
這與 .editorconfig(已提交)和本機 IDE 設定(個人)的運作方式如出一轍。正如 Angelo Lima 的 CI/CD 指南所指出,將共享 Hook 標準化的團隊,在使用 Claude Code 時較少遇到「在我電腦上可以跑」的問題。
Claude Code Hooks 疑難排解與常見錯誤
常見的 Claude Code hooks 問題包括:hooks 未觸發(請檢查 matcher 拼寫與 settings.json 的位置)、hooks 有執行但無法阻擋(exit code 用錯,應使用 2 而非 1)、無限迴圈(Stop hook 觸發了它自己),以及啟動緩慢(同步 hooks 過多)。我最常看到的錯誤是 exit code 混淆——開發者想用的是 exit 2,卻寫成了 exit 1。
Hook 沒有觸發
症狀: 你已經新增了 hook,但事件發生時卻沒有任何反應。
修正方法:
- Matcher 拼寫錯誤,Matcher 有區分大小寫。
"write"不會符合Write工具。使用/hooks檢查正確的工具名稱。 - 設定檔錯誤,位於
~/.claude/settings.json的 hooks 不會出現在專案範圍的/hooks輸出中。改用專案根目錄下的.claude/settings.json。 - JSON 語法錯誤,多餘的逗號或缺少的括號會悄悄停用整個 hooks 設定。用
jq .驗證你的 settings.json。 disableAllHooks: true,檢查是否有人(或先前的除錯階段)留下了這個旗標。
Hook 有執行但不會阻擋
症狀: 你的 PreToolUse hook 有執行,但動作仍會繼續進行。
修正方式:
- 結束代碼錯誤,結束代碼 1 代表「錯誤」(hook 失敗),而非「阻擋」。請使用
exit 2來阻擋動作。正如官方文件所述,幾乎所有人都會踩到這個坑。 - 缺少 stdout JSON,對於阻擋型 hook,請輸出一則 JSON 訊息,讓 Claude 知道動作被阻擋的原因:
echo '{"message": "Blocked: reason"}'
無限迴圈
症狀: Claude 不斷重試相同的操作,或是你的機器異常發熱。
修復方式:
- Stop hook 觸發了動作,如果你的 Stop hook 會寫入檔案或執行指令,導致 Claude 做出回應,那就形成了迴圈。Stop hook 應該只做被動的事:記錄、通知、清理。
- PostToolUse hook 引發編輯,會修改檔案的 PostToolUse hook 會觸發另一個 PostToolUse 事件。請使用特定的 matcher 或
if欄位來防範這種情況。
效能問題
症狀: Claude 啟動或執行工具的時間明顯變長。
解決方法:
- SessionStart 掛鉤過多,每一個掛鉤都會在啟動時同步執行。請保持輕量化(每個不超過 1 秒)。
- 高頻路徑中有繁重的腳本,PreToolUse 和 PostToolUse 的掛鉤會頻繁觸發。如果你的腳本涉及網路請求或大量運算,請加上
timeout欄位(毫秒),並考慮是否應改用 HTTP 掛鉤。 - 缺少快取,如果你重複檢查相同的項目(例如「這是受保護的分支嗎?」),請將結果快取到暫存檔中,而不是在每次掛鉤觸發時都執行 Git 指令。
常見問題
什麼是 Claude Code hooks?它們如何運作?
Claude Code hooks 是使用者自訂的自動化腳本,會在 Claude Code 工作階段的特定生命週期事件觸發時執行。你可以在 settings.json 中設定 matcher 模式與 handler(shell 指令、HTTP 端點、prompt 或 agent)。當符合條件的事件觸發時,hook 會自動執行,並透過 exit code 來控制結果。
如何在 Claude Code 的 settings.json 中設定 hooks?
在以下三個設定檔位置中任選其一,加入 "hooks" 物件:~/.claude/settings.json(使用者全域)、.claude/settings.json(專案共用)或 .claude/settings.local.json(專案個人)。每個事件類型會對應一組 hook 定義陣列,其中包含 matcher、選用的 if 欄位,以及一個 hooks 陣列,該陣列內含具備 type 與 command 或 url 的處理常式物件。
PreToolUse 和 PostToolUse 掛鉤有什麼區別?
PreToolUse 會在工具執行之前觸發,讓你能夠透過結束代碼 2 來阻止它。PostToolUse 則在執行完成之後觸發,適用於格式化、測試或記錄。PreToolUse 用於預防與控管,PostToolUse 用於驗證與清理。兩者都會透過 stdin 以 JSON 格式接收工具名稱與輸入。
Claude Code 的 hooks 能阻擋危險指令嗎?
可以。設定為 exit code 2 的 PreToolUse hooks 能阻擋任何工具的執行。你可以保護敏感檔案不被寫入、阻擋符合危險模式的 shell 指令(例如 rm -rf 或 git push main),並防止存取生產環境資料庫。阻擋訊息會作為回饋傳回給 Claude,讓它據此調整做法。
Claude Code 提供了哪些 hook 事件?
Claude Code 提供了 15 種以上的事件:PreToolUse 和 PostToolUse 用於工具執行、Notification 用於警示、Stop 用於工作階段結束、SessionStart 用於初始化、UserPromptSubmit 用於輸入過濾、PreCompact 和 PostCompact 用於情境管理,以及較新的事件如 ConfigChange、FileChanged、TaskCreated 和 PermissionDenied。完整參考表格請見上方的 hook 事件章節。
Hooks 與 MCP 工具和 Skills 有何不同?
Hooks 是確定性的——無論 Claude 如何判斷,只要事件符合條件就一定會觸發。MCP 工具擴展了 Claude 的能力(資料庫存取、API 呼叫),但由 Claude 自行決定何時使用。Skills 是透過斜線指令呼叫的可重複使用指令套件。CLAUDE.md 則提供行為指引。當某件事必須每次都執行時,請使用 hooks;當 Claude 需要新能力時,則使用 MCP。
Claude Code 的 hooks 在 headless 模式下能正常運作嗎?
可以,但有幾點需要注意。Hooks 在 headless 模式(claude -p)下會正常觸發,但像是 macOS 通知這類桌面專屬的 hooks 則需要備用方案。重要的是,以結束代碼 2 退出的 PreToolUse hooks 能夠暫停 headless 工作階段,並透過 --resume 交由人工核准。這使得「人在迴路中」(human-in-the-loop)的 CI/CD 流程得以實現,讓特定操作需要經過人工簽核。
多少個 hook 算太多?hook 會拖慢 Claude Code 嗎?
沒有硬性上限,但每個同步 hook 都會增加延遲。SessionStart hook 會在啟動時執行,所以請保持輕量(每個不超過 1 秒)。PreToolUse 和 PostToolUse hook 會在每次符合條件的工具呼叫時觸發,這裡若放置沉重的腳本,延遲會迅速累積。建議將 hook 總數控制在 10–15 個以內,使用 if 欄位來縮小作用範圍,並加上 timeout 值以防止腳本失控。
我可以使用 hooks 搭配 Prettier 或 Black 來自動格式化程式碼嗎?
可以,這是最受歡迎的 hook 使用情境。建立一個符合 Write|Edit 的 PostToolUse hook,從 stdin JSON 中提取檔案路徑,再根據副檔名執行對應的格式化工具。完整且可直接複製貼上的設定範例(涵蓋 TypeScript、JavaScript 和 Python 檔案),請參閱生產環境範例章節中的第一個範例。
Claude Code 的 Hooks 安全嗎?有哪些安全風險?
Hooks 以你完整的用戶權限執行,沒有沙箱隔離。惡意的 hook 可能讀取你的 SSH 金鑰、刪除檔案,或外洩資料。請只使用來自可信來源的 hooks,在將任何共享的 .claude/settings.json 納入專案之前務必先行檢視,並使用 .claude/settings.local.json 來存放不應共享的個人 hooks。若想了解更廣泛的 AI 安全模式,請參閱我們的 LLM 防護指南。