MAR 18, 20266 分鐘閱讀Claude Code

用 Claude Code 寫程式,有些事不能靠「建議」— 你需要系統層級的保證

CLAUDE.md 是「建議」,Hooks 是「法律」。當你需要 100% 執行率而不是 80%,就需要系統層級的保證。完整解析 Claude Code Hooks 機制、設定方式、實戰範例,讓你的 AI 開發工作流從「大部分時候有做」變成「每次都做」。

hook

用 Claude Code 寫程式的人,遲早會撞到這面牆

很多人 Vibe Coding 用 Claude Code 做開發,初期體驗很好 — 丟需求,出程式碼。

但隨著專案變複雜,一個結構性問題會浮現:

你在 CLAUDE.md 裡寫了「每次 commit 前跑 test」、「改完程式要跑 Prettier」,但 AI 不會每次都做。

有時候記得,有時候忘記。Session 越長,遺忘率越高。

這不是 AI 的 bug,是架構設計的必然結果 — CLAUDE.md 本質上是一份「建議書」。AI 會盡量遵守,但它是概率性的,你的指令會在長 context 中被稀釋。

問題的本質:有些事情需要 100% 執行率,不是 80%。

格式化必須每次都跑。危險指令必須每次都攔截。Type check 必須每次都做。「大部分時候會做」跟「每次都做」之間的差距,就是 bug 和穩定之間的差距。


解法:CLAUDE.md 管判斷,Hooks 管紀律

Claude Code 有一個叫 Hooks 的機制,專門解決這個問題。

Hooks 讓你在 AI 工作流的特定時間點,綁定一個「必定執行」的動作:

  • AI 改完檔案 → 自動跑 Prettier
  • AI 要執行 bash 指令 → 自動檢查有沒有危險操作
  • AI 完成任務 → 自動發桌面通知

關鍵字是「自動」和「必定」。不是 AI 決定要不要做,是系統層級保證會做。

如果 CLAUDE.md 是「建議」,Hooks 就是「法律」。

這個區分很重要:CLAUDE.md 管的是 AI 的「判斷」— 什麼技術選型、coding style。Hooks 管的是 AI 的「紀律」— 什麼事情必須做、什麼操作絕對不能做。兩者搭配才是完整的 AI 開發工作流。


怎麼設定:比想像中簡單

最快的方式:直接叫 Claude 幫你設

在 Claude Code 裡面直接用自然語言描述你要的 Hook,例如:

幫我加一個 Hook,每次編輯 .ts 檔案之後自動跑 Prettier

Claude 會自動幫你寫好 JSON 設定並存檔。

你也可以打 /hooks 查看目前已設定的 Hook(注意:/hooks 選單是唯讀的,只能查看,不能新增或修改)。

不需要改任何程式碼,不需要裝任何套件。

進階方式:直接寫 JSON

.claude/settings.json 加入設定:

javascript
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}

意思是:每當 AI 編輯或寫入檔案,自動對該檔案跑 Prettier。


核心觸發時機,覆蓋整個 AI 工作流

以下列出最常用的 7 個 Hook 事件。Claude Code 實際支援超過 15 個事件(包括 SubagentStop、SessionEnd、PreCompact、PermissionRequest 等),完整列表請參考官方文件
觸發時機什麼時候觸發實際用途
SessionStart開啟新 session載入額外 context、檢查環境
UserPromptSubmit送出 prompt 後記錄日誌、注入 context
PreToolUseAI 執行操作前攔截危險指令
PostToolUse工具執行完成後自動格式化、type check
NotificationAI 發通知時桌面通知提醒
StopAI 完成回應時跑測試、驗證結果
Setup專案初始化時安裝依賴、build

四個實戰 Hook 設定

1. 自動格式化

javascript
{
  "matcher": "Edit|MultiEdit|Write",
  "hooks": [{
    "type": "command",
    "command": "jq -r '.tool_input.file_path' | { read fp; if echo \"$fp\" | grep -qE '\\.(ts|tsx|js|jsx)$'; then npx prettier --write \"$fp\"; fi; }"
  }]
}

只對 TypeScript / JavaScript 檔案執行。AI 改完檔案的瞬間,Prettier 就跑了。再也不需要手動跑。

2. 危險指令攔截

javascript
{
  "matcher": "Bash",
  "hooks": [{
    "type": "command",
    "command": "jq -r '.tool_input.command' | { read cmd; if echo \"$cmd\" | grep -qE 'rm\\s+-rf\\s+/'; then echo 'Blocked: dangerous rm command' >&2; exit 2; fi; }"
  }]
}

exit 2 是關鍵 — 它是「絕對否決權」。不管 AI 想做什麼,exit code 2 都能完全阻止,並把錯誤訊息傳回給 AI。

3. 桌面通知

.claude/settings.json 加入 Notification event 的 Hook 即可(見下方完整設定範例)。AI 跑耗時任務時可以切去做其他事,完成後收到系統通知。

4. TypeScript Type Check

javascript
{
  "matcher": "Edit|MultiEdit",
  "hooks": [{
    "type": "command",
    "command": "jq -r '.tool_input.file_path' | { read fp; if echo \"$fp\" | grep -qE '\\.(ts|tsx)$'; then npx tsc --noEmit --skipLibCheck 2>&1 | head -20 || true; fi; }"
  }]
}

進階:Async Hooks — 不阻塞的背景執行

asynchook

上面的 Hook 都是「同步」的 — AI 會等它跑完才繼續。對格式化和危險指令攔截來說,這是必要的。

但某些 Hook 根本不需要阻塞 AI:記錄日誌、發通知、上傳指標。這些「射後不理」的任務,加一行 "async": true 就能讓它們在背景執行:

javascript
{
  "type": "command",
  "command": "./log-bash-usage.sh",
  "async": true,
  "timeout": 30
}

AI 不會等這個 Hook 跑完,直接繼續工作。如果你的專案 Hook 越來越多,每次互動都要等好幾秒,async 可以大幅提速。

什麼應該用 async?

  • ✅ 日誌記錄、Slack 通知、metrics 上傳 → async: true
  • ❌ 格式化、危險指令攔截、Type check → 保持同步

判斷標準很簡單:如果這個 Hook 需要影響 AI 接下來的行為,就用同步。如果只是觀察和報告,就用 async。


Exit Code 控制流程

Exit Code效果
0正常,繼續執行
其他非零有錯誤,但不阻止 AI(stderr 顯示於 verbose 模式)
2完全阻止操作,把 stderr 傳回給 AI

exit 2 是整個 Hooks 系統最強大的部分。它讓你可以在 AI 執行任何操作之前先「審查」,不符合條件就直接擋掉。


設定檔放哪裡

位置檔案路徑適合什麼
全域~/.claude/settings.json所有專案都要用的 Hook
專案.claude/settings.json團隊共用,加入版控
個人.claude/settings.local.json只有自己用,不加入版控

團隊協作的做法:共用的 Hook(格式化、lint)放專案設定並加入 git,個人化的(通知、日誌)放 local 設定。


可以直接複製的完整設定

以下組合適合大部分 TypeScript / JavaScript 專案,複製到 .claude/settings.json 即可(macOS 環境):

javascript
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [{
          "type": "command",
          "command": "jq -r '.tool_input.file_path' | { read fp; if echo \"$fp\" | grep -qE '\\.(ts|tsx|js|jsx)$'; then npx prettier --write \"$fp\"; fi; }"
        }]
      },
      {
        "matcher": "Edit|MultiEdit",
        "hooks": [{
          "type": "command",
          "command": "jq -r '.tool_input.file_path' | { read fp; if echo \"$fp\" | grep -qE '\\.(ts|tsx)$'; then npx tsc --noEmit --skipLibCheck 2>&1 | head -20 || true; fi; }"
        }]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{
          "type": "command",
          "command": "jq -r '.tool_input.command' | { read cmd; if echo \"$cmd\" | grep -qE 'rm\\s+-rf\\s+/'; then echo 'Blocked: dangerous rm command' >&2; exit 2; fi; }"
        }]
      }
    ],
    "Notification": [
      {
        "hooks": [{
          "type": "command",
          "command": "osascript -e 'display notification \"Claude Code 需要你的注意\" with title \"Claude Code\"'"
        }]
      }
    ]
  }
}

安全性注意事項

Hooks 用系統權限執行,沒有沙箱隔離:

  • Hook 能做任何你能做的事
  • Clone 別人的專案時,先檢查 .claude/settings.json 裡有沒有異常的 Hook
  • 非共用的 Hook 放在 .claude/settings.local.json,不加入版控

核心 Insight

這個「建議 vs 規則」的框架不只適用於 Claude Code。

任何 AI 自動化工具,都需要思考同一個問題:哪些事情「建議 AI 做」就夠了,哪些事情必須用系統層級保證?

把 AI 當「聰明但不完全可靠的助手」來管理,而不是當「完美的執行者」來期待 — 這條線搞清楚,對 AI 工具的掌控力會完全不同。


延伸閱讀:Claude Code Hooks 官方文件