什麼是 Hooks?
想像你僱了一個非常能幹的 AI 助手。它可以讀寫檔案、執行命令、搜尋程式碼。但你不想讓它毫無限制地做任何事——你想要護欄。
Hooks 就是這些護欄。它們是你預先定義的規則,在 Claude Code 的生命週期中自動觸發。不需要你每次下指令,不需要 AI「記得」要遵守——它們是確定性的(deterministic),100% 會執行。
一個簡單的例子:
// 每次 Claude 要執行 Shell 命令之前,自動檢查是否有 rm -rf
PreToolUse → matcher: "Bash" → 你的腳本檢查命令內容 → 阻止或放行
這就是 Hooks 的核心:在 AI 做事之前或之後,插入你的邏輯。
14 種事件:完整的生命週期覆蓋
Claude Code 的每個操作都被拆解為事件。你可以在任何一個節點掛上 Hook。
Session 生命週期
| 事件 | 觸發時機 | 可阻止? | 典型用途 |
|---|---|---|---|
| SessionStart | 對話開始或恢復時 | 否 | 載入環境變數、偵測專案類型 |
| SessionEnd | 對話結束時 | 否 | 清理暫存檔、紀錄統計 |
| PreCompact | Context 壓縮前 | 否 | 保存重要上下文、注入摘要 |
使用者互動
| 事件 | 觸發時機 | 可阻止? | 典型用途 |
|---|---|---|---|
| UserPromptSubmit | 使用者送出訊息,Claude 處理前 | 是 | 輸入驗證、敏感資訊過濾 |
| Notification | Claude 發送通知時 | 否 | macOS 原生通知、Slack 推播 |
工具執行(最常用)
| 事件 | 觸發時機 | 可阻止? | 典型用途 |
|---|---|---|---|
| PreToolUse ⭐ | 工具執行之前 | 是 | 安全檢查、自動核准、參數修改 |
| PermissionRequest | 權限對話框即將出現時 | 是 | 自動核准安全操作、攔截危險操作 |
| PostToolUse | 工具執行成功之後 | 否 | 自動格式化、觸發測試 |
| PostToolUseFailure | 工具執行失敗之後 | 否 | 錯誤紀錄、自動重試邏輯 |
Agent 與任務管理
| 事件 | 觸發時機 | 可阻止? | 典型用途 |
|---|---|---|---|
| Stop | Claude 完成回應時 | 是 | 檢查任務是否真的完成 |
| SubagentStart | 子 Agent 啟動時 | 否 | 安全驗證、資源管控 |
| SubagentStop | 子 Agent 完成時 | 是 | 輸出品質驗證 |
| TeammateIdle | 團隊中的 Agent 即將閒置 | 是 | 品質閘門、防止過早結束 |
| TaskCompleted | 任務即將標記為完成 | 是 | 完成條件驗證 |
3 種 Hook 類型
1. Command Hook(Shell 命令)
最常用的類型。執行一個 Shell 腳本,透過 stdin 接收 JSON 輸入,用 exit code 控制行為。
{
"type": "command",
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/security_check.py",
"timeout": 60
}
適合:快速確定性檢查、檔案操作、外部工具整合。
2. Prompt Hook(LLM 判斷)
把決策交給一個輕量 LLM(通常是 Haiku)。它會根據 context 做出 yes/no 判斷。
{
"type": "prompt",
"prompt": "檢查以下操作是否安全:$ARGUMENTS。如果涉及刪除或修改系統檔案,回傳 deny。",
"timeout": 30
}
適合:需要理解語意的判斷(例如「這段程式碼看起來有安全風險嗎?」)。
3. Agent Hook(多步驟驗證)
啟動一個有工具存取權(Read、Grep、Glob)的子 Agent,最多 50 個 tool-use 回合。
{
"type": "agent",
"prompt": "驗證修改是否符合專案規範:$ARGUMENTS",
"timeout": 60
}
適合:複雜的多步驟驗證(例如檢查修改是否破壞其他檔案的相依性)。
三種類型比較
| 面向 | Command | Prompt | Agent |
|---|---|---|---|
| 速度 | < 1 秒 | 3-30 秒 | 10-60 秒 |
| 邏輯類型 | 確定性規則 | 語意判斷 | 多步驟推理 |
| 額外成本 | 無 | API tokens | API tokens(更多) |
| 可讀取檔案 | 透過腳本 | 只看 context | Read/Grep/Glob |
| 支援 async | 是 | 否 | 否 |
Exit Code:Hook 的溝通語言
Command Hook 透過 exit code 告訴 Claude Code 下一步該怎麼做:
| Exit Code | 意義 | 行為 |
|---|---|---|
| 0 | 成功 | 放行。stdout 的 JSON 會被解析處理 |
| 2 | 阻止 | 操作被攔截。stderr 的文字回饋給 Claude |
| 其他 | 非阻止性錯誤 | 操作照常進行,stderr 只在 verbose 模式顯示 |
這個設計的精妙之處:exit code 2 的 stderr 會直接回饋給 Claude,所以 AI 會「看到」你的攔截原因並據此調整行為。例如:
#!/bin/bash
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command // empty')
# 攔截 rm -rf
if [[ "$command" == *"rm -rf"* ]]; then
echo "禁止使用 rm -rf。請使用更安全的刪除方式。" >&2
exit 2 # Claude 會看到這個訊息,改用其他方法
fi
exit 0 # 放行
PreToolUse:最強大的事件
PreToolUse 是 Hooks 系統的核心。它在權限系統之前執行,擁有三種決策能力:
// JSON 輸出(exit 0 時)
{
"hookSpecificOutput": {
"permissionDecision": "allow", // 或 "deny" 或 "ask"
"permissionDecisionReason": "此操作已由 Hook 自動核准",
"updatedInput": { // 可以修改工具參數!
"command": "npm run lint --fix"
}
}
}
"allow"— 直接放行,跳過權限對話框(使用者不會被詢問)"deny"— 直接阻止,理由回饋給 Claude"ask"— 交給使用者決定(顯示權限對話框)
updatedInput 更厲害——你可以偷偷修改 Claude 要執行的命令。例如強制加上 --dry-run 或修改檔案路徑。
配置層級
Hooks 可以在多個層級定義,優先順序由低到高:
| 位置 | 範圍 | 可共享? |
|---|---|---|
~/.claude/settings.json |
所有專案(全域) | 否(本機) |
.claude/settings.json |
單一專案 | 是(可 commit) |
.claude/settings.local.json |
單一專案 | 否(gitignored) |
Plugin hooks/hooks.json |
Plugin 啟用時 | 是(隨 Plugin) |
| Skill/Agent YAML frontmatter | 元件執行時 | 是(定義在元件中) |
| 組織管理政策 | 全組織 | 是(管理員控制) |
配置範例(.claude/settings.json):
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/validate-bash.sh"
}
]
},
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/protect-files.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write",
"async": true
}
]
}
],
"Notification": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude 需要你的注意\" with title \"Claude Code\"'"
}
]
}
]
}
}
環境變數
| 變數 | 可用範圍 | 用途 |
|---|---|---|
$CLAUDE_PROJECT_DIR |
所有 Hook | 專案根目錄路徑 |
${CLAUDE_PLUGIN_ROOT} |
Plugin Hook | Plugin 根目錄(可攜式路徑) |
$CLAUDE_ENV_FILE |
僅 SessionStart | 寫入此檔案可持久化環境變數 |
$CLAUDE_CODE_REMOTE |
所有 Hook | 遠端環境時設為 "true" |
$CLAUDE_ENV_FILE 是 SessionStart 的獨特能力。寫入這個檔案的環境變數,會在整個 Session 中持續生效:
#!/bin/bash
# SessionStart Hook:自動偵測專案類型
cd "$CLAUDE_PROJECT_DIR" || exit 1
if [ -f "package.json" ]; then
echo "export PROJECT_TYPE=nodejs" >> "$CLAUDE_ENV_FILE"
echo "export NODE_ENV=development" >> "$CLAUDE_ENV_FILE"
elif [ -f "Cargo.toml" ]; then
echo "export PROJECT_TYPE=rust" >> "$CLAUDE_ENV_FILE"
elif [ -f "requirements.txt" ]; then
echo "export PROJECT_TYPE=python" >> "$CLAUDE_ENV_FILE"
fi
exit 0
Matcher:精準過濾
Matcher 使用正規表達式決定 Hook 在哪些工具上觸發:
| Pattern | 匹配對象 |
|---|---|
Bash |
只匹配 Bash 工具 |
Edit|Write |
Edit 或 Write 工具 |
mcp__.* |
所有 MCP 工具 |
mcp__rss__.* |
RSS MCP 的所有工具 |
* 或省略 |
所有工具 |
bash 不會匹配 Bash,而且不會有任何錯誤提示——Hook 就是靜默地不觸發。這是最常見的配置錯誤。
10 個實戰場景
1. 阻止危險的 Shell 命令
// PreToolUse + matcher: "Bash"
// 攔截 rm -rf、git push --force、DROP TABLE 等
2. 保護敏感檔案
// PreToolUse + matcher: "Edit|Write"
// 阻止修改 .env、credentials.json、*.pem
3. 自動格式化程式碼
// PostToolUse + matcher: "Edit|Write" + async: true
// 修改檔案後自動跑 prettier / black / rustfmt
4. 桌面通知
// Notification + command
// Claude 需要你注意時,發送 macOS 原生通知或 Slack 訊息
5. 自動設定開發環境
// SessionStart + CLAUDE_ENV_FILE
// 偵測專案類型,自動載入對應的環境變數
6. 安全掃描(我們在用的)
// PreToolUse + matcher: "Edit|Write|MultiEdit"
// 每次修改檔案前,掃描 SQL injection、XSS、command injection
7. 自動核准安全操作
// PreToolUse + matcher: "Bash"
// ls、pwd、echo、git status 等安全命令自動放行,不再彈權限對話框
8. 非同步測試
// PostToolUse + matcher: "Write|Edit" + async: true
// 修改檔案後在背景自動跑測試,不阻塞 Claude 繼續工作
9. 任務完成驗證
// Stop + type: "prompt"
// Claude 說「完成了」之前,讓 LLM 檢查是否真的全部做完
10. MCP 工具限流
// PreToolUse + matcher: "mcp__.*"
// 限制 MCP 工具的呼叫頻率,避免打爆外部 API
限制與注意事項
1. 啟動時快照,Session 中不可修改
Claude Code 在啟動時擷取 Hooks 的快照。Session 進行中修改設定檔不會生效,必須重啟或在 /hooks 選單中重新載入。這是安全設計,防止 Session 中途被注入惡意 Hook。
2. Stop Hook 無限迴圈
Stop Hook 可以阻止 Claude 停止,導致它繼續對話然後再次觸發 Stop,形成迴圈。必須檢查 stop_hook_active:
#!/bin/bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
exit 0 # 已在 Stop Hook 中,直接放行
fi
# ... 你的檢查邏輯
3. Shell Profile 污染
.zshrc 或 .bashrc 中的 echo 輸出會污染 JSON 解析,導致 Hook 靜默失敗。解法:
# 在 .zshrc 中,只在互動模式才輸出
if [[ $- == *i* ]]; then
echo "Shell ready"
fi
4. PostToolUse 無法撤銷
PostToolUse 在工具已經執行完之後才觸發。它能記錄、能通知,但不能撤銷已經發生的操作。想攔截必須用 PreToolUse。
5. PermissionRequest 不在 Headless 模式觸發
用 claude -p(headless/非互動模式)時,PermissionRequest Hook 不會觸發。CI/CD 場景要改用 PreToolUse。
6. 平行執行,無法互相依賴
同一事件的多個 Hook 平行執行,不保證順序。不能讓 Hook A 的結果影響 Hook B。
7. Exit Code 與 JSON 互斥
Exit code 2 時,stdout 的 JSON 會被忽略。想用 JSON 控制行為,必須 exit 0。兩者不能混用。
完整的 stdin 輸入格式
每個 Hook 透過 stdin 接收 JSON。所有事件共享的基礎欄位:
{
"session_id": "abc123",
"transcript_path": "/path/to/transcript.json",
"cwd": "/current/working/dir",
"permission_mode": "default", // default|plan|acceptEdits|dontAsk|bypassPermissions
"hook_event_name": "PreToolUse"
}
各事件會加上自己的特定欄位:
- PreToolUse / PostToolUse:
tool_name、tool_input(如file_path、command) - UserPromptSubmit:
user_prompt - Stop / SubagentStop:
reason、stop_hook_active - SessionStart:
source(startup/resume/compact)
與 Codex / Gemini 的比較
| 能力 | Claude Code Hooks | Codex CLI | Gemini CLI |
|---|---|---|---|
| 事件驅動自動化 | 14 種事件 | 無 | 無 |
| 攔截工具執行 | PreToolUse | 沙盒隔離 | 無 |
| 自動核准/拒絕 | allow/deny/ask | 無 | 無 |
| 修改工具參數 | updatedInput | 無 | 無 |
| LLM 驅動判斷 | prompt/agent Hook | 無 | 無 |
| 安全護欄方式 | 細粒度行為控制 | 檔案系統沙盒 | 權限提示 |
Codex 選擇了沙盒隔離策略——把 Agent 關在圍欄裡。Claude Code 選擇了行為監控策略——讓 Agent 自由行動,但在每個關鍵節點安裝攝影機和警報器。兩種哲學各有優劣:沙盒更簡單安全,Hooks 更靈活強大。
結論:從「信任 AI」到「驗證 AI」
Hooks 體現了一個重要的理念轉變:從被動地信任 AI 的判斷,到主動地在每個節點驗證 AI 的行為。
這不是不信任 AI——而是工程上的最佳實踐。就像你不會讓 production server 裸奔而不設 monitoring 和 alerting,你也不應該讓 AI coding agent 在沒有任何護欄的情況下操作你的程式碼。
Hooks 讓這種護欄變得確定性的、自動的、可程式化的。它把 AI 安全從「希望 AI 記得遵守規則」提升到「系統層級保證規則被執行」。
這是 Claude Code 在 AI 編碼工具競爭中最獨特的差異化——不是模型更聰明或速度更快,而是給開發者最細粒度的控制權。
參考資料
- Anthropic, "Claude Code Hooks Reference", Official Documentation
- Anthropic, "Automate Workflows with Hooks", Official Guide
- Disler, "Claude Code Hooks Mastery", GitHub
- aiorg.dev, "Claude Code Hooks: Complete Guide with 20+ Examples"
- Pixelmojo, "Claude Code Hooks for Production Quality CI/CD Patterns"