Claude Code hooks — セッション・ツールイベントでシェルコマンドを自動実行する
settings.json の hooks でセッション開始・ツール呼び出し前後・終了時にシェルコマンドを挿入。5つの実例: セキュリティブロック・自動フォーマット・ログ記録・外部アラート。
Claude Code の Hooks — settings.json の hooks キーで定義 — は、セッション開始・ツール呼び出し前後・セッション終了時に シェルコマンドを自動実行 できる。AI が実行しようとしていることに割り込んだり、後処理を行ったり、終了時のクリーンアップをしたりできる強力な拡張ポイントだ。
このガイドは Claude Code 1.x / 公式 Hooks 仕様 を対象としている。Claude Code セットアップの上に、自動化とセキュリティのレイヤーをひとつ追加する。
TL;DR
| hookイベント | 発火タイミング | 典型的な用途 |
|---|---|---|
SessionStart | セッション開始直後 | メモリ同期通知、環境検証 |
UserPromptSubmit | ユーザーがプロンプトを送信した直後 | スラッシュコマンド認識、ログ、後処理 |
PreToolUse | ツール呼び出し直前 | 危険なコマンドのブロック、シークレットファイル保護 |
PostToolUse | ツール呼び出し直後 | 自動フォーマット(prettier)、lint、副作用ログ |
Stop | セッション終了直前 | 変更サマリー、バックアップ、通知 |
重要なルール:
- 終了コード 2 でツール呼び出しをブロックする(PreToolUse)。
- hookのstdinにJSONが渡される —
jqで解析する。 - hookはシェルコマンド — OS差異に注意(macOS/Linux/Windows WSL)。
前提条件
- Claude Code 1.x インストール済み — Claude Code セットアップ
jqインストール済み(brew install jq/apt install jq/winget install jqlang.jq)settings.jsonの編集権限(通常は~/.claude/settings.json)
ベースラインをダウンロードする
devAlice 推奨の5つの Hook ベースライン + permissions の deny/allow リスト — ダウンロードしてカスタマイズしてください。
settings.json# 1. ダウンロード
curl -fsSL https://devalice.jaceclub.com/assets/ai-agents/claude-code-hooks/settings.example.json -o settings.json
# 2. SHA-256検証
shasum -a 256 settings.json
# Expected: 30c1d4117a935cac03b601c71125c11b71733c8c59517ab129fd8913cfb8a69e
# 3. 内容確認(特にPreToolUse hooks)
less settings.json
# 4. 所定の場所にコピー(macOS/Linux)
mkdir -p ~/.claude
cp settings.json ~/.claude/settings.json⚠️ 注意: Hook は 任意のシェルコマンドを実行 する。他者の Hook を適用する前は 必ず内容を確認 してください。このサンプルは安全な5つの Hook ベースラインですが、お使いの環境に合わせてレビューし適用してください。
1. Hooks 構造 — 5分
~/.claude/settings.jsonのhooksキー:
{
"hooks": {
"EventName": [
{
"matcher": "regex or tool name", // 省略可
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc 'actual shell command'"
}
]
}
]
}
}マッチングルール:
matcherなし → 全イベントで発火matcher= ツール名(Bash、Write、Edit、Read…)→ そのツールのみmatcher= 正規表現(^/(?:ej|euijinpro)\\b)→UserPromptSubmitでプロンプトテキストにマッチ
stdinに渡されるJSON:
{
"session_id": "...",
"transcript_path": "/path/to/transcript.jsonl",
"cwd": "/Users/...",
"tool_name": "Bash",
"tool_input": { "command": "..." },
"tool_response": { /* PostToolUseのみ */ }
}jq -r .tool_input.commandで取り出す。
2. SessionStart — コンテキストを読み込む
最もシンプルな Hook。セッション開始時に1行表示する:
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc 'printf \"[session start] %s\\nmemory sync: latest (skip)\\n\" \"$(date \"+%Y-%m-%d %H:%M:%S\")\"'"
}
]
}
]stdoutはシステムメッセージとして表示される。以下の用途に使える:
- メモリファイルの自動ロードをトリガー
- プロジェクト固有のコンテキスト出力
- 開始時のgitステータスサマリー
# より詳細な例
command='/bin/bash -lc "echo [session start]; git -C \"$PWD\" status -s; git -C \"$PWD\" log --oneline -3"'3. PreToolUse — 危険なコマンドをブロックする(最も重要な Hook)
exit 2 でブロック。AI が危険なシェルコマンドを実行しようとしても止めることができる。
3.1 危険なパターン
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc 'cmd=$(jq -r .tool_input.command); case \"$cmd\" in *\"rm -rf /\"*|*\"sudo rm\"*|*\":(){\"*) echo \"blocked dangerous command: $cmd\" >&2; exit 2;; esac'"
}
]
}
]ブロックされるパターン:
rm -rf /— システム破壊sudo rm— 広範な削除(必要な場合はホワイトリストで許可):(){— フォークボム(:(){ :|: & };:)
3.2 シークレットファイルの編集をブロックする
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc 'path=$(jq -r .tool_input.file_path); case \"$path\" in */.env|*/credentials.json|*/.aws/credentials) echo \"blocked secret-file edit: $path\" >&2; exit 2;; esac'"
}
]
}.env、credentials.json、~/.aws/credentialsなどへの誤った編集を防ぐ。
3.3 特定ディレクトリを保護する
command='/bin/bash -lc "path=\$(jq -r .tool_input.file_path); case \"\$path\" in /etc/*|/System/*) echo \"blocked system path: \$path\" >&2; exit 2;; esac"'4. PostToolUse — 自動フォーマット / Lint / ログ
ツール呼び出し 後 のクリーンアップ。
4.1 Prettier自動フォーマット
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc 'path=$(jq -r .tool_input.file_path); case \"$path\" in *.ts|*.tsx|*.js|*.jsx) prettier --write \"$path\" 2>/dev/null || true ;; esac'"
}
]
}
]AI の Write/Edit 後に prettier が自動フォーマット。編集ごとに約0.5秒かかる。
4.2 変更ファイルをログに記録する
command='/bin/bash -lc "path=\$(jq -r .tool_input.file_path); echo \"[changed] \$(date +%T) \$path\" >> ~/.claude/change.log"'セッション内の全ファイル変更を時刻順に記録する。
4.3 型チェック / Lint(重い処理は Stop に移動)
毎回の編集で tsc --noEmit を実行するのはコストがかかる。Stop Hook(§6)で行う方が効率的だ。
5. UserPromptSubmit — スラッシュ検出 / 後処理トリガー
"UserPromptSubmit": [
{
"matcher": "^/(?:ej|euijinpro)\\b",
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc 'echo \"[ej skill] prompt earmarked for euijin.pro logging\" >&2'"
}
]
}
]- スラッシュコマンドを検出 → 外部システム(Slack、別途ログ)をトリガー
- 特定キーワードの自動ラベリング(
urgent、bug) - トークンバジェットのしきい値チェック
6. Stop — セッション終了時のクリーンアップ
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc 'printf \"\\n[session end] %s\\n\" \"$(date \"+%Y-%m-%d %H:%M:%S\")\"'"
}
]
}
]用途:
- 変更ファイルのgitステータスサマリー
- バックアップ(
rsyncまたはgit stash) - 外部への終了通知
- 型チェック / ビルドの1回実行
command='/bin/bash -lc "if git diff --quiet; then echo \"[clean]\"; else echo \"[changes]\"; git diff --stat; fi"'7. permissions — Deny / Allow
Hooks とは別ですが、settings.json で最も重要なセキュリティキーだ。
"permissions": {
"deny": [
"Bash(rm -rf /:*)",
"Bash(sudo rm:*)",
"Read(.env)",
"Read(.env.local)",
"Read(.aws/credentials)",
"Read(*/credentials.json)"
],
"allow": [
"Bash(git status:*)",
"Bash(git log:*)",
"Bash(git diff:*)",
"Bash(pnpm:*)",
"Bash(npm:*)",
"Bash(node:*)"
]
}denyは無条件に優先 — Hook ブロックを補完するallowはユーザーへの確認なしに自動承認(頻繁に使う安全なコマンド)- その他は毎回ユーザーに確認する
このガイドの Hook は deny と重複しています — 多層防御だ。
8. settings.jsonの場所と優先順位
| 場所 | スコープ | 備考 |
|---|---|---|
~/.claude/settings.json | ユーザー全体 | 全プロジェクト |
<project>/.claude/settings.json | プロジェクト | プロジェクト進入時にユーザー設定とマージ |
<project>/.claude/settings.local.json | プロジェクト + ユーザーローカル | .gitignore推奨 |
マージ順: ユーザー → プロジェクト → プロジェクト.local。後が前を上書きする。
Hook は マージではなく追記 — ユーザー5つ + プロジェクト3つ = 合計8つが実行される。
9. デバッグ — Hook が発火しない場合
9.1 stdin ペイロードを確認する
一時的なデバッグ Hook:
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc 'cat > /tmp/claude-hook-debug.json'"
}
]
}→ cat /tmp/claude-hook-debug.json | jq .
9.2 終了コードをテストする
command='/bin/bash -lc "echo dbg >&2; exit 2"'→ ブロッキング(PreToolUse)が機能しているか確認する。
9.3 Hook の発火を確認する
command='/bin/bash -lc "echo \"[hook fired $$ $(date +%T)]\" >> ~/.claude/hook-trace.log"'セッション後にログを確認する。
9.4 JSON 構文エラー
settings.json は厳格 — 末尾カンマやエスケープ漏れがよくある。jq . ~/.claude/settings.json で検証してください。
10. トラブルシューティング
「command not found: jq」
brew install jq(macOS)/ sudo apt install jq(Linux)/ winget install jqlang.jq(Windows)
Hook が発火するが何もしない
commandは1行である必要がある。複数行の場合は\\nを使うか、別スクリプトを呼び出してください。- シェルエスケープに注意 — JSON 内の
\"は二重エスケープだ。
PreToolUse の exit 2 が無視される
exit 2がシェルコマンドの最終行に確実に到達しているか確認してください。set -e環境ではcase ;;が exit 0 になることがある — マッチしたブランチ内で直接exit 2してください。
Prettier が動かない
- プロジェクトルートに prettier がインストールされているか確認(
pnpm prettier --version)。 - Hook の PATH に
node_modules/.binが含まれていない可能性 →npx prettierまたは絶対パスを使用してください。
settings.json の変更が反映されない
- セッションの再起動が必要だ。または
/config reload(サポートされている場合)。 - JSON 構文エラーにより静かに無視されている可能性がある。
jq .で検証してください。
次のステップ
- Claude Code セットアップ — 前提条件
- エージェントランナー — 自律実行 + Hooks の組み合わせ
- MCP サーバー — Hooks との役割の違い
- マルチエージェントワークフロー — Subagents の統合
参考リンク
変更履歴
- 2026-05-12 — 初版(devAlice M2 シード展開)