<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>PreToolUse &#8211; 小人物看世界</title>
	<atom:link href="https://blog.che-ya.com/tag/pretooluse/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.che-ya.com</link>
	<description>軟體工程師的技術筆記</description>
	<lastBuildDate>Wed, 08 Apr 2026 08:05:27 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://blog.che-ya.com/wp-content/uploads/2021/08/cropped-APP_icon-32x32.png</url>
	<title>PreToolUse &#8211; 小人物看世界</title>
	<link>https://blog.che-ya.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Hooks 事件掛鉤：自動化你的 Claude Code 工作流程</title>
		<link>https://blog.che-ya.com/claude-code-hooks/</link>
		
		<dc:creator><![CDATA[ㄚ槌]]></dc:creator>
		<pubDate>Fri, 17 Apr 2026 02:27:00 +0000</pubDate>
				<category><![CDATA[Claude Code 進階]]></category>
		<category><![CDATA[Claude Code]]></category>
		<category><![CDATA[AI 編程工具]]></category>
		<category><![CDATA[Anthropic]]></category>
		<category><![CDATA[CLI]]></category>
		<category><![CDATA[Hooks]]></category>
		<category><![CDATA[PreToolUse]]></category>
		<category><![CDATA[自動化]]></category>
		<guid isPermaLink="false">https://blog.che-ya.com/?p=770</guid>

					<description><![CDATA[Claude Code 的 Hooks（事件掛鉤）是一套強大的自動化機制，讓你可以在 Claude Code  ... <a title="Hooks 事件掛鉤：自動化你的 Claude Code 工作流程" class="read-more" href="https://blog.che-ya.com/claude-code-hooks/" aria-label="Read more about Hooks 事件掛鉤：自動化你的 Claude Code 工作流程">閱讀全文</a>]]></description>
										<content:encoded><![CDATA[
<p>Claude Code 的 Hooks（事件掛鉤）是一套強大的自動化機制，讓你可以在 Claude Code 的生命週期中插入自訂邏輯。無論是在工具執行前進行安全檢查、在檔案寫入後自動執行格式化、還是在 Session 啟動時初始化環境變數，Hooks 都能幫你實現。透過在 <code>settings.json</code> 中設定 Shell 指令、HTTP 請求、Prompt 或 Agent，你可以完全掌控 Claude Code 的行為，打造符合團隊需求的自動化工作流程。</p>



<h2 class="wp-block-heading">什麼是 Hooks</h2>



<p>Hooks 是使用者定義的自動化處理程式，會在 Claude Code 生命週期的特定時間點自動觸發執行。你可以把它想像成程式開發中的「事件監聽器」——當 Claude Code 執行特定動作（如使用工具、啟動 Session、完成回應）時，你預先設定好的 Hook 就會自動執行。</p>



<p>Hooks 支援四種處理類型：</p>



<ul class="wp-block-list">
<li><strong>Command Hooks</strong>：執行 Shell 指令，透過 stdin 接收事件資料，用 exit code 和 stdout 回傳結果</li>



<li><strong>HTTP Hooks</strong>：發送 JSON POST 請求到指定的 URL 端點，適合整合外部服務</li>



<li><strong>Prompt Hooks</strong>：將事件資料送給 Claude 模型評估，回傳 yes/no 決策</li>



<li><strong>Agent Hooks</strong>：啟動子代理進行驗證，可使用 Read、Grep、Glob 等工具</li>
</ul>



<p>每種類型都有各自適合的應用場景。Command Hooks 最靈活且常用，適合大部分自動化需求；HTTP Hooks 適合與外部審批系統整合；Prompt Hooks 讓 AI 幫你做智慧判斷；Agent Hooks 則適合需要深入分析程式碼的驗證任務。</p>



<h2 class="wp-block-heading">Hooks 的設定方式</h2>



<p>Hooks 的設定統一放在 <code>settings.json</code> 中，根據適用範圍的不同，可以放在以下位置：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>位置</th><th>路徑</th><th>適用範圍</th></tr></thead><tbody><tr><td>使用者設定</td><td><code>~/.claude/settings.json</code></td><td>所有專案（僅本機）</td></tr><tr><td>專案設定</td><td><code>.claude/settings.json</code></td><td>此專案（可提交到版本控制）</td></tr><tr><td>專案本機設定</td><td><code>.claude/settings.local.json</code></td><td>此專案（僅本機）</td></tr><tr><td>企業管理設定</td><td>Managed policy settings</td><td>整個組織</td></tr><tr><td>Plugin Hooks</td><td><code>hooks/hooks.json</code></td><td>啟用該 Plugin 時</td></tr></tbody></table></figure>



<p>基本的設定結構如下，每個事件名稱下可以設定多組 matcher 和 hooks：</p>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/check-bash.sh",
            "timeout": 30
          }
        ]
      }
    ]
  }
}</code></pre>



<p>其中 <code>matcher</code> 欄位用來過濾觸發條件，支援正規表達式語法。例如 <code>Bash</code> 只匹配 Bash 工具、<code>Edit|Write</code> 匹配 Edit 或 Write 工具、<code>mcp__.*</code> 匹配所有 MCP 工具。沒有設定 matcher 的事件（如 <code>Stop</code>、<code>UserPromptSubmit</code>）會在每次事件發生時都觸發。</p>



<h2 class="wp-block-heading">Hook 的生命週期事件</h2>



<p>Claude Code 的 Hooks 涵蓋了整個使用生命週期，從 Session 啟動到結束，每個階段都有對應的事件可以掛鉤。以下是主要的事件分類：</p>



<h3 class="wp-block-heading">Session 階段</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>事件</th><th>觸發時機</th><th>Matcher</th></tr></thead><tbody><tr><td><code>SessionStart</code></td><td>Session 啟動或恢復時</td><td><code>startup</code>、<code>resume</code>、<code>clear</code>、<code>compact</code></td></tr><tr><td><code>InstructionsLoaded</code></td><td>CLAUDE.md 或規則檔案載入時</td><td><code>session_start</code>、<code>nested_traversal</code>、<code>include</code></td></tr><tr><td><code>Notification</code></td><td>Claude 發送通知時</td><td><code>notification</code>（對話繼續需要注意）</td></tr><tr><td><code>Stop</code></td><td>Claude 完成回應時</td><td><code>end_turn</code>（主動結束）或 <code>max_turns</code>（達到上限）</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">工具執行階段（最常用）</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>事件</th><th>觸發時機</th><th>可否阻擋</th></tr></thead><tbody><tr><td><code>PreToolUse</code></td><td>工具執行之前</td><td>可以（allow/deny/ask）</td></tr><tr><td><code>PostToolUse</code></td><td>工具執行成功之後</td><td>可以回饋訊息</td></tr><tr><td><code>PostToolUseFailure</code></td><td>工具執行失敗之後</td><td>可提供額外上下文</td></tr><tr><td><code>PermissionRequest</code></td><td>權限對話框出現時</td><td>可自動允許或拒絕</td></tr><tr><td><code>PermissionDenied</code></td><td>Auto mode 拒絕工具呼叫時</td><td>可要求重試</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">回應與通知階段</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>事件</th><th>觸發時機</th><th>說明</th></tr></thead><tbody><tr><td><code>UserPromptSubmit</code></td><td>使用者提交 Prompt 時</td><td>可過濾或阻擋特定內容</td></tr><tr><td><code>Stop</code></td><td>Claude 完成回應時</td><td>可阻擋讓 Claude 繼續工作</td></tr><tr><td><code>StopFailure</code></td><td>API 錯誤導致中止時</td><td>用於錯誤監控與通知</td></tr><tr><td><code>Notification</code></td><td>Claude 發送通知時</td><td>可自訂通知行為</td></tr><tr><td><code>SubagentStart / SubagentStop</code></td><td>子代理啟動或結束時</td><td>可注入額外上下文</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">PreToolUse：工具執行前的守門員</h2>



<p><code>PreToolUse</code> 是最重要也最常用的 Hook 事件，因為它是唯一能夠在工具執行前攔截並阻擋操作的事件。當 Claude 準備使用任何工具（Bash、Edit、Write、Read 等）時，PreToolUse Hook 會先被觸發，你可以在這裡進行安全檢查、自動審批或修改工具輸入。</p>



<p>Hook 接收到的輸入 JSON 包含工具名稱和工具參數：</p>



<pre class="wp-block-code"><code lang="json" class="language-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..."
}</code></pre>



<p>Hook 可以透過輸出 JSON 來控制 Claude 的行為，最關鍵的是 <code>permissionDecision</code> 欄位，支援四種決策：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>決策</th><th>效果</th><th>適用場景</th></tr></thead><tbody><tr><td><code>allow</code></td><td>允許工具執行，跳過權限提示</td><td>自動核准安全指令</td></tr><tr><td><code>deny</code></td><td>阻擋工具執行</td><td>封鎖危險操作</td></tr><tr><td><code>ask</code></td><td>強制顯示權限提示</td><td>敏感操作需要人工確認</td></tr><tr><td><code>defer</code></td><td>不做決定，交由下一個 Hook 或預設行為處理</td><td>條件不匹配時</td></tr></tbody></table></figure>



<p>以下是一個封鎖危險 Bash 指令的 PreToolUse Hook 範例：</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">#!/bin/bash
# .claude/hooks/block-dangerous.sh

# 從 stdin 讀取事件 JSON
COMMAND=$(jq -r '.tool_input.command' &lt; /dev/stdin)

# 檢查是否包含危險指令
if echo "$COMMAND" | grep -qE 'rm -rf /|mkfs|dd if=|:(){ :|&amp;}'; then
  # 輸出 JSON 阻擋執行
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: "偵測到危險指令，已自動阻擋"
    }
  }'
else
  # exit 0 且不輸出 JSON 表示不干預
  exit 0
fi</code></pre>



<p>對應的 settings.json 設定：</p>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-dangerous.sh",
            "timeout": 10
          }
        ]
      }
    ]
  }
}</code></pre>



<h2 class="wp-block-heading">PostToolUse：工具執行後的品質把關</h2>



<p><code>PostToolUse</code> 在工具成功執行之後觸發，適合用來進行後處理作業，例如自動格式化程式碼、執行 Lint 檢查、記錄操作日誌等。與 PreToolUse 不同的是，PostToolUse 無法阻擋已完成的操作，但可以將檢查結果回饋給 Claude，讓 Claude 根據結果調整後續行為。</p>



<p>PostToolUse Hook 接收到的 JSON 除了 <code>tool_input</code> 外，還包含 <code>tool_response</code>（工具執行結果）：</p>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "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
  }
}</code></pre>



<p>以下是一個在檔案寫入後自動執行 ESLint 檢查的範例：</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">#!/bin/bash
# .claude/hooks/auto-lint.sh

FILE_PATH=$(jq -r '.tool_input.file_path' &lt; /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&gt;&amp;1)
  
  if [ $? -ne 0 ]; then
    # 將 Lint 錯誤回饋給 Claude
    jq -n --arg ctx "$LINT_RESULT" '{
      hookSpecificOutput: {
        hookEventName: "PostToolUse",
        additionalContext: ("ESLint 檢查發現問題，請修正：\n" + $ctx)
      }
    }'
  fi
fi

exit 0</code></pre>



<p>設定方式如下，使用 <code>Edit|Write</code> 作為 matcher 來同時匹配編輯和寫入操作：</p>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/auto-lint.sh"
          }
        ]
      }
    ]
  }
}</code></pre>



<h2 class="wp-block-heading">Notification Hook：自訂通知行為</h2>



<p><code>Notification</code> 事件在 Claude Code 發送通知時觸發，例如等待使用者輸入、需要權限確認、驗證成功等情境。你可以透過 matcher 過濾特定類型的通知：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Matcher 值</th><th>觸發時機</th></tr></thead><tbody><tr><td><code>permission_prompt</code></td><td>Claude 需要使用者授權工具時</td></tr><tr><td><code>idle_prompt</code></td><td>Claude 等待使用者輸入時</td></tr><tr><td><code>auth_success</code></td><td>驗證成功時</td></tr><tr><td><code>elicitation_dialog</code></td><td>MCP Server 請求輸入時</td></tr></tbody></table></figure>



<p>以下範例在 Claude 等待權限確認時，自動發送桌面通知提醒你：</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">#!/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 &amp;&gt; /dev/null; then
  osascript -e "display notification \"$MESSAGE\" with title \"$TITLE\""
fi

# Linux 桌面通知
if command -v notify-send &amp;&gt; /dev/null; then
  notify-send "$TITLE" "$MESSAGE"
fi

exit 0</code></pre>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "hooks": {
    "Notification": [
      {
        "matcher": "permission_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/desktop-notify.sh",
            "async": true
          }
        ]
      }
    ]
  }
}</code></pre>



<p>注意這裡使用了 <code>"async": true</code>，讓通知腳本在背景執行，不會阻塞 Claude Code 的主流程。</p>



<h2 class="wp-block-heading">Hook 的四種處理類型詳解</h2>



<h3 class="wp-block-heading">Command Hook：Shell 指令</h3>



<p>Command Hook 是最基本也最靈活的類型，透過執行 Shell 指令來處理事件。事件的 JSON 資料會透過 stdin 傳入，Hook 透過 exit code 和 stdout 回傳結果。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Exit Code</th><th>意義</th><th>JSON 處理</th></tr></thead><tbody><tr><td><code>0</code></td><td>成功</td><td>解析 stdout 的 JSON</td></tr><tr><td><code>2</code></td><td>阻擋性錯誤</td><td>忽略 JSON，使用 stderr 訊息</td></tr><tr><td>其他</td><td>非阻擋性錯誤</td><td>忽略 JSON，在 verbose 模式顯示 stderr</td></tr></tbody></table></figure>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "type": "command",
  "command": ".claude/hooks/my-hook.sh",
  "shell": "bash",
  "timeout": 30,
  "async": false
}</code></pre>



<h3 class="wp-block-heading">HTTP Hook：遠端服務整合</h3>



<p>HTTP Hook 將事件 JSON 以 POST 請求發送到指定的 URL，非常適合與團隊的審批系統、日誌服務或監控平台整合。支援自訂 Headers 和環境變數插值：</p>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "type": "http",
  "url": "https://approval.example.com/hooks/validate",
  "headers": {
    "Authorization": "Bearer $MY_API_TOKEN"
  },
  "allowedEnvVars": ["MY_API_TOKEN"],
  "timeout": 10
}</code></pre>



<p>遠端端點回傳的 JSON 格式與 Command Hook 相同，非 2xx 回應碼會被視為非阻擋性錯誤。</p>



<h3 class="wp-block-heading">Prompt Hook：AI 智慧判斷</h3>



<p>Prompt Hook 將事件資料送給 Claude 模型，讓 AI 做出 allow 或 deny 的智慧判斷。使用 <code>$ARGUMENTS</code> 占位符來插入事件 JSON：</p>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "type": "prompt",
  "prompt": "審查以下 Shell 指令是否安全。如果指令可能刪除重要檔案、修改系統設定或存取敏感資料，回答 deny；否則回答 allow。指令內容：$ARGUMENTS",
  "timeout": 30
}</code></pre>



<h3 class="wp-block-heading">Agent Hook：子代理驗證</h3>



<p>Agent Hook 會啟動一個子代理來進行更深入的驗證，子代理可以使用 Read、Grep、Glob 等工具來分析程式碼，適合需要理解上下文才能做出判斷的場景：</p>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "type": "agent",
  "prompt": "驗證這個指令是否符合專案的安全政策。檢查 .claude/SECURITY.md 中的規則，並確認指令不會違反任何安全限制。指令內容：$ARGUMENTS",
  "timeout": 60
}</code></pre>



<h2 class="wp-block-heading">共用設定欄位參考</h2>



<p>所有類型的 Hook 都支援以下共用欄位：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>欄位</th><th>必填</th><th>說明</th></tr></thead><tbody><tr><td><code>type</code></td><td>是</td><td>處理類型：<code>command</code>、<code>http</code>、<code>prompt</code> 或 <code>agent</code></td></tr><tr><td><code>if</code></td><td>否</td><td>額外的過濾條件，使用權限規則語法，例如 <code>Bash(git *)</code></td></tr><tr><td><code>timeout</code></td><td>否</td><td>逾時秒數，預設值依類型不同（Command: 600s、HTTP: 30s、Prompt: 30s、Agent: 60s）</td></tr><tr><td><code>statusMessage</code></td><td>否</td><td>執行時顯示的自訂 Spinner 訊息</td></tr><tr><td><code>once</code></td><td>否</td><td>設為 true 時每個 Session 只執行一次（僅限 Skill 中的 Hook）</td></tr></tbody></table></figure>



<p><code>if</code> 欄位特別有用，它讓你可以在 matcher 的基礎上進一步過濾。例如你想只針對 <code>rm</code> 開頭的 Bash 指令觸發 Hook，可以設定 <code>"if": "Bash(rm *)"</code>，這樣 <code>ls</code> 或 <code>git status</code> 等指令就不會觸發。</p>



<h2 class="wp-block-heading">Hook 中可用的環境變數</h2>



<p>Claude Code 會在執行 Hook 時提供幾個實用的環境變數：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>變數</th><th>說明</th></tr></thead><tbody><tr><td><code>$CLAUDE_PROJECT_DIR</code></td><td>專案根目錄路徑（建議用雙引號包裹，以處理路徑中的空格）</td></tr><tr><td><code>${CLAUDE_PLUGIN_ROOT}</code></td><td>Plugin 安裝目錄</td></tr><tr><td><code>${CLAUDE_PLUGIN_DATA}</code></td><td>Plugin 持久化資料目錄</td></tr></tbody></table></figure>



<p><code>CLAUDE_ENV_FILE</code> 是一個特殊的環境變數，只在特定事件中可用。你可以透過寫入這個檔案來持久化環境變數，讓後續的 Claude Code 操作都能存取到這些變數：</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">#!/bin/bash
# 在 SessionStart hook 中初始化環境
if [ -n "$CLAUDE_ENV_FILE" ]; then
  # 載入 nvm 並設定 Node 版本
  export NVM_DIR="$HOME/.nvm"
  [ -s "$NVM_DIR/nvm.sh" ] &amp;&amp; \. "$NVM_DIR/nvm.sh"
  nvm use 18
  
  # 將環境變數寫入持久化檔案
  echo 'export NODE_ENV=development' &gt;&gt; "$CLAUDE_ENV_FILE"
  echo 'export DEBUG=app:*' &gt;&gt; "$CLAUDE_ENV_FILE"
fi

exit 0</code></pre>



<h2 class="wp-block-heading">實戰應用範例</h2>



<h3 class="wp-block-heading">範例一：自動核准安全指令</h3>



<p>在日常開發中，你可能會頻繁使用 <code>git status</code>、<code>npm test</code>、<code>ls</code> 等安全指令，每次都需要手動確認權限會降低效率。以下 Hook 可以自動核准這些安全指令：</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">#!/bin/bash
# .claude/hooks/approve-safe-commands.sh

COMMAND=$(jq -r '.tool_input.command' &lt; /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</code></pre>



<h3 class="wp-block-heading">範例二：操作日誌記錄</h3>



<p>在團隊或企業環境中，記錄 Claude Code 的所有操作是很重要的合規需求。以下 Hook 會將每次工具使用記錄到日誌檔：</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">#!/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" \
  &gt;&gt; "$LOG_DIR/audit.log"

exit 0</code></pre>



<p>將這個 Hook 同時掛載到 PreToolUse 和 PostToolUse 事件，就能完整記錄所有工具的使用情況：</p>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "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
          }
        ]
      }
    ]
  }
}</code></pre>



<h3 class="wp-block-heading">範例三：Prompt 內容過濾</h3>



<p>在企業環境中，你可能需要防止 Claude 接收包含敏感資訊的 Prompt。以下 Hook 使用 <code>UserPromptSubmit</code> 事件來過濾使用者輸入：</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">#!/bin/bash
# .claude/hooks/filter-prompts.sh

PROMPT=$(jq -r '.prompt' &lt; /dev/stdin)

# 檢查是否包含敏感關鍵字
if echo "$PROMPT" | grep -qi 'password\|api.key\|secret\|credential'; then
  jq -n '{
    decision: "block",
    reason: "Prompt 中包含敏感資訊關鍵字，請移除後再試"
  }'
else
  exit 0
fi</code></pre>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/filter-prompts.sh"
          }
        ]
      }
    ]
  }
}</code></pre>



<h3 class="wp-block-heading">範例四：Session 啟動環境初始化</h3>



<p>利用 <code>SessionStart</code> Hook 在每次啟動 Claude Code 時自動初始化開發環境，載入專案所需的環境變數和工具版本：</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">#!/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" =~ ^#.*$ ]] &amp;&amp; continue
      [[ -z "$line" ]] &amp;&amp; continue
      echo "export $line" &gt;&gt; "$CLAUDE_ENV_FILE"
    done &lt; "$CLAUDE_PROJECT_DIR/.env"
  fi
  
  # 設定專案特定的工具路徑
  echo "export PATH=$CLAUDE_PROJECT_DIR/node_modules/.bin:\$PATH" &gt;&gt; "$CLAUDE_ENV_FILE"
fi

# 回傳環境資訊給 Claude
jq -n '{
  hookSpecificOutput: {
    hookEventName: "SessionStart",
    additionalContext: "開發環境已初始化。.env 已載入，node_modules/.bin 已加入 PATH。"
  }
}'</code></pre>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/init-env.sh"
          }
        ]
      }
    ]
  }
}</code></pre>



<h2 class="wp-block-heading">除錯與管理 Hooks</h2>



<p>Claude Code 提供了幾個實用的工具來幫助你除錯和管理 Hooks：</p>



<p><strong>查看已設定的 Hooks</strong>：在 Claude Code 中輸入 <code>/hooks</code> 指令，會在瀏覽器中開啟一個頁面，顯示所有已設定的 Hooks 及其來源（User、Project、Local、Plugin、Session 或 Built-in）。</p>



<p><strong>停用所有 Hooks</strong>：如果你需要暫時停用所有 Hooks（例如排除問題時），可以在 settings.json 中加入：</p>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "disableAllHooks": true
}</code></pre>



<p>注意，這個設定會遵循設定層級，企業管理層級設定的 Hooks 只能透過企業管理設定中的 <code>disableAllHooks</code> 來停用。</p>



<p><strong>輸出上限</strong>：Hook 的 JSON 輸出有 10,000 字元的上限。超過此限制的內容會被儲存到檔案中，不會直接傳遞給 Claude。因此建議保持 Hook 輸出簡潔，只回傳必要的資訊。</p>



<h2 class="wp-block-heading">常見問題與疑難排解</h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>問題</th><th>解決方案</th></tr></thead><tbody><tr><td>Hook 沒有觸發</td><td>確認 matcher 正確匹配工具名稱（區分大小寫），使用 <code>/hooks</code> 確認 Hook 已載入</td></tr><tr><td>Hook 觸發了但沒有效果</td><td>確認 exit code 為 0，且 stdout 輸出的是合法的 JSON 格式</td></tr><tr><td>Hook 執行太慢</td><td>設定較短的 <code>timeout</code>，或使用 <code>"async": true</code> 在背景執行</td></tr><tr><td>JSON 解析錯誤</td><td>使用 <code>jq -n</code> 來生成 JSON 而非手動拼接字串，確保特殊字元被正確跳脫</td></tr><tr><td>環境變數無法存取</td><td>確認 Hook 腳本有可執行權限（<code>chmod +x</code>），且 <code>$CLAUDE_PROJECT_DIR</code> 路徑正確</td></tr><tr><td>PreToolUse 的 allow/deny 無效</td><td>使用 <code>hookSpecificOutput.permissionDecision</code> 而非頂層的 <code>decision</code> 欄位</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">Hooks 最佳實踐</h2>



<ul class="wp-block-list">
<li><strong>保持 Hook 腳本簡短快速</strong>：Hook 會阻塞 Claude Code 的主流程（除非使用 async），長時間執行的腳本會影響使用體驗。非必要的後處理可以使用 <code>"async": true</code></li>



<li><strong>善用 matcher 和 if 過濾</strong>：避免對所有工具呼叫都觸發 Hook，只針對特定工具和特定模式觸發，減少不必要的開銷</li>



<li><strong>使用 jq 處理 JSON</strong>：Hook 的輸入和輸出都是 JSON 格式，<code>jq</code> 是處理 JSON 的最佳工具，避免用字串操作來解析或生成 JSON</li>



<li><strong>正確處理 exit code</strong>：exit 0 表示成功、exit 2 表示阻擋性錯誤、其他值表示非阻擋性錯誤。確保你的腳本在所有路徑上都有正確的 exit code</li>



<li><strong>將安全相關的 Hook 放在專案設定中</strong>：將 <code>.claude/hooks/</code> 目錄和 <code>.claude/settings.json</code> 提交到版本控制，確保團隊所有成員都使用相同的安全規則</li>



<li><strong>測試 Hook 腳本</strong>：在正式使用之前，先用 <code>echo '{"tool_name":"Bash","tool_input":{"command":"test"}}' | ./hook.sh</code> 手動測試你的 Hook 腳本是否正確運作</li>
</ul>



<h2 class="wp-block-heading">總結</h2>



<p>Hooks 是 Claude Code 中實現自動化工作流程的核心機制。透過 PreToolUse 你可以建立安全防線，透過 PostToolUse 你可以自動化品質檢查，透過 SessionStart 你可以初始化開發環境，透過 Notification 你可以自訂通知行為。四種處理類型（Command、HTTP、Prompt、Agent）讓你能夠靈活地整合各種工具和服務，無論是本地腳本還是遠端 API 都能輕鬆對接。</p>



<p>建議從最簡單的 Command Hook 開始，先建立一個自動核准安全指令的 PreToolUse Hook 來提升日常開發效率，再根據團隊需求逐步擴展到日誌記錄、程式碼品質檢查等進階應用。</p>



<h2 class="wp-block-heading">延伸閱讀</h2>



<ul class="wp-block-list">
<li><a href="https://blog.che-ya.com/claude-code-introduction/">Claude Code 是什麼？完整介紹與安裝教學</a></li>



<li><a href="https://blog.che-ya.com/claude-code-getting-started/">Claude Code 新手上路：第一次使用就上手</a></li>



<li><a href="https://blog.che-ya.com/claude-md-project-memory/">CLAUDE.md 專案記憶：讓 Claude 記住你的專案規範</a></li>



<li><a href="https://blog.che-ya.com/claude-code-cli-reference/">Claude Code CLI 指令完整參考</a></li>



<li><a href="https://blog.che-ya.com/claude-code-context-token-optimization/">Context 管理與 Token 優化技巧</a></li>



<li><a href="https://blog.che-ya.com/claude-code-slash-commands-shortcuts/">Slash Commands 與快捷鍵完整指南</a></li>



<li><a href="https://blog.che-ya.com/claude-code-custom-skills/">Custom Skills：打造你的專屬自訂技能</a></li>



<li><a href="https://code.claude.com/docs/en/hooks" rel="nofollow noopener" target="_blank">Claude Code Hooks 官方文件</a></li>
</ul>
<div class="saboxplugin-wrap" itemtype="http://schema.org/Person" itemscope itemprop="author"><div class="saboxplugin-tab"><div class="saboxplugin-gravatar"><img alt='ㄚ槌' src='https://secure.gravatar.com/avatar/9914399915f96350f302945e8ddddee1a9b1995350182f513fd2e1fa816c100a?s=100&#038;d=mm&#038;r=g' srcset='https://secure.gravatar.com/avatar/9914399915f96350f302945e8ddddee1a9b1995350182f513fd2e1fa816c100a?s=200&#038;d=mm&#038;r=g 2x' class='avatar avatar-100 photo' height='100' width='100' itemprop="image"/></div><div class="saboxplugin-authorname"><a href="https://blog.che-ya.com/author/a3230230/" class="vcard author" rel="author"><span class="fn">ㄚ槌</span></a></div><div class="saboxplugin-desc"><div itemprop="description"></div></div><div class="saboxplugin-web "><a href="https://blog.che-ya.com" target="_self">blog.che-ya.com</a></div><div class="clearfix"></div></div></div><p><a class="a2a_button_facebook" href="https://www.addtoany.com/add_to/facebook?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fclaude-code-hooks%2F&amp;linkname=Hooks%20%E4%BA%8B%E4%BB%B6%E6%8E%9B%E9%89%A4%EF%BC%9A%E8%87%AA%E5%8B%95%E5%8C%96%E4%BD%A0%E7%9A%84%20Claude%20Code%20%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B" title="Facebook" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_line" href="https://www.addtoany.com/add_to/line?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fclaude-code-hooks%2F&amp;linkname=Hooks%20%E4%BA%8B%E4%BB%B6%E6%8E%9B%E9%89%A4%EF%BC%9A%E8%87%AA%E5%8B%95%E5%8C%96%E4%BD%A0%E7%9A%84%20Claude%20Code%20%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B" title="Line" rel="nofollow noopener" target="_blank"></a><a class="a2a_button_x" href="https://www.addtoany.com/add_to/x?linkurl=https%3A%2F%2Fblog.che-ya.com%2Fclaude-code-hooks%2F&amp;linkname=Hooks%20%E4%BA%8B%E4%BB%B6%E6%8E%9B%E9%89%A4%EF%BC%9A%E8%87%AA%E5%8B%95%E5%8C%96%E4%BD%A0%E7%9A%84%20Claude%20Code%20%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B" title="X" rel="nofollow noopener" target="_blank"></a><a class="a2a_dd addtoany_share_save addtoany_share" href="https://www.addtoany.com/share#url=https%3A%2F%2Fblog.che-ya.com%2Fclaude-code-hooks%2F&#038;title=Hooks%20%E4%BA%8B%E4%BB%B6%E6%8E%9B%E9%89%A4%EF%BC%9A%E8%87%AA%E5%8B%95%E5%8C%96%E4%BD%A0%E7%9A%84%20Claude%20Code%20%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B" data-a2a-url="https://blog.che-ya.com/claude-code-hooks/" data-a2a-title="Hooks 事件掛鉤：自動化你的 Claude Code 工作流程"></a></p>]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
