Hooks でガードレールを作る¶
LLM の判断に任せず、settings.json の hooks でシェルレベルの強制をかける。
押さえるべきイベント¶
| イベント | 何ができるか |
|---|---|
PreToolUse |
ツール実行を ブロックできる。exit 2 で阻止、stderr が Claude に返る |
UserPromptSubmit |
ユーザ入力に機密語が含まれていないかチェック |
PostToolUse |
編集後の format/lint/test/通知 |
Stop |
応答完了時に diff レビュー、PR コメントを書く |
典型 1: 危険コマンドブロック¶
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "jq -r '.tool_input.command' | grep -qE '(rm -rf|git push --force|drop database)' && { echo 'blocked: dangerous command' >&2; exit 2; } || exit 0"
}]
}]
}
}
典型 2: 機密ファイル保護¶
permissions 評価順は deny → ask → allow。deny で明示する方が確実。
典型 3: 編集後の自動フォーマット¶
{
"hooks": {
"PostToolUse": [{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs -r npx prettier --write"
}]
}]
}
}
-r は xargs が空入力の時にコマンドを呼ばない安全策。
典型 4: コミット前テスト¶
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "node .claude/hooks/pre-bash.js"
}]
}]
}
}
pre-bash.js 内で git push を intercept し npm run lint && npm test を実行、失敗時 exit 1 で push を止める。
設計原則¶
- deterministic であること。LLM 判断を入れず、確実にブロック/実行する所だけ hook 化
- exit 2 で stderr が Claude にフィードバックされる → 「なぜブロックしたか」を必ず stderr に書く
- 重い処理は hook で同期実行せず、
run_in_background的に投げて Stop hook で待つ
アンチパターン¶
- 何でも hook 化 → 編集のたびに数秒〜数十秒待たされる。重いのは Stop hook へ
- LLM 判断系を hook の中で別 API 呼び出し → ループ・コスト爆発・遅延
--no-verifyで hook 回避を Claude 自身に許す → permission でBash(git commit:--no-verify*)を deny
出典¶
- _research/claude-code-features/2026-05-11-claude-code-features.md
- _research/examples/2026-05-11-awesome-templates.md
- https://code.claude.com/docs/en/hooks-guide
- https://adambailey.io/blog/claude-hooks-lint-tests