Applied AI School
v0 · 規劃中
Anthropic

Claude Code hooks 教學:PreToolUse / PostToolUse 心智模型

PreToolUse / PostToolUse 心智模型,為什麼 hook 比 prompt instruction 穩。

TL;DR

  • PreToolUse hook:tool 跑之前執行,可以 block tool call、把錯誤訊息丟回給 Claude
  • PostToolUse hook:tool 跑之後執行,做後續動作(formatter、test、lint)但不能 block——事情已經發生了
  • 比「叫 Claude 記得 X」可靠——LLM 的「記得」是機率性的,hook 是 deterministic enforcement

一個情境:那個總是忘記跑 prettier 的 agent

你 CLAUDE.md 寫了大大一行:

改完任何 .ts / .tsx 檔案,一定要跑 pnpm prettier --write

它記得 80% 的時候。剩下 20% 你 review PR 看到一堆混亂縮排,又要回去 nag 它一次。

問題不在 prompt 寫得不夠用力——你已經用 caps、用粗體、用驚嘆號了。問題是這個規則住錯地方了:它住在 prompt instruction,靠 LLM 自律去執行。LLM 的「記得」是機率分布,不是 if-statement。

Hook 是把這條規則從 prompt 搬到 enforcement layer——Claude Code 自己幫你跑,不問 LLM 的意見。

Hook 在流程的哪一格

正常的 tool call 流程:

你的 prompt → Claude 決定用 Edit tool → Claude Code 執行 → 結果回給 Claude → 下一輪

把 hook 插進去就變成:

Claude 決定用 Edit tool
        ↓
   PreToolUse hook  ← 可以在這裡 block
        ↓
   Claude Code 執行 Edit
        ↓
   PostToolUse hook ← 可以在這裡跑 formatter
        ↓
   結果回給 Claude

每一個 tool call 都有這兩個格子可以填。你想塞什麼指令都可以——shell command、Node script、Python——只要它會回傳 exit code,Claude Code 就接得住。

Pre 跟 Post 的能力對照

PreToolUsePostToolUse
跑的時機tool 執行tool 執行
可以 block tool❌(事情已經發生了)
拿到的 inputClaude 想呼叫的 tool name + 參數tool 執行的結果(含 stdout / 錯誤)
適合的場景擋掉危險命令、保護敏感檔案、enforce 命名規則跑 formatter、跑 test、回 lint 錯誤給 Claude 自己修
Block 怎麼回 Claudeexit code 非 0 + stderr 訊息不能 block,但可以把訊息回給 Claude(它會看到並反應)

一句話分:Pre 是守門人,Post 是清潔工

為什麼 hook 比 prompt 穩

把同一條規則寫在兩個地方比一下:

把規則放在 prompt把規則放在 hook
LLM 可能記得Claude Code 一定執行
吃 context window 額度不吃 context
換個 model 行為可能跑掉跟 model 無關
Debug 是「為什麼這次沒記得」Debug 是看 hook script 的 log

這跟 git pre-commit hook 是同一個哲學——你不會在 commit message 裡寫「請記得跑 lint」,你會裝一個 pre-commit hook 把它擋下來。Claude Code 的 hook 只是把這個概念從 commit-level 拉到 tool-call-level:每一次 read / write / edit / bash,都有一個可以攔截的位置。

兩個典型例子(先有畫面就好)

想做的事Pre 還是 Post為什麼
改完 .ts 自動跑 prettierPost改完才有東西能 format
不准 Claude 讀 .envPre要在它真的讀之前擋下
改完跑 tsc --noEmit,型別錯把錯誤丟回給 Claude 自己修Post已經改了才有得 type-check;用 Post 的「回訊息給 Claude」能力
擋掉所有 rm -rfPre等它跑完就來不及了

選 Pre 還是 Post 的判準很簡單:你要的是「擋下來」還是「事後處理」

接下來

下一篇 寫第一個 hook 把 settings.json 打開,從一個最小的 PostToolUse hook 開始——edit 完一個檔案就 echo 一行到 log,看整個 pipeline 怎麼接起來。