Claude Code 的 Hooks(事件掛鉤)是一套強大的自動化機制,讓你可以在 Claude Code 的生命週期中插入自訂邏輯。無論是在工具執行前進行安全檢查、在檔案寫入後自動執行格式化、還是在 Session 啟動時初始化環境變數,Hooks 都能幫你實現。透過在 settings.json 中設定 Shell 指令、HTTP 請求、Prompt 或 Agent,你可以完全掌控 Claude Code 的行為,打造符合團隊需求的自動化工作流程。
什麼是 Hooks
Hooks 是使用者定義的自動化處理程式,會在 Claude Code 生命週期的特定時間點自動觸發執行。你可以把它想像成程式開發中的「事件監聽器」——當 Claude Code 執行特定動作(如使用工具、啟動 Session、完成回應)時,你預先設定好的 Hook 就會自動執行。
Hooks 支援四種處理類型:
- Command Hooks:執行 Shell 指令,透過 stdin 接收事件資料,用 exit code 和 stdout 回傳結果
- HTTP Hooks:發送 JSON POST 請求到指定的 URL 端點,適合整合外部服務
- Prompt Hooks:將事件資料送給 Claude 模型評估,回傳 yes/no 決策
- Agent Hooks:啟動子代理進行驗證,可使用 Read、Grep、Glob 等工具
每種類型都有各自適合的應用場景。Command Hooks 最靈活且常用,適合大部分自動化需求;HTTP Hooks 適合與外部審批系統整合;Prompt Hooks 讓 AI 幫你做智慧判斷;Agent Hooks 則適合需要深入分析程式碼的驗證任務。
Hooks 的設定方式
Hooks 的設定統一放在 settings.json 中,根據適用範圍的不同,可以放在以下位置:
| 位置 | 路徑 | 適用範圍 |
|---|---|---|
| 使用者設定 | ~/.claude/settings.json | 所有專案(僅本機) |
| 專案設定 | .claude/settings.json | 此專案(可提交到版本控制) |
| 專案本機設定 | .claude/settings.local.json | 此專案(僅本機) |
| 企業管理設定 | Managed policy settings | 整個組織 |
| Plugin Hooks | hooks/hooks.json | 啟用該 Plugin 時 |
基本的設定結構如下,每個事件名稱下可以設定多組 matcher 和 hooks:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/check-bash.sh",
"timeout": 30
}
]
}
]
}
}
其中 matcher 欄位用來過濾觸發條件,支援正規表達式語法。例如 Bash 只匹配 Bash 工具、Edit|Write 匹配 Edit 或 Write 工具、mcp__.* 匹配所有 MCP 工具。沒有設定 matcher 的事件(如 Stop、UserPromptSubmit)會在每次事件發生時都觸發。
Hook 的生命週期事件
Claude Code 的 Hooks 涵蓋了整個使用生命週期,從 Session 啟動到結束,每個階段都有對應的事件可以掛鉤。以下是主要的事件分類:
Session 階段
| 事件 | 觸發時機 | Matcher |
|---|---|---|
SessionStart | Session 啟動或恢復時 | startup、resume、clear、compact |
InstructionsLoaded | CLAUDE.md 或規則檔案載入時 | session_start、nested_traversal、include |
Notification | Claude 發送通知時 | notification(對話繼續需要注意) |
Stop | Claude 完成回應時 | end_turn(主動結束)或 max_turns(達到上限) |
工具執行階段(最常用)
| 事件 | 觸發時機 | 可否阻擋 |
|---|---|---|
PreToolUse | 工具執行之前 | 可以(allow/deny/ask) |
PostToolUse | 工具執行成功之後 | 可以回饋訊息 |
PostToolUseFailure | 工具執行失敗之後 | 可提供額外上下文 |
PermissionRequest | 權限對話框出現時 | 可自動允許或拒絕 |
PermissionDenied | Auto mode 拒絕工具呼叫時 | 可要求重試 |
回應與通知階段
| 事件 | 觸發時機 | 說明 |
|---|---|---|
UserPromptSubmit | 使用者提交 Prompt 時 | 可過濾或阻擋特定內容 |
Stop | Claude 完成回應時 | 可阻擋讓 Claude 繼續工作 |
StopFailure | API 錯誤導致中止時 | 用於錯誤監控與通知 |
Notification | Claude 發送通知時 | 可自訂通知行為 |
SubagentStart / SubagentStop | 子代理啟動或結束時 | 可注入額外上下文 |
PreToolUse:工具執行前的守門員
PreToolUse 是最重要也最常用的 Hook 事件,因為它是唯一能夠在工具執行前攔截並阻擋操作的事件。當 Claude 準備使用任何工具(Bash、Edit、Write、Read 等)時,PreToolUse Hook 會先被觸發,你可以在這裡進行安全檢查、自動審批或修改工具輸入。
Hook 接收到的輸入 JSON 包含工具名稱和工具參數:
{
"session_id": "abc123",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": {
"command": "rm -rf node_modules",
"description": "Remove node_modules"
},
"tool_use_id": "toolu_01ABC..."
}
Hook 可以透過輸出 JSON 來控制 Claude 的行為,最關鍵的是 permissionDecision 欄位,支援四種決策:
| 決策 | 效果 | 適用場景 |
|---|---|---|
allow | 允許工具執行,跳過權限提示 | 自動核准安全指令 |
deny | 阻擋工具執行 | 封鎖危險操作 |
ask | 強制顯示權限提示 | 敏感操作需要人工確認 |
defer | 不做決定,交由下一個 Hook 或預設行為處理 | 條件不匹配時 |
以下是一個封鎖危險 Bash 指令的 PreToolUse Hook 範例:
#!/bin/bash
# .claude/hooks/block-dangerous.sh
# 從 stdin 讀取事件 JSON
COMMAND=$(jq -r '.tool_input.command' < /dev/stdin)
# 檢查是否包含危險指令
if echo "$COMMAND" | grep -qE 'rm -rf /|mkfs|dd if=|:(){ :|&}'; then
# 輸出 JSON 阻擋執行
jq -n '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "偵測到危險指令,已自動阻擋"
}
}'
else
# exit 0 且不輸出 JSON 表示不干預
exit 0
fi
對應的 settings.json 設定:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-dangerous.sh",
"timeout": 10
}
]
}
]
}
}
PostToolUse:工具執行後的品質把關
PostToolUse 在工具成功執行之後觸發,適合用來進行後處理作業,例如自動格式化程式碼、執行 Lint 檢查、記錄操作日誌等。與 PreToolUse 不同的是,PostToolUse 無法阻擋已完成的操作,但可以將檢查結果回饋給 Claude,讓 Claude 根據結果調整後續行為。
PostToolUse Hook 接收到的 JSON 除了 tool_input 外,還包含 tool_response(工具執行結果):
{
"hook_event_name": "PostToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "/project/src/utils.ts",
"content": "..."
},
"tool_response": {
"filePath": "/project/src/utils.ts",
"success": true
}
}
以下是一個在檔案寫入後自動執行 ESLint 檢查的範例:
#!/bin/bash
# .claude/hooks/auto-lint.sh
FILE_PATH=$(jq -r '.tool_input.file_path' < /dev/stdin)
# 只對 TypeScript 和 JavaScript 檔案執行
if [[ "$FILE_PATH" == *.ts ]] || [[ "$FILE_PATH" == *.tsx ]] || \
[[ "$FILE_PATH" == *.js ]] || [[ "$FILE_PATH" == *.jsx ]]; then
LINT_RESULT=$(npx eslint "$FILE_PATH" 2>&1)
if [ $? -ne 0 ]; then
# 將 Lint 錯誤回饋給 Claude
jq -n --arg ctx "$LINT_RESULT" '{
hookSpecificOutput: {
hookEventName: "PostToolUse",
additionalContext: ("ESLint 檢查發現問題,請修正:\n" + $ctx)
}
}'
fi
fi
exit 0
設定方式如下,使用 Edit|Write 作為 matcher 來同時匹配編輯和寫入操作:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/auto-lint.sh"
}
]
}
]
}
}
Notification Hook:自訂通知行為
Notification 事件在 Claude Code 發送通知時觸發,例如等待使用者輸入、需要權限確認、驗證成功等情境。你可以透過 matcher 過濾特定類型的通知:
| Matcher 值 | 觸發時機 |
|---|---|
permission_prompt | Claude 需要使用者授權工具時 |
idle_prompt | Claude 等待使用者輸入時 |
auth_success | 驗證成功時 |
elicitation_dialog | MCP Server 請求輸入時 |
以下範例在 Claude 等待權限確認時,自動發送桌面通知提醒你:
#!/bin/bash
# .claude/hooks/desktop-notify.sh
INPUT=$(cat)
MESSAGE=$(echo "$INPUT" | jq -r '.message')
TITLE=$(echo "$INPUT" | jq -r '.title // "Claude Code"')
# macOS 桌面通知
if command -v osascript &> /dev/null; then
osascript -e "display notification \"$MESSAGE\" with title \"$TITLE\""
fi
# Linux 桌面通知
if command -v notify-send &> /dev/null; then
notify-send "$TITLE" "$MESSAGE"
fi
exit 0
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/desktop-notify.sh",
"async": true
}
]
}
]
}
}
注意這裡使用了 "async": true,讓通知腳本在背景執行,不會阻塞 Claude Code 的主流程。
Hook 的四種處理類型詳解
Command Hook:Shell 指令
Command Hook 是最基本也最靈活的類型,透過執行 Shell 指令來處理事件。事件的 JSON 資料會透過 stdin 傳入,Hook 透過 exit code 和 stdout 回傳結果。
| Exit Code | 意義 | JSON 處理 |
|---|---|---|
0 | 成功 | 解析 stdout 的 JSON |
2 | 阻擋性錯誤 | 忽略 JSON,使用 stderr 訊息 |
| 其他 | 非阻擋性錯誤 | 忽略 JSON,在 verbose 模式顯示 stderr |
{
"type": "command",
"command": ".claude/hooks/my-hook.sh",
"shell": "bash",
"timeout": 30,
"async": false
}
HTTP Hook:遠端服務整合
HTTP Hook 將事件 JSON 以 POST 請求發送到指定的 URL,非常適合與團隊的審批系統、日誌服務或監控平台整合。支援自訂 Headers 和環境變數插值:
{
"type": "http",
"url": "https://approval.example.com/hooks/validate",
"headers": {
"Authorization": "Bearer $MY_API_TOKEN"
},
"allowedEnvVars": ["MY_API_TOKEN"],
"timeout": 10
}
遠端端點回傳的 JSON 格式與 Command Hook 相同,非 2xx 回應碼會被視為非阻擋性錯誤。
Prompt Hook:AI 智慧判斷
Prompt Hook 將事件資料送給 Claude 模型,讓 AI 做出 allow 或 deny 的智慧判斷。使用 $ARGUMENTS 占位符來插入事件 JSON:
{
"type": "prompt",
"prompt": "審查以下 Shell 指令是否安全。如果指令可能刪除重要檔案、修改系統設定或存取敏感資料,回答 deny;否則回答 allow。指令內容:$ARGUMENTS",
"timeout": 30
}
Agent Hook:子代理驗證
Agent Hook 會啟動一個子代理來進行更深入的驗證,子代理可以使用 Read、Grep、Glob 等工具來分析程式碼,適合需要理解上下文才能做出判斷的場景:
{
"type": "agent",
"prompt": "驗證這個指令是否符合專案的安全政策。檢查 .claude/SECURITY.md 中的規則,並確認指令不會違反任何安全限制。指令內容:$ARGUMENTS",
"timeout": 60
}
共用設定欄位參考
所有類型的 Hook 都支援以下共用欄位:
| 欄位 | 必填 | 說明 |
|---|---|---|
type | 是 | 處理類型:command、http、prompt 或 agent |
if | 否 | 額外的過濾條件,使用權限規則語法,例如 Bash(git *) |
timeout | 否 | 逾時秒數,預設值依類型不同(Command: 600s、HTTP: 30s、Prompt: 30s、Agent: 60s) |
statusMessage | 否 | 執行時顯示的自訂 Spinner 訊息 |
once | 否 | 設為 true 時每個 Session 只執行一次(僅限 Skill 中的 Hook) |
if 欄位特別有用,它讓你可以在 matcher 的基礎上進一步過濾。例如你想只針對 rm 開頭的 Bash 指令觸發 Hook,可以設定 "if": "Bash(rm *)",這樣 ls 或 git status 等指令就不會觸發。
Hook 中可用的環境變數
Claude Code 會在執行 Hook 時提供幾個實用的環境變數:
| 變數 | 說明 |
|---|---|
$CLAUDE_PROJECT_DIR | 專案根目錄路徑(建議用雙引號包裹,以處理路徑中的空格) |
${CLAUDE_PLUGIN_ROOT} | Plugin 安裝目錄 |
${CLAUDE_PLUGIN_DATA} | Plugin 持久化資料目錄 |
CLAUDE_ENV_FILE 是一個特殊的環境變數,只在特定事件中可用。你可以透過寫入這個檔案來持久化環境變數,讓後續的 Claude Code 操作都能存取到這些變數:
#!/bin/bash
# 在 SessionStart hook 中初始化環境
if [ -n "$CLAUDE_ENV_FILE" ]; then
# 載入 nvm 並設定 Node 版本
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
nvm use 18
# 將環境變數寫入持久化檔案
echo 'export NODE_ENV=development' >> "$CLAUDE_ENV_FILE"
echo 'export DEBUG=app:*' >> "$CLAUDE_ENV_FILE"
fi
exit 0
實戰應用範例
範例一:自動核准安全指令
在日常開發中,你可能會頻繁使用 git status、npm test、ls 等安全指令,每次都需要手動確認權限會降低效率。以下 Hook 可以自動核准這些安全指令:
#!/bin/bash
# .claude/hooks/approve-safe-commands.sh
COMMAND=$(jq -r '.tool_input.command' < /dev/stdin)
# 定義安全指令的模式
if [[ "$COMMAND" =~ ^(npm|yarn|pnpm).*(test|lint|build|check) ]] || \
[[ "$COMMAND" =~ ^git.*(status|log|diff|branch|tag) ]] || \
[[ "$COMMAND" =~ ^(ls|pwd|cat|head|tail|wc|echo) ]]; then
jq -n '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "allow",
permissionDecisionReason: "安全的唯讀指令,已自動核准"
}
}'
else
exit 0
fi
範例二:操作日誌記錄
在團隊或企業環境中,記錄 Claude Code 的所有操作是很重要的合規需求。以下 Hook 會將每次工具使用記錄到日誌檔:
#!/bin/bash
# .claude/hooks/audit-log.sh
INPUT=$(cat)
EVENT=$(echo "$INPUT" | jq -r '.hook_event_name')
TOOL=$(echo "$INPUT" | jq -r '.tool_name // "N/A"')
SESSION=$(echo "$INPUT" | jq -r '.session_id')
CWD=$(echo "$INPUT" | jq -r '.cwd')
# 記錄到日誌檔
LOG_DIR="$CLAUDE_PROJECT_DIR/.claude/logs"
mkdir -p "$LOG_DIR"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Event=$EVENT Tool=$TOOL Session=$SESSION CWD=$CWD" \
>> "$LOG_DIR/audit.log"
exit 0
將這個 Hook 同時掛載到 PreToolUse 和 PostToolUse 事件,就能完整記錄所有工具的使用情況:
{
"hooks": {
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/audit-log.sh",
"async": true
}
]
}
],
"PostToolUse": [
{
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/audit-log.sh",
"async": true
}
]
}
]
}
}
範例三:Prompt 內容過濾
在企業環境中,你可能需要防止 Claude 接收包含敏感資訊的 Prompt。以下 Hook 使用 UserPromptSubmit 事件來過濾使用者輸入:
#!/bin/bash
# .claude/hooks/filter-prompts.sh
PROMPT=$(jq -r '.prompt' < /dev/stdin)
# 檢查是否包含敏感關鍵字
if echo "$PROMPT" | grep -qi 'password\|api.key\|secret\|credential'; then
jq -n '{
decision: "block",
reason: "Prompt 中包含敏感資訊關鍵字,請移除後再試"
}'
else
exit 0
fi
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/filter-prompts.sh"
}
]
}
]
}
}
範例四:Session 啟動環境初始化
利用 SessionStart Hook 在每次啟動 Claude Code 時自動初始化開發環境,載入專案所需的環境變數和工具版本:
#!/bin/bash
# .claude/hooks/init-env.sh
if [ -n "$CLAUDE_ENV_FILE" ]; then
# 載入 .env 檔案中的環境變數
if [ -f "$CLAUDE_PROJECT_DIR/.env" ]; then
while IFS= read -r line; do
[[ "$line" =~ ^#.*$ ]] && continue
[[ -z "$line" ]] && continue
echo "export $line" >> "$CLAUDE_ENV_FILE"
done < "$CLAUDE_PROJECT_DIR/.env"
fi
# 設定專案特定的工具路徑
echo "export PATH=$CLAUDE_PROJECT_DIR/node_modules/.bin:\$PATH" >> "$CLAUDE_ENV_FILE"
fi
# 回傳環境資訊給 Claude
jq -n '{
hookSpecificOutput: {
hookEventName: "SessionStart",
additionalContext: "開發環境已初始化。.env 已載入,node_modules/.bin 已加入 PATH。"
}
}'
{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/init-env.sh"
}
]
}
]
}
}
除錯與管理 Hooks
Claude Code 提供了幾個實用的工具來幫助你除錯和管理 Hooks:
查看已設定的 Hooks:在 Claude Code 中輸入 /hooks 指令,會在瀏覽器中開啟一個頁面,顯示所有已設定的 Hooks 及其來源(User、Project、Local、Plugin、Session 或 Built-in)。
停用所有 Hooks:如果你需要暫時停用所有 Hooks(例如排除問題時),可以在 settings.json 中加入:
{
"disableAllHooks": true
}
注意,這個設定會遵循設定層級,企業管理層級設定的 Hooks 只能透過企業管理設定中的 disableAllHooks 來停用。
輸出上限:Hook 的 JSON 輸出有 10,000 字元的上限。超過此限制的內容會被儲存到檔案中,不會直接傳遞給 Claude。因此建議保持 Hook 輸出簡潔,只回傳必要的資訊。
常見問題與疑難排解
| 問題 | 解決方案 |
|---|---|
| Hook 沒有觸發 | 確認 matcher 正確匹配工具名稱(區分大小寫),使用 /hooks 確認 Hook 已載入 |
| Hook 觸發了但沒有效果 | 確認 exit code 為 0,且 stdout 輸出的是合法的 JSON 格式 |
| Hook 執行太慢 | 設定較短的 timeout,或使用 "async": true 在背景執行 |
| JSON 解析錯誤 | 使用 jq -n 來生成 JSON 而非手動拼接字串,確保特殊字元被正確跳脫 |
| 環境變數無法存取 | 確認 Hook 腳本有可執行權限(chmod +x),且 $CLAUDE_PROJECT_DIR 路徑正確 |
| PreToolUse 的 allow/deny 無效 | 使用 hookSpecificOutput.permissionDecision 而非頂層的 decision 欄位 |
Hooks 最佳實踐
- 保持 Hook 腳本簡短快速:Hook 會阻塞 Claude Code 的主流程(除非使用 async),長時間執行的腳本會影響使用體驗。非必要的後處理可以使用
"async": true - 善用 matcher 和 if 過濾:避免對所有工具呼叫都觸發 Hook,只針對特定工具和特定模式觸發,減少不必要的開銷
- 使用 jq 處理 JSON:Hook 的輸入和輸出都是 JSON 格式,
jq是處理 JSON 的最佳工具,避免用字串操作來解析或生成 JSON - 正確處理 exit code:exit 0 表示成功、exit 2 表示阻擋性錯誤、其他值表示非阻擋性錯誤。確保你的腳本在所有路徑上都有正確的 exit code
- 將安全相關的 Hook 放在專案設定中:將
.claude/hooks/目錄和.claude/settings.json提交到版本控制,確保團隊所有成員都使用相同的安全規則 - 測試 Hook 腳本:在正式使用之前,先用
echo '{"tool_name":"Bash","tool_input":{"command":"test"}}' | ./hook.sh手動測試你的 Hook 腳本是否正確運作
總結
Hooks 是 Claude Code 中實現自動化工作流程的核心機制。透過 PreToolUse 你可以建立安全防線,透過 PostToolUse 你可以自動化品質檢查,透過 SessionStart 你可以初始化開發環境,透過 Notification 你可以自訂通知行為。四種處理類型(Command、HTTP、Prompt、Agent)讓你能夠靈活地整合各種工具和服務,無論是本地腳本還是遠端 API 都能輕鬆對接。
建議從最簡單的 Command Hook 開始,先建立一個自動核准安全指令的 PreToolUse Hook 來提升日常開發效率,再根據團隊需求逐步擴展到日誌記錄、程式碼品質檢查等進階應用。
延伸閱讀
- Claude Code 是什麼?完整介紹與安裝教學
- Claude Code 新手上路:第一次使用就上手
- CLAUDE.md 專案記憶:讓 Claude 記住你的專案規範
- Claude Code CLI 指令完整參考
- Context 管理與 Token 優化技巧
- Slash Commands 與快捷鍵完整指南
- Custom Skills:打造你的專屬自訂技能
- Claude Code Hooks 官方文件