實用 hook 範例集
Formatter / test runner / lint feedback / access control 四個範例。
TL;DR
- 四個常用範例可以直接抄走:formatter、test runner、lint feedback、file access control
- 每個給可複製的
settings.json片段 + 何時用 + 邏輯說明 - hook 命令可以是 inline shell,不一定要寫獨立 script 檔
這篇怎麼讀
上一篇你已經會寫 hook 了。這篇是 cookbook——掃過去挑你需要的抄,不要從頭讀到尾。
四個範例的觸發點與用途速查:
| 範例 | event | matcher | 解決什麼 |
|---|---|---|---|
| Formatter | PostToolUse | Write|Edit | Claude 寫的檔自動格式化 |
| Test runner | PostToolUse | Edit | 改完立刻知道有沒有壞 |
| Lint feedback | PostToolUse | Edit | 把 lint error 丟回 Claude 自己修 |
| Access control | PreToolUse | Read | block 讀 .env 等機密檔 |
1. Formatter
Claude 寫出來的檔常常空白、引號跟你 repo 不一致。每次都要再叫它跑一次 prettier 很煩,直接掛 hook 自動跑。
{
"hooks": {
"PostToolUse": [{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs -I{} pnpm exec prettier --write {}"
}]
}]
}
}
從 stdin 拿 hook payload、抽出 file_path、丟給 prettier。改成 eslint --fix 或 ruff format 也是同個 pattern。
2. Test runner
改完 foo.ts 自動跑 foo.test.ts。發現壞掉立刻知道,不用等 Claude 整輪做完才發現。
{
"hooks": {
"PostToolUse": [{
"matcher": "Edit",
"hooks": [{
"type": "command",
"command": "f=$(jq -r '.tool_input.file_path'); t=${f%.ts}.test.ts; test -f \"$t\" && pnpm vitest run \"$t\""
}]
}]
}
}
關鍵是 test -f——對應 test 檔不存在就 silent skip,不要每個 edit 都炸錯誤訊息。
3. Lint feedback
跟 formatter 不一樣:lint 抓的是 logic 問題(unused var、any、未處理 promise),需要 Claude 真的改邏輯。把 stderr 丟回 Claude 讓它自己修。
{
"hooks": {
"PostToolUse": [{
"matcher": "Edit",
"hooks": [{
"type": "command",
"command": "f=$(jq -r '.tool_input.file_path'); pnpm eslint \"$f\" 1>&2 || exit 2"
}]
}]
}
}
exit 2 是關鍵——Claude Code 把 stderr 當作 feedback 餵回 Claude,它看到 lint error 會接著修。exit 1 只會 abort,沒這個效果。
4. File access control
讓 Claude 永遠不能讀 .env、secrets/、*.pem 這類檔案。比靠 prompt 提醒可靠。
{
"hooks": {
"PreToolUse": [{
"matcher": "Read",
"hooks": [{
"type": "command",
"command": "f=$(jq -r '.tool_input.file_path'); case \"$f\" in *.env|*/secrets/*|*.pem) echo \"blocked: $f\" 1>&2; exit 2;; esac"
}]
}]
}
}
PreToolUse + exit 2 會直接 block 那次 Read,stderr 訊息會顯示給 Claude 知道為什麼被擋。比 permissions.deny 更靈活——能寫 pattern、能附理由。
接下來
四個範例都會踩到一些雷:matcher 寫錯、stdin payload 結構搞混、exit 2 跟 exit 1 行為差很多。下一篇 Hooks 雷區 把常見坑收齊。

