Skip to content

Claude Code Hooks

Hooks 是 Claude Code 的事件處理機制,讓你在特定時機點自動執行 shell 命令或腳本。這是實現自動化工作流程的強大功能。

為什麼需要 Hooks?

沒有 Hooks使用 Hooks
每次寫檔案後手動執行 prettier自動在 Write/Edit 後格式化
每次都要手動允許測試指令自動批准安全的測試命令
忘記檢查 linter 警告自動在編輯後執行 lint
手動記錄執行過的命令自動記錄所有 Bash 命令
傳統方式:
Claude:[寫入 index.ts]
你:[手動執行 prettier]
你:[手動執行 eslint]

使用 Hooks:
Claude:[寫入 index.ts]
       [自動執行 prettier]
       [自動執行 eslint]
       [已完成格式化和檢查]

Hook 類型

Claude Code 提供 8 種 Hook 事件:

Hook觸發時機主要用途
PreToolUse工具執行前阻擋危險命令、驗證輸入、自動批准
PostToolUse工具執行後執行格式化、觸發 linter、記錄變更
PermissionRequest權限對話框前自動批准重複請求、拒絕敏感存取
SessionStartSession 開始時注入 git status、載入 TODO
UserPromptSubmit用戶提交 prompt 時注入上下文、驗證請求
StopClaude 完成回應時驗證任務完成、強制繼續
SubagentStopSub-agent 完成時驗證輸出、觸發後續動作
PreCompactContext 壓縮前備份對話記錄

設定檔位置

Hooks 設定在 JSON 檔案中,優先順序如下:

位置用途Git 追蹤
.claude/settings.local.json個人設定(最高優先)否(加入 .gitignore)
.claude/settings.json專案共用設定
~/.claude/settings.json全域設定N/A

基本結構

json
{
  "hooks": {
    "HookType": [
      {
        "matcher": "ToolName",
        "hooks": [
          {
            "type": "command",
            "command": "your-command-here"
          }
        ]
      }
    ]
  }
}

Matcher 語法

Matcher 用於過濾哪些工具會觸發 Hook:

語法說明範例
"Write"精確匹配只匹配 Write 工具
"Write|Edit"多重匹配匹配 Write 或 Edit
"*"""全部匹配匹配所有工具
"Bash(npm test*)"參數匹配匹配以 npm test 開頭的命令
"mcp__memory__.*"模式匹配匹配 MCP 工具

注意

Matcher 是 區分大小寫 的。"bash" 不會匹配到 Bash 工具。

實用範例

1. 自動格式化程式碼

每次 Write 或 Edit 後自動執行 Prettier:

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "file_path=$(cat | jq -r '.tool_input.file_path'); if [[ \"$file_path\" == *.ts ]] || [[ \"$file_path\" == *.tsx ]]; then npx prettier --write \"$file_path\"; fi"
          }
        ]
      }
    ]
  }
}

2. 自動批准測試命令

讓測試命令不需要手動確認:

json
{
  "hooks": {
    "PermissionRequest": [
      {
        "matcher": "Bash(npm test*)",
        "hooks": [
          {
            "type": "command",
            "command": "echo '{\"decision\": \"allow\"}'"
          }
        ]
      },
      {
        "matcher": "Bash(npm run lint*)",
        "hooks": [
          {
            "type": "command",
            "command": "echo '{\"decision\": \"allow\"}'"
          }
        ]
      }
    ]
  }
}

3. Session 開始時注入上下文

讓 Claude 知道目前的專案狀態:

json
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo '=== Git Status ===' && git status --short && echo '\\n=== TODO ===' && head -20 TODO.md 2>/dev/null || echo 'No TODO.md'"
          }
        ]
      }
    ]
  }
}

4. 記錄所有 Bash 命令

用於稽核或除錯:

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.command' >> ~/.claude/bash-history.log"
          }
        ]
      }
    ]
  }
}

5. 阻擋危險操作

防止修改 production 設定:

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "file_path=$(cat | jq -r '.tool_input.file_path'); if echo \"$file_path\" | grep -q 'production\\|.env.prod'; then echo '{\"decision\": \"block\", \"reason\": \"Cannot modify production files\"}'; fi"
          }
        ]
      }
    ]
  }
}

6. 強制完成檢查清單

確保 Claude 完成所有項目才停止:

json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo '{\"continue\": false}'"
          }
        ]
      }
    ]
  }
}

使用 prompt 類型強制驗證:

json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Review if all tasks are complete. If not, continue working."
          }
        ]
      }
    ]
  }
}

Hook 輸入與輸出

輸入格式(stdin)

所有 Hook 都會收到 JSON 格式的輸入:

json
{
  "session_id": "abc123",
  "transcript_path": "/path/to/transcript.jsonl",
  "cwd": "/Users/you/project",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/Users/you/project/index.ts",
    "content": "..."
  }
}

輸出與 Exit Code

Exit Code效果
0成功,stdout 會被處理
2阻擋操作,stderr 成為錯誤訊息
其他非阻擋性錯誤

JSON 回應格式

進階控制可以回傳 JSON:

json
{
  "decision": "allow|block|deny",
  "reason": "顯示給 Claude 的說明",
  "continue": true,
  "updatedInput": {
    "file_path": "modified/path.js"
  }
}
欄位說明
decisionallow/block(PreToolUse)、allow/deny(PermissionRequest)
reason顯示給 Claude 的說明文字
continue用於 Stop/SubagentStop,設為 true 強制繼續
updatedInput修改工具參數(v2.0.10+)

環境變數

Hook 執行時可用的環境變數:

變數說明
CLAUDE_PROJECT_DIR專案根目錄
CLAUDE_CODE_REMOTE是否為遠端環境
CLAUDE_TOOL_INPUT_*工具輸入參數(大寫)

除錯技巧

查看 Transcript 檔案

bash
# 即時查看對話記錄
tail -f /path/to/transcript.jsonl | jq

建立 Log Wrapper

bash
#!/bin/bash
# ~/.claude/scripts/log-wrapper.sh
LOG=~/.claude/hooks.log
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // "n/a"')
echo "=== $(date) | $TOOL ===" >> "$LOG"
echo "$INPUT" >> "$LOG"
# 執行實際命令
echo "$INPUT" | "$@"

使用:

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/scripts/log-wrapper.sh your-actual-command"
          }
        ]
      }
    ]
  }
}

安全性考量

重要

Hook 設定檔的直接修改需要在 /hooks 選單中確認才會生效,防止惡意程式碼注入。

最佳實踐

  1. 驗證輸入:永遠驗證 stdin 的內容
  2. 引號包裹變數:防止 shell injection
  3. 使用絕對路徑:腳本路徑使用絕對路徑
  4. 避免處理敏感檔案:不要在 Hook 中處理 .env 或憑證檔案

完整設定範例

一個完整的 .claude/settings.json 範例:

json
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo '📋 Project: '$(basename $PWD) && git status --short 2>/dev/null | head -5"
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash(rm -rf*)",
        "hooks": [
          {
            "type": "command",
            "command": "echo '{\"decision\": \"block\", \"reason\": \"Dangerous: rm -rf is not allowed\"}'"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "file=$(cat | jq -r '.tool_input.file_path'); ext=\"${file##*.}\"; case \"$ext\" in ts|tsx|js|jsx) npx prettier --write \"$file\" 2>/dev/null;; go) gofmt -w \"$file\" 2>/dev/null;; esac"
          }
        ]
      }
    ],
    "PermissionRequest": [
      {
        "matcher": "Bash(npm test*)|Bash(npm run build*)",
        "hooks": [
          {
            "type": "command",
            "command": "echo '{\"decision\": \"allow\"}'"
          }
        ]
      }
    ]
  }
}

參考資源

下一步

AI 時代的軟體工程工作坊教學手冊