はじめに
Claude Code を使って開発していると、こんなことを感じたことはありませんか?
- 「ファイルを編集したら自動でリンターを走らせたい」
- 「危険なコマンドを実行する前にブロックしたい」
- 「Claude の応答が終わったら通知音を鳴らしたい」
- 「本番環境に影響するコマンドだけは絶対に自動承認させたくない」
Claude Code Hooks を使えば、これらすべてが実現できます。
Hooks は、Claude Code のライフサイクル上の特定のポイントで自動的に実行されるユーザー定義の処理です。シェルコマンドの実行はもちろん、LLM による判定やサブエージェントの起動まで、柔軟な自動化が可能です。
本記事では、全14種類のフックイベントを一つ一つ丁寧に解説し、実践的なユースケースも紹介していきます。
目次
- Hooks の全体像 ── ライフサイクルを理解する
- 設定ファイルの配置場所
- 基本構造を理解する ── 3階層のネスト
- Exit Code と JSON 出力による制御
- 3つのハンドラータイプ
- 全14イベント詳細解説
- 実践ユースケース集
- セキュリティに関する注意点
- よくあるハマりポイント
- まとめ
Hooks の全体像 ── ライフサイクルを理解する
Hooks を理解するには、まず Claude Code のライフサイクルを把握することが重要です。以下の図で全体の流れを見てみましょう。
この一連の流れの中に14箇所のフックポイントが用意されており、各ポイントに独自の処理を差し込むことができます。
設定ファイルの配置場所
Hooks の設定は JSON ファイルに記述します。用途に応じて複数の配置場所が選べます。
| 配置場所 | スコープ | チームで共有 | 用途 |
|---|---|---|---|
~/.claude/settings.json |
全プロジェクト共通 | No | 個人の好みの設定(通知音など) |
.claude/settings.json |
プロジェクト単位 | Yes | チーム共通のルール(危険コマンドのブロックなど) |
.claude/settings.local.json |
プロジェクト単位 | No | 個人的なプロジェクト固有の設定 |
| マネージドポリシー設定 | 組織全体 | Yes | エンタープライズ管理者による統制 |
設定ファイルを直接編集しても即座には反映されません。Claude Code はセッション起動時にスナップショットを取得し、セッション中はそれを使用します。外部から変更した場合は /hooks メニューで確認が必要です。
使い分けのコツ:
- 通知音やログなど個人的な設定は
~/.claude/settings.jsonへ - 危険コマンドのブロックなどチームで統一したいルールは
.claude/settings.jsonへ(リポジトリにコミット) - API キーを含む設定など共有したくないものは
.claude/settings.local.jsonへ
基本構造を理解する ── 3階層のネスト
Hooks の設定は3階層のネスト構造になっています。
{
"hooks": {
"PreToolUse": [ // ← 第1層: Hook Event(いつ?)
{
"matcher": "Bash", // ← 第2層: Matcher Group(どの条件で?)
"hooks": [
{ // ← 第3層: Hook Handler(何をする?)
"type": "command",
"command": "echo 'Bashが実行されようとしています'",
"timeout": 600
}
]
}
]
}
}
| 層 | 役割 | 例 |
|---|---|---|
| 第1層 | いつ 発火するか |
PreToolUse(ツール実行前) |
| 第2層 | どの条件 で発火するか |
"Bash" のときだけ |
| 第3層 | 何を 実行するか | シェルコマンド、プロンプト、エージェント |
Matcher は正規表現で指定できるので、"Edit|Write" のように複数のツールにマッチさせたり、"mcp__.*" で全 MCP ツールにマッチさせたりできます。
Exit Code と JSON 出力による制御
Hooks の戻り値(Exit Code)によって、Claude Code の動作を制御できます。
Exit Code の意味
| Exit Code | 意味 | 動作 |
|---|---|---|
| 0 | 成功 | stdout の JSON を解析し、アクション続行 |
| 2 | ブロッキングエラー | 対象のアクションをブロック(対応イベントのみ) |
| それ以外 | 非ブロッキングエラー | verbose モードでログ表示、実行は続行 |
Exit Code 2 が特に重要です。これを使うと「そのアクションを止める」ことができます。ただし、すべてのイベントでブロックできるわけではありません。
| ブロック可能なイベント | Exit 2 の効果 |
|---|---|
PreToolUse |
ツール呼び出しをブロック |
PermissionRequest |
権限を拒否 |
UserPromptSubmit |
プロンプト処理をブロック |
Stop |
Claude の停止を防ぎ、続行させる |
SubagentStop |
サブエージェントの停止を防ぐ |
TaskCompleted |
タスク完了マークを防ぐ |
JSON 出力で細かく制御する
Exit 0 で stdout に JSON を出力すると、さらに細かい制御が可能です。
{
"continue": true, // false にすると Claude が完全停止
"stopReason": "処理を中断しました", // 停止時のメッセージ
"systemMessage": "注意: 本番DBへの接続を検出しました" // 警告メッセージ
}
3つのハンドラータイプ
Hooks では、処理の実行方法を3種類から選べます。
1. Command Hook ── シェルコマンドを実行
最もシンプルで一般的なタイプです。任意のシェルコマンドを実行できます。
{
"type": "command",
"command": "npm run lint",
"timeout": 600,
"statusMessage": "リント実行中...",
"async": false
}
| フィールド | 必須 | 説明 |
|---|---|---|
command |
Yes | 実行するシェルコマンド |
timeout |
No | タイムアウト秒数(デフォルト: 600秒) |
statusMessage |
No | 実行中にスピナーに表示されるメッセージ |
async |
No |
true でバックグラウンド実行 |
2. Prompt Hook ── LLM に判断させる
Claude モデルにプロンプトを送り、Yes/No の判定を得ます。シェルスクリプトでは判断しにくい「意味的な」チェックに向いています。
{
"type": "prompt",
"prompt": "以下のコード変更がセキュリティ上問題ないか判断してください: $ARGUMENTS",
"timeout": 30
}
$ARGUMENTS にはフックの入力 JSON が展開されるので、ツール名や入力パラメータを参照して判断させることができます。
3. Agent Hook ── サブエージェントで検証
Read / Grep / Glob などのツールを使ってファイルを調査し、判定を返すサブエージェントを起動します。
{
"type": "agent",
"prompt": "テストファイルが存在し、カバレッジが80%以上あるか確認してください",
"timeout": 60
}
使い分けの目安:
| タイプ | 向いているケース |
|---|---|
| Command | 明確なルールに基づくチェック(コマンド名の検証、ファイルの存在確認など) |
| Prompt | 文脈や意味を考慮した判断(コード変更の安全性チェックなど) |
| Agent | ファイルを調査してから判断する必要があるケース(テストカバレッジの確認など) |
全14イベント詳細解説
ここからが本記事の本題です。全14種類のフックイベントを一つ一つ解説していきます。
1. SessionStart ── セッション開始
🎯 一言で言うと: セッションが始まるときに環境を整える
いつ発火するか
- 新規セッション開始時
- 既存セッションの再開時
- コンテキストクリア後
- コンパクション後の再開時
Matcher で起動タイプを絞れる
| Matcher値 | 意味 |
|---|---|
startup |
新規セッション開始 |
resume |
既存セッションの再開 |
clear |
コンテキストクリア後 |
compact |
コンパクション後 |
入力フィールド
共通フィールド(session_id, cwd, permission_mode 等)に加えて:
| フィールド | 説明 |
|---|---|
type |
開始タイプ(startup / resume / clear / compact) |
ブロック: 不可
セッション開始自体を止めることはできません。
特別な機能: 環境変数の永続化
JSON 出力で hookSpecificOutput.env を返すと、セッション全体にわたる環境変数を設定できます。
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"env": {
"NODE_ENV": "development",
"DATABASE_URL": "postgresql://localhost:5432/dev"
}
}
}
stdout がコンテキストに追加される
SessionStart は特別で、Exit 0 時の stdout の内容がClaude が見えるコンテキストとして追加されます。「このプロジェクトでは常にこのルールに従ってください」のようなガイダンスを注入するのに便利です。
設定例
{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "echo '現在のNode.jsバージョン: '$(node -v)'. このプロジェクトではTypeScriptを使用してください。'"
}
]
}
]
}
}
2. UserPromptSubmit ── ユーザー入力の検証
🎯 一言で言うと: ユーザーのプロンプトが処理される前にチェックする
いつ発火するか
ユーザーがテキストを入力して送信した直後、Claude のモデル処理が始まる前。
Matcher: なし(常に発火)
このイベントには Matcher を設定できません。毎回必ず発火します。
入力フィールド
| フィールド | 説明 |
|---|---|
prompt |
ユーザーが送信したプロンプトテキスト |
ブロック: 可能
Exit 2 でプロンプトの処理をブロックし、プロンプト自体を消去します。機密情報の流出防止などに有用です。
stdout がコンテキストに追加される
SessionStart と同様に、stdout が Claude のコンテキストに追加されます。プロンプトに補足情報を付与するのに使えます。
設定例: プロンプトのコンテキスト補強
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "echo '補足: 現在のブランチは '$(git branch --show-current)' です。直近のコミット: '$(git log --oneline -1)"
}
]
}
]
}
}
この設定により、ユーザーが何を入力しても、Claude には「現在のブランチ名」と「直近のコミット」の情報が自動的に追加されます。
3. PreToolUse ── ツール実行前の制御
🎯 一言で言うと: ツールが実行される前に許可・拒否・変更ができる、最も強力なフック
いつ発火するか
Claude がツール(Bash, Edit, Write, Read 等)を呼び出す直前。
Matcher: ツール名(正規表現)
| Matcher例 | マッチ対象 |
|---|---|
Bash |
Bash コマンドの実行 |
Edit|Write |
ファイルの編集または書き込み |
Notebook.* |
Notebook 系ツール全般 |
mcp__github__.* |
GitHub MCP サーバーの全ツール |
入力フィールド
| フィールド | 説明 |
|---|---|
tool_name |
ツール名(例: "Bash", "Edit") |
tool_input |
ツールに渡される入力パラメータ |
ブロック: 可能
豊富な Decision Control
PreToolUse は最も細かい制御ができるイベントです。
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "本番データベースへの直接アクセスは禁止されています"
}
}
permissionDecision |
効果 |
|---|---|
"allow" |
ツール実行を許可(権限プロンプトをスキップ) |
"deny" |
ツール実行を拒否 |
"ask" |
ユーザーに権限確認を表示 |
さらに、updatedInput でツール入力を書き換えたり、addedContext で Claude に追加情報を注入したりもできます。
設定例: 危険なコマンドをブロック
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); CMD=$(echo \"$INPUT\" | jq -r '.tool_input.command'); case \"$CMD\" in *'rm -rf'*|*'drop table'*|*'DROP TABLE'*) echo '{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"危険なコマンドです\"}}' && exit 0;; esac"
}
]
}
]
}
}
4. PermissionRequest ── 権限確認の自動化
🎯 一言で言うと: 「このツールを実行していいですか?」のダイアログを自動で判定する
いつ発火するか
Claude がツールを実行しようとして権限確認が必要になったとき、ダイアログが表示される直前。
Matcher: ツール名
PreToolUse と同じツール名でフィルタ可能。
ブロック: 可能
Exit 2 で権限を拒否します。
Decision Control
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow",
"applyPermissionRule": "always"
}
}
}
applyPermissionRule: "always" を指定すると、同じパターンの次回以降の権限確認を永続的にスキップするルールが追加されます。
PreToolUse との違い
| 比較 | PreToolUse | PermissionRequest |
|---|---|---|
| 発火タイミング | ツール実行前(常に) | 権限が必要なときだけ |
| 主な用途 | ツール実行のブロック・変更 | 権限の自動許可・拒否 |
allow の意味 |
権限プロンプトをスキップ | 権限を自動許可 |
設定例: 安全なコマンドを自動承認
{
"hooks": {
"PermissionRequest": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); CMD=$(echo \"$INPUT\" | jq -r '.tool_input.command'); case \"$CMD\" in 'npm test'|'npm run lint'|'npm run build') echo '{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"allow\"}}}';; esac"
}
]
}
]
}
}
5. PostToolUse ── ツール実行後の後処理
🎯 一言で言うと: ツールが正常に実行された後にフォーマッタやリンターを走らせる
いつ発火するか
ツールが成功した直後。
Matcher: ツール名
入力フィールド
| フィールド | 説明 |
|---|---|
tool_name |
ツール名 |
tool_input |
ツール入力パラメータ |
tool_result |
ツール実行結果 |
ブロック: 不可
ツールは既に実行済みなので、ブロックはできません。ただし decision: "block" を返すと、Claude に対して「問題があった」というフィードバックを送れます。
設定例: ファイル編集後にフォーマッタを自動実行
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); FILE=$(echo \"$INPUT\" | jq -r '.tool_input.file_path // .tool_input.path'); if [ -n \"$FILE\" ] && echo \"$FILE\" | grep -qE '\\.(ts|tsx|js|jsx)$'; then npx prettier --write \"$FILE\" 2>/dev/null; fi",
"statusMessage": "コードフォーマット中..."
}
]
}
]
}
}
6. PostToolUseFailure ── ツール失敗時のハンドリング
🎯 一言で言うと: ツールがエラーで失敗した後にログ記録やカスタムフィードバックを行う
いつ発火するか
ツール実行がエラーで終了した直後。
入力フィールド
| フィールド | 説明 |
|---|---|
tool_name |
ツール名 |
tool_input |
ツール入力パラメータ |
tool_error |
エラー情報 |
ブロック: 不可
ツールは既に失敗済みです。decision: "block" で Claude にフィードバックを送れます。
設定例: ツール失敗をログに記録
{
"hooks": {
"PostToolUseFailure": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); echo \"$(date -u +%Y-%m-%dT%H:%M:%SZ) | $(echo \"$INPUT\" | jq -r '.tool_name') | $(echo \"$INPUT\" | jq -r '.tool_error' | head -c 200)\" >> ~/.claude/tool-failures.log"
}
]
}
]
}
}
7. Notification ── 通知イベント
🎯 一言で言うと: Claude Code の UI イベント(権限確認ダイアログ表示など)に反応する
いつ発火するか
権限確認ダイアログ、アイドル状態プロンプト、認証成功などの UI イベント発生時。
よくある誤解: 「Claude の応答完了」で Notification は発火しません。応答完了で発火するのは Stop イベントです。
Matcher: 通知タイプ
| Matcher値 | 意味 |
|---|---|
permission_prompt |
権限確認ダイアログが表示された |
idle_prompt |
アイドル状態のプロンプト |
auth_success |
認証が成功した |
ブロック: 不可
設定例: 権限確認が表示されたら音で知らせる
バックグラウンドで Claude を走らせているとき、権限確認を見逃さないための設定です。
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{
"type": "command",
"command": "afplay /System/Library/Sounds/Ping.aiff"
}
]
}
]
}
}
afplay は macOS 専用のコマンドです。Linux の場合は paplay や aplay を使ってください。
8. SubagentStart ── サブエージェント起動
🎯 一言で言うと: サブエージェントが生成されたことを検知する
いつ発火するか
Claude がサブエージェント(タスク実行のための子プロセス)を起動した直後。
Matcher: エージェントタイプ
| Matcher値の例 | 意味 |
|---|---|
Bash |
Bash エージェント |
Explore |
探索エージェント |
Plan |
計画エージェント |
入力フィールド
| フィールド | 説明 |
|---|---|
agent_type |
エージェントタイプ |
agent_id |
エージェント識別子 |
ブロック: 不可
設定例: サブエージェントの活動をログ
{
"hooks": {
"SubagentStart": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); echo \"[START] $(date +%H:%M:%S) $(echo \"$INPUT\" | jq -r '.agent_type') ($(echo \"$INPUT\" | jq -r '.agent_id'))\" >> ~/.claude/agent-activity.log"
}
]
}
]
}
}
9. SubagentStop ── サブエージェント完了
🎯 一言で言うと: サブエージェントの完了を検知し、必要なら続行させる
いつ発火するか
サブエージェントの処理が完了した時点。
ブロック: 可能
Exit 2 でサブエージェントの停止を防ぎ、処理を続行させることができます。
{
"decision": "block",
"reason": "まだタスクが完了していません。追加の検証を行ってください。"
}
Skills や Agents のフロントマターで Stop フックを定義すると、自動的に SubagentStop に変換されます。
10. Stop ── Claude の応答完了
🎯 一言で言うと: Claude が応答を終えたときに品質チェックや通知を行う、非常に実用的なフック
いつ発火するか
Claude のエージェントループが終了し、ユーザーの次の入力を待つ直前。
Matcher: なし(常に発火)
入力フィールド
| フィールド | 説明 |
|---|---|
stop_reason |
停止理由 |
stop_ts |
停止タイムスタンプ |
ブロック: 可能 ← ここが面白い!
Exit 2 で Claude の停止を防ぎ、応答を続行させることができます。これにより「テストが通るまで止まるな」のような強力な制御が実現できます。
設定例: 応答完了時に通知音
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "afplay /System/Library/Sounds/Glass.aiff"
}
]
}
]
}
}
設定例: テストが通るまで停止させない
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "npm test 2>&1 || (echo 'テストが失敗しています。修正を続けてください。' >&2 && exit 2)",
"timeout": 120,
"statusMessage": "テスト実行中..."
}
]
}
]
}
}
11. TeammateIdle ── チームメイトのアイドル制御
🎯 一言で言うと: Agent Teams のチームメイトがアイドルになるのを防ぐ
いつ発火するか
エージェントチームのチームメイトが作業を終え、アイドル状態に遷移しようとするとき。
ブロック: 可能
Exit 2 でアイドル化を防ぎ、stderr のフィードバックをチームメイトに渡して作業を続行させます。
Agent Teams 機能を使用していない場合、このイベントは発火しません。
12. TaskCompleted ── タスク完了の品質ゲート
🎯 一言で言うと: タスクが「完了」とマークされる前に品質チェックを行う
いつ発火するか
タスクが完了状態に遷移する直前。
ブロック: 可能
Exit 2 でタスク完了のマークを防ぎます。CI/CD のゲートチェックのようなイメージです。
設定例: テスト未通過のタスク完了を防ぐ
{
"hooks": {
"TaskCompleted": [
{
"hooks": [
{
"type": "command",
"command": "npm test 2>&1 || (echo 'テストが失敗しているため、タスクを完了できません' >&2 && exit 2)",
"timeout": 120
}
]
}
]
}
}
13. PreCompact ── コンテキスト圧縮前
🎯 一言で言うと: コンテキストが圧縮される前にログや保存処理を行う
いつ発火するか
コンテキストが長くなりすぎて圧縮が必要になったとき、または手動でコンパクションが実行されたとき。
Matcher: トリガー方法
| Matcher値 | 意味 |
|---|---|
manual |
ユーザーが手動で実行 |
auto |
自動的にトリガー |
ブロック: 不可
設定例
{
"hooks": {
"PreCompact": [
{
"matcher": "auto",
"hooks": [
{
"type": "command",
"command": "echo \"[$(date)] Auto-compaction triggered\" >> ~/.claude/compact.log"
}
]
}
]
}
}
14. SessionEnd ── セッション終了
🎯 一言で言うと: セッション終了時のクリーンアップやログ書き込みを行う
いつ発火するか
セッションが何らかの理由で終了する時点。
Matcher: 終了理由
| Matcher値 | 意味 |
|---|---|
clear |
コンテキストがクリアされた |
logout |
ログアウト |
prompt_input_exit |
プロンプト入力から終了 |
other |
その他の理由 |
ブロック: 不可
セッション終了は止められません。
設定例: セッション統計の記録
{
"hooks": {
"SessionEnd": [
{
"matcher": ".*",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); echo \"Session $(echo \"$INPUT\" | jq -r '.session_id') ended ($(echo \"$INPUT\" | jq -r '.reason')) at $(date)\" >> ~/.claude/session-history.log"
}
]
}
]
}
}
実践ユースケース集
ここでは、実際の開発で役立つユースケースをいくつか紹介します。
ユースケース 1: 開発環境の自動セットアップ
セッション開始時に必要な環境情報を Claude に渡し、環境変数も設定する。
{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "echo '{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"env\":{\"NODE_ENV\":\"development\",\"DB_HOST\":\"localhost\"}}}' && echo 'プロジェクト: '$(basename $(pwd))' | Node: '$(node -v)' | ブランチ: '$(git branch --show-current 2>/dev/null || echo 'N/A')"
}
]
}
]
}
}
ユースケース 2: 包括的なファイル編集ガードレール
ファイル編集前に対象を検証し、編集後にフォーマッタとリンターを自動実行。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); FILE=$(echo \"$INPUT\" | jq -r '.tool_input.file_path // .tool_input.path'); if echo \"$FILE\" | grep -qE '(node_modules|dist|build|.min.)'; then echo '{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"生成物・依存ファイルの編集は禁止されています\"}}'; fi"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); FILE=$(echo \"$INPUT\" | jq -r '.tool_input.file_path // .tool_input.path'); if echo \"$FILE\" | grep -qE '\\.(ts|tsx|js|jsx)$'; then npx prettier --write \"$FILE\" 2>/dev/null && npx eslint --fix \"$FILE\" 2>/dev/null; fi",
"statusMessage": "フォーマット & リント実行中..."
}
]
}
]
}
}
ユースケース 3: AI による品質ゲート
Claude の応答完了時に、別の LLM がコード品質を自動チェック。
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "agent",
"prompt": "直前の変更内容を確認し、以下を検証してください:\n1. テストファイルが存在するか\n2. TypeScriptの型エラーがないか\n3. セキュリティ上の問題がないか\n問題があればblockしてください。",
"timeout": 60
}
]
}
]
}
}
ユースケース 4: Slack 通知連携
長時間のタスクが完了したら Slack に通知を送る。
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "curl -s -X POST -H 'Content-Type: application/json' -d '{\"text\":\"Claude Codeの処理が完了しました\"}' $SLACK_WEBHOOK_URL",
"async": true
}
]
}
]
}
}
ユースケース 5: 機密情報の流出防止
プロンプトに API キーやパスワードが含まれていないかチェック。
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); PROMPT=$(echo \"$INPUT\" | jq -r '.prompt'); if echo \"$PROMPT\" | grep -qiE '(api[_-]?key|secret|password|token)\\s*[:=]\\s*[\"'\\''\\w]'; then echo '{\"decision\":\"block\",\"reason\":\"機密情報が含まれている可能性があります。プロンプトから除去してください。\"}'; fi"
}
]
}
]
}
}
ユースケース 6: git push の保護
main ブランチへの force push を絶対に防ぐ。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); CMD=$(echo \"$INPUT\" | jq -r '.tool_input.command'); if echo \"$CMD\" | grep -qE 'git\\s+push.*--force.*main|git\\s+push.*-f.*main'; then echo '{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"mainブランチへのforce pushは禁止されています\"}}'; fi"
}
]
}
]
}
}
セキュリティに関する注意点
Hooks は強力な機能ですが、セキュリティにも配慮が必要です。
- フックはユーザー権限で実行される ── フックが実行できることは、あなたのターミナルで実行できることと同じ
- 外部からの設定変更に注意 ── セッション起動後にフック設定が外部から変更された場合、Claude Code は警告を表示する
- stdout に機密情報を出力しない ── verbose モードで表示される可能性がある
-
disableAllHooks: trueで全フックを一時的に無効化できる -
エンタープライズ管理者は
allowManagedHooksOnlyでユーザー定義フックをブロック可能
よくあるハマりポイント
存在しないイベント名
以下のイベント名は存在しません。設定すると Invalid key in record エラーになります。
| ❌ 間違い | ✅ 正しい代替 |
|---|---|
PostResponse |
Stop(応答完了時に使う) |
PreResponse |
UserPromptSubmit(プロンプト処理前に使う) |
OnError |
PostToolUseFailure(ツール失敗後に使う) |
設定が反映されない
設定ファイルを直接編集した場合、セッションの再起動が必要です。もしくは /hooks メニューで確認してください。
shell profile による JSON パースエラー
.bashrc や .zshrc で echo している場合、フックの stdout に余計なテキストが混入して JSON パースが失敗することがあります。フックスクリプトでは #!/bin/bash --norc を使うか、不要な出力がないか確認してください。
まとめ
Claude Code Hooks は、開発ワークフローを大幅にカスタマイズできる強力な仕組みです。
| やりたいこと | 使うイベント |
|---|---|
| 環境の初期化 | SessionStart |
| プロンプトの検証・補強 | UserPromptSubmit |
| 危険なコマンドのブロック | PreToolUse |
| 権限確認の自動化 | PermissionRequest |
| ファイル編集後の自動フォーマット | PostToolUse |
| エラーのログ記録 | PostToolUseFailure |
| バックグラウンド動作中の通知 | Notification |
| サブエージェントの監視 |
SubagentStart / SubagentStop
|
| 応答完了時の品質チェック | Stop |
| タスクの品質ゲート | TaskCompleted |
| セッション統計の記録 | SessionEnd |
まずは Stop イベントで応答完了時の通知音から始めてみることをおすすめします。たった数行の設定で、Claude Code の体験が大きく変わるはずです。
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "afplay /System/Library/Sounds/Glass.aiff"
}
]
}
]
}
}
この設定を ~/.claude/settings.json に追加するだけ。Claude がバックグラウンドで作業を終えたら、すぐに気づけるようになります。
ぜひ自分の開発ワークフローに合った Hooks を見つけて、Claude Code をさらに便利にカスタマイズしてみてください。
関連記事
本記事の知識を使って、リアルタイムダッシュボードを実際に作る続編を書きました。
- Claude Code Hooks 実践編 ── 全操作を可視化するリアルタイムダッシュボードを作る — コード全体のウォークスルー
- Claude Code Hooks でリアルタイム監視基盤を設計する ── アーキテクチャ解説 — 設計判断の深掘り
- Claude Code Hooks 活用パターン集 ── ダッシュボード開発で学んだ実践Tips — 実践パターンとTips