介紹

Claude Code hooks 是使用者定義的 shell 命令,在 Claude Code 生命週期的各個時點執行。Hooks 提供對 Claude Code 行為的確定性控制,確保某些動作總是會發生,而不是依賴 LLM 選擇執行它們。

範例使用案例包括:

  • 通知:自訂當 Claude Code 等待您的輸入或執行權限時如何通知您。
  • 自動格式化:在每次檔案編輯後對 .ts 檔案執行 prettier,對 .go 檔案執行 gofmt 等。
  • 記錄:追蹤和計算所有執行的命令以符合合規性或除錯需求。
  • 回饋:當 Claude Code 產生不符合您程式碼庫慣例的程式碼時提供自動回饋。
  • 自訂權限:阻止對生產檔案或敏感目錄的修改。

透過將這些規則編碼為 hooks 而不是提示指令,您將建議轉換為應用程式層級的程式碼,每次預期執行時都會執行。

Hooks 會以您的完整使用者權限執行 shell 命令,無需確認。您有責任確保您的 hooks 是安全的。Anthropic 不對因使用 hook 而導致的任何資料遺失或系統損壞承擔責任。請檢閱安全考量

快速開始

在此快速開始中,您將新增一個記錄 Claude Code 執行的 shell 命令的 hook。

快速開始先決條件:安裝 jq 以在命令列中進行 JSON 處理。

步驟 1:開啟 hooks 設定

執行 /hooks 斜線命令 並選擇 PreToolUse hook 事件。

PreToolUse hooks 在工具呼叫之前執行,可以阻止它們並向 Claude 提供關於如何做不同處理的回饋。

步驟 2:新增匹配器

選擇 + Add new matcher… 以僅在 Bash 工具呼叫上執行您的 hook。

為匹配器輸入 Bash

步驟 3:新增 hook

選擇 + Add new hook… 並輸入此命令:

jq -r '"\(.tool_input.command) - \(.tool_input.description // "No description")"' >> ~/.claude/bash-command-log.txt

步驟 4:儲存您的設定

對於儲存位置,選擇 User settings,因為您要記錄到您的家目錄。此 hook 將適用於所有專案,而不僅僅是您目前的專案。

然後按 Esc 直到您回到 REPL。您的 hook 現在已註冊!

步驟 5:驗證您的 hook

再次執行 /hooks 或檢查 ~/.claude/settings.json 以查看您的設定:

"hooks": {
  "PreToolUse": [
    {
      "matcher": "Bash",
      "hooks": [
        {
          "type": "command",
          "command": "jq -r '\"\\(.tool_input.command) - \\(.tool_input.description // \"No description\")\"' >> ~/.claude/bash-command-log.txt"
        }
      ]
    }
  ]
}

設定

Claude Code hooks 在您的設定檔案中設定:

  • ~/.claude/settings.json - 使用者設定
  • .claude/settings.json - 專案設定
  • .claude/settings.local.json - 本地專案設定(不提交)
  • 企業管理政策設定

結構

Hooks 按匹配器組織,每個匹配器可以有多個 hooks:

{
  "hooks": {
    "EventName": [
      {
        "matcher": "ToolPattern",
        "hooks": [
          {
            "type": "command",
            "command": "your-command-here"
          }
        ]
      }
    ]
  }
}
  • matcher:匹配工具名稱的模式(僅適用於 PreToolUsePostToolUse
    • 簡單字串精確匹配:Write 僅匹配 Write 工具
    • 支援正規表示式:Edit|WriteNotebook.*
    • 如果省略或空字串,hooks 會對所有匹配事件執行
  • hooks:當模式匹配時要執行的命令陣列
    • type:目前僅支援 "command"
    • command:要執行的 bash 命令
    • timeout:(可選)命令應該執行多長時間(以秒為單位),超時後取消所有進行中的 hooks。

Hook 事件

PreToolUse

在 Claude 建立工具參數之後、處理工具呼叫之前執行。

常見匹配器:

  • Task - 代理任務
  • Bash - Shell 命令
  • Glob - 檔案模式匹配
  • Grep - 內容搜尋
  • Read - 檔案讀取
  • EditMultiEdit - 檔案編輯
  • Write - 檔案寫入
  • WebFetchWebSearch - 網路操作

PostToolUse

在工具成功完成後立即執行。

識別與 PreToolUse 相同的匹配器值。

Notification

當 Claude Code 發送通知時執行。

Stop

當主要 Claude Code 代理完成回應時執行。

SubagentStop

當 Claude Code 子代理(Task 工具呼叫)完成回應時執行。

Hook 輸入

Hooks 透過 stdin 接收包含會話資訊和事件特定資料的 JSON 資料:

{
  // 通用欄位
  session_id: string
  transcript_path: string  // 對話 JSON 的路徑

  // 事件特定欄位
  ...
}

PreToolUse 輸入

tool_input 的確切架構取決於工具。

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  }
}

PostToolUse 輸入

tool_inputtool_response 的確切架構取決於工具。

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  },
  "tool_response": {
    "filePath": "/path/to/file.txt",
    "success": true
  }
}

Notification 輸入

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "message": "Task completed successfully",
  "title": "Claude Code"
}

Stop 和 SubagentStop 輸入

當 Claude Code 已經因為 stop hook 而繼續時,stop_hook_active 為 true。檢查此值或處理記錄以防止 Claude Code 無限期執行。

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "stop_hook_active": true
}

Hook 輸出

有兩種方式讓 hooks 將輸出返回給 Claude Code。輸出傳達是否阻止以及應該向 Claude 和使用者顯示的任何回饋。

簡單:退出代碼

Hooks 透過退出代碼、stdout 和 stderr 傳達狀態:

  • 退出代碼 0:成功。stdout 在記錄模式(CTRL-R)中向使用者顯示。
  • 退出代碼 2:阻止錯誤。stderr 回饋給 Claude 自動處理。請參閱下面的每個 hook 事件行為。
  • 其他退出代碼:非阻止錯誤。stderr 向使用者顯示,執行繼續。

提醒:如果退出代碼為 0,Claude Code 不會看到 stdout。

退出代碼 2 行為

Hook 事件行為
PreToolUse阻止工具呼叫,向 Claude 顯示錯誤
PostToolUse向 Claude 顯示錯誤(工具已執行)
NotificationN/A,僅向使用者顯示 stderr
Stop阻止停止,向 Claude 顯示錯誤
SubagentStop阻止停止,向 Claude 子代理顯示錯誤

進階:JSON 輸出

Hooks 可以在 stdout 中返回結構化 JSON 以進行更複雜的控制:

通用 JSON 欄位

所有 hook 類型都可以包含這些可選欄位:

{
  "continue": true, // Claude 是否應該在 hook 執行後繼續(預設:true)
  "stopReason": "string" // 當 continue 為 false 時顯示的訊息
  "suppressOutput": true, // 在記錄模式中隱藏 stdout(預設:false)
}

如果 continue 為 false,Claude 在 hooks 執行後停止處理。

  • 對於 PreToolUse,這與 "decision": "block" 不同,後者僅阻止特定工具呼叫並向 Claude 提供自動回饋。
  • 對於 PostToolUse,這與 "decision": "block" 不同,後者向 Claude 提供自動回饋。
  • 對於 StopSubagentStop,這優先於任何 "decision": "block" 輸出。
  • 在所有情況下,"continue" = false 優先於任何 "decision": "block" 輸出。

stopReason 伴隨 continue 提供向使用者顯示的原因,不向 Claude 顯示。

PreToolUse 決策控制

PreToolUse hooks 可以控制工具呼叫是否進行。

  • “approve” 繞過權限系統。reason 向使用者顯示但不向 Claude 顯示。
  • “block” 防止工具呼叫執行。reason 向 Claude 顯示。
  • undefined 導致現有權限流程。reason 被忽略。
{
  "decision": "approve" | "block" | undefined,
  "reason": "決策的解釋"
}

PostToolUse 決策控制

PostToolUse hooks 可以控制工具呼叫是否進行。

  • “block” 自動用 reason 提示 Claude。
  • undefined 什麼都不做。reason 被忽略。
{
  "decision": "block" | undefined,
  "reason": "決策的解釋"
}

Stop/SubagentStop 決策控制

StopSubagentStop hooks 可以控制 Claude 是否必須繼續。

  • “block” 防止 Claude 停止。您必須填入 reason 讓 Claude 知道如何進行。
  • undefined 允許 Claude 停止。reason 被忽略。
{
  "decision": "block" | undefined,
  "reason": "當 Claude 被阻止停止時必須提供"
}

JSON 輸出範例:Bash 命令編輯

#!/usr/bin/env python3
import json
import re
import sys

# 將驗證規則定義為 (正規表示式模式, 訊息) 元組的列表
VALIDATION_RULES = [
    (
        r"\bgrep\b(?!.*\|)",
        "使用 'rg' (ripgrep) 而不是 'grep' 以獲得更好的效能和功能",
    ),
    (
        r"\bfind\s+\S+\s+-name\b",
        "使用 'rg --files | rg pattern' 或 'rg --files -g pattern' 而不是 'find -name' 以獲得更好的效能",
    ),
]


def validate_command(command: str) -> list[str]:
    issues = []
    for pattern, message in VALIDATION_RULES:
        if re.search(pattern, command):
            issues.append(message)
    return issues


try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"錯誤:無效的 JSON 輸入:{e}", file=sys.stderr)
    sys.exit(1)

tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
command = tool_input.get("command", "")

if tool_name != "Bash" or not command:
    sys.exit(1)

# 驗證命令
issues = validate_command(command)

if issues:
    for message in issues:
        print(f"• {message}", file=sys.stderr)
    # 退出代碼 2 阻止工具呼叫並向 Claude 顯示 stderr
    sys.exit(2)

使用 MCP 工具

Claude Code hooks 與模型上下文協定(MCP)工具無縫協作。當 MCP 伺服器提供工具時,它們會以特殊的命名模式出現,您可以在 hooks 中匹配。

MCP 工具命名

MCP 工具遵循模式 mcp__<server>__<tool>,例如:

  • mcp__memory__create_entities - Memory 伺服器的建立實體工具
  • mcp__filesystem__read_file - Filesystem 伺服器的讀取檔案工具
  • mcp__github__search_repositories - GitHub 伺服器的搜尋工具

為 MCP 工具設定 Hooks

您可以針對特定 MCP 工具或整個 MCP 伺服器:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "mcp__memory__.*",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
          }
        ]
      },
      {
        "matcher": "mcp__.*__write.*",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/scripts/validate-mcp-write.py"
          }
        ]
      }
    ]
  }
}

範例

程式碼格式化

在檔案修改後自動格式化程式碼:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/scripts/format-code.sh"
          }
        ]
      }
    ]
  }
}

通知

自訂當 Claude Code 請求權限或提示輸入變為閒置時發送的通知。

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/my_custom_notifier.py"
          }
        ]
      }
    ]
  }
}

安全考量

免責聲明

使用風險自負:Claude Code hooks 會在您的系統上自動執行任意 shell 命令。透過使用 hooks,您確認:

  • 您對您設定的命令負全責
  • Hooks 可以修改、刪除或存取您的使用者帳戶可以存取的任何檔案
  • 惡意或編寫不當的 hooks 可能導致資料遺失或系統損壞
  • Anthropic 不提供保證且不對因使用 hook 而導致的任何損壞承擔責任
  • 您應該在生產使用前在安全環境中徹底測試 hooks

在將任何 hook 命令新增到您的設定之前,請務必檢閱並理解它們。

安全最佳實務

以下是編寫更安全 hooks 的一些關鍵實務:

  1. 驗證和清理輸入 - 永遠不要盲目信任輸入資料
  2. 總是引用 shell 變數 - 使用 "$VAR" 而不是 $VAR
  3. 阻止路徑遍歷 - 檢查檔案路徑中的 ..
  4. 使用絕對路徑 - 為腳本指定完整路徑
  5. 跳過敏感檔案 - 避免 .env.git/、金鑰等

設定安全

直接編輯設定檔案中的 hooks 不會立即生效。Claude Code:

  1. 在啟動時擷取 hooks 的快照
  2. 在整個會話中使用此快照
  3. 如果 hooks 被外部修改則警告
  4. 需要在 /hooks 選單中檢閱才能應用變更

這防止惡意 hook 修改影響您目前的會話。

Hook 執行詳細資訊

  • 逾時:預設 60 秒執行限制,每個命令可設定。
    • 如果任何個別命令逾時,所有進行中的 hooks 都會被取消。
  • 平行化:所有匹配的 hooks 平行執行
  • 環境:在目前目錄中以 Claude Code 的環境執行
  • 輸入:透過 stdin 的 JSON
  • 輸出
    • PreToolUse/PostToolUse/Stop:進度在記錄中顯示(Ctrl-R)
    • Notification:僅記錄到除錯(--debug

除錯

要排除 hooks 故障:

  1. 檢查 /hooks 選單是否顯示您的設定
  2. 驗證您的設定檔案是有效的 JSON
  3. 手動測試命令
  4. 檢查退出代碼
  5. 檢閱 stdout 和 stderr 格式期望
  6. 確保適當的引號轉義
  7. 使用 claude --debug 來除錯您的 hooks。成功 hook 的輸出如下所示。
[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
[DEBUG] Found 1 hook matchers in settings
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Found 1 hook commands to execute
[DEBUG] Executing hook command: <Your command> with timeout 60000ms
[DEBUG] Hook command completed with status 0: <Your stdout>

進度訊息出現在記錄模式(Ctrl-R)中,顯示:

  • 哪個 hook 正在執行
  • 正在執行的命令
  • 成功/失敗狀態
  • 輸出或錯誤訊息