Claude Codeでの開発中、「ファイル保存のたびにフォーマッターを手動で実行している」「危険なコマンドをうっかり許可してしまった」といった経験はないでしょうか。hooks機能を活用すると、こうした反復作業や見落としをシェルコマンドやLLM判定で自動化できます。

Claude Code hooksとは、Claude Codeのライフサイクル上の決まったタイミングで自動実行されるユーザー定義のコマンド群です。LLMの判断に頼らず確定的(deterministic)に動作するため、「必ず実行してほしい処理」に適しています。

hooksの基本構造と設定ファイル

hooksの設定はJSON形式で記述し、3つの階層で構成されます。

  1. イベント名(いつ発火するか)
  2. マッチャーグループ(どのツール・条件で絞り込むか)
  3. ハンドラ配列(何を実行するか)
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}

設定ファイルの配置場所とスコープ

設定ファイルの置き場所によって適用範囲が変わります。

配置先適用範囲リポジトリ共有
~/.claude/settings.json全プロジェクト共通不可(ローカルのみ)
.claude/settings.jsonプロジェクト単位可能(git commit対象)
.claude/settings.local.jsonプロジェクト単位不可(.gitignore推奨)
マネージドポリシー組織全体管理者が制御
プラグイン hooks/hooks.jsonプラグイン有効時プラグインに同梱
スキル・エージェントのfrontmatterコンポーネント稼働中のみコンポーネントに定義

チームで統一したいルール(自動フォーマット等)は .claude/settings.json、個人環境だけに適用する通知設定は ~/.claude/settings.json に置く、という使い分けが実務では効果的です。

/hooksメニューによる対話的な設定

CLIで /hooks と入力すると、GUIライクなメニューが開きます。JSONを直接編集しなくても、イベント選択→マッチャー指定→コマンド入力→保存先選択の流れで設定を追加できます。

メニュー内ではフックごとにソースラベルが表示されます。

  • [User]: ~/.claude/settings.json
  • [Project]: .claude/settings.json
  • [Local]: .claude/settings.local.json
  • [Plugin]: プラグイン同梱のhooks

全hooksを一括で無効化するトグルもこのメニューに用意されています。

全14イベントの一覧と使い分け

2026年2月時点でClaude Code hooksが対応するイベントは14種類です。セッションの開始から終了まで、ライフサイクル順に並べます。

イベント発火タイミングブロック可否
SessionStartセッション開始・再開時不可
UserPromptSubmitユーザーがプロンプトを送信した直後(処理前)可能
PreToolUseツール実行の直前可能
PermissionRequest権限ダイアログ表示時可能
PostToolUseツール実行成功の直後不可(実行済み)
PostToolUseFailureツール実行失敗の直後不可(失敗済み)
Notification通知送信時不可
SubagentStartサブエージェント起動時不可
SubagentStopサブエージェント完了時可能
Stopメインエージェントの応答完了時可能
TeammateIdleチームメイトがアイドル移行する直前可能
TaskCompletedタスク完了マーク時可能
PreCompactコンテキスト圧縮の直前不可
SessionEndセッション終了時不可

マッチャーの動作と正規表現パターン

マッチャーはイベントごとに異なるフィールドに対して正規表現で照合されます。

イベントマッチ対象記述例
PreToolUse / PostToolUse / PostToolUseFailure / PermissionRequestツール名BashEdit|Writemcp__.*
SessionStart開始方法startupresumeclearcompact
SessionEnd終了理由clearlogoutprompt_input_exitbypass_permissions_disabledother
Notification通知タイプpermission_promptidle_promptauth_successelicitation_dialog
SubagentStart / SubagentStopエージェント種別BashExplorePlan、カスタムエージェント名
PreCompactトリガーmanualauto
UserPromptSubmit / Stop / TeammateIdle / TaskCompletedなし全発火時に実行(マッチャー非対応)

マッチャーを省略するか "*" と書くと、該当イベントの全発火に対してhookが実行されます。

MCPツールへのhook適用

MCPサーバーのツールにもhooksを適用できます。ツール名は mcp__<サーバー名>__<ツール名> の形式です。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "mcp__github__.*",
        "hooks": [
          {
            "type": "command",
            "command": "echo \"GitHub MCP tool called\" >> ~/mcp-ops.log"
          }
        ]
      }
    ]
  }
}

mcp__memory__.* のようにサーバー単位での一括指定や、mcp__.*__write.* のように全サーバーの書き込み系操作を横断して捕捉する書き方も可能です。

hookハンドラの3タイプ:command / prompt / agent

hookが発火したとき実行される処理は3種類から選択できます。

commandタイプ(シェルコマンド)

もっとも基本的な方式です。シェルコマンドを直接実行し、stdin経由でイベントのJSON情報を受け取ります。

{
  "type": "command",
  "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/lint-check.sh",
  "timeout": 30
}
フィールド必須説明
type"command"
command実行するシェルコマンド
timeout×タイムアウト秒数(デフォルト: 600)
async×true で非同期実行(結果は次ターンで配信)
statusMessage×実行中にスピナーに表示するメッセージ
once×true でセッション中に1回だけ実行(スキル限定)

promptタイプ(LLM単発判定)

シェルコマンドではなく、Claudeモデル(デフォルトはHaiku)にプロンプトを送って判定させる方式です。$ARGUMENTS プレースホルダにイベントのJSONが展開されます。

{
  "type": "prompt",
  "prompt": "以下のコンテキストを確認し、全タスクが完了しているか判定してください: $ARGUMENTS",
  "timeout": 30
}

モデルは {"ok": true} または {"ok": false, "reason": "理由"} のJSON形式で応答します。

agentタイプ(マルチターン検証)

promptタイプをさらに拡張し、サブエージェントがRead・Grep・Globなどのツールを使いながら最大50ターンにわたって検証する方式です。

{
  "type": "agent",
  "prompt": "テストスイートを実行し、全テストが通過しているか確認してください。$ARGUMENTS",
  "timeout": 120
}

3タイプの選定基準

観点commandpromptagent
判定の性質確定的ルールLLMの判断LLM+ツール調査
実行速度最速数秒数十秒〜
非同期対応async: true で可能不可不可
デフォルトタイムアウト600秒30秒60秒
適用例フォーマッタ実行、ファイル保護コード品質の定性チェックテスト実行結果の包括検証

「rm -rf を含むコマンドをブロックする」のような明確なルールにはcommand、「実装が完了しているか総合判定する」のような曖昧な基準にはpromptまたはagentが適しています。

stdin入力とstdout出力の仕様

共通入力フィールド

全イベントで共通して受け取るJSON構造は次の通りです。

{
  "session_id": "abc123",
  "transcript_path": "/home/user/.claude/projects/.../transcript.jsonl",
  "cwd": "/home/user/my-project",
  "permission_mode": "default",
  "hook_event_name": "PreToolUse"
}

イベントごとに tool_nametool_inputpromptsource などの固有フィールドが追加されます。

終了コードによる制御

終了コード意味動作
0成功stdoutのJSONを解析し、アクション続行
2ブロックエラーstderrのメッセージをClaudeにフィードバックし、アクションを中止
その他非ブロックエラーstderrをverboseモードで表示し、アクション続行

JSON出力による詳細制御

終了コード0でJSONを出力すると、より細かい振る舞いを指定できます。

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "grep よりも rg を使ってください"
  }
}

PreToolUse のパーミッション判定は3段階です。

動作
"allow"パーミッションダイアログをスキップして実行許可
"deny"ツール実行を拒否し、理由をClaudeに通知
"ask"通常通りユーザーに確認を求める

全イベント共通で使えるフィールドもあります。

フィールド説明
continuefalse にするとClaude全体の処理を停止
stopReasoncontinue: false 時にユーザーに表示するメッセージ
suppressOutputtrue でverboseモードへのstdout表示を抑制
systemMessageユーザーへの警告メッセージ

実践レシピ:すぐに使えるhook設定5選

1. ファイル編集後の自動フォーマット

開発現場で最も導入効果の高いhookです。Prettierを例にしますが、Black(Python)やrustfmt(Rust)など任意のフォーマッターに差し替え可能です。

.claude/settings.json に追加します。

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}

PostToolUseイベントはツール実行完了後に発火するため、Claudeが書き込んだファイルに対して即座にフォーマッターが走ります。

2. 危険コマンドのブロック

rm -rfDROP TABLE のような破壊的コマンドを実行前に検知して拒否するスクリプトです。

.claude/hooks/block-dangerous.sh:

#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')

BLOCKED_PATTERNS=("rm -rf" "DROP TABLE" "DROP DATABASE" "format c:" "> /dev/sda")

for pattern in "${BLOCKED_PATTERNS[@]}"; do
  if echo "$COMMAND" | grep -qi "$pattern"; then
    echo "ブロック: '$pattern' を含むコマンドは実行できません" >&2
    exit 2
  fi
done

exit 0

.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-dangerous.sh"
          }
        ]
      }
    ]
  }
}

3. デスクトップ通知(OS別)

Claudeが入力待ちや権限確認で停止したとき、デスクトップ通知を送る設定です。ターミナルを常時監視する必要がなくなります。

~/.claude/settings.json に追加します。

macOS:

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Codeが入力を待っています\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

Linux(notify-send):

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "notify-send 'Claude Code' 'Claude Codeが入力を待っています'"
          }
        ]
      }
    ]
  }
}

WSL / Windows:

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "powershell.exe -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Claude Codeが入力を待っています', 'Claude Code')\""
          }
        ]
      }
    ]
  }
}

4. センシティブファイルの保護

.env、秘密鍵、ロックファイルなど変更してほしくないファイルへの書き込みをPreToolUseで防ぎます。

.claude/hooks/protect-files.sh:

#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

PROTECTED_PATTERNS=(".env" ".git/" "id_rsa" "id_ed25519" "package-lock.json" "yarn.lock" "Cargo.lock")

for pattern in "${PROTECTED_PATTERNS[@]}"; do
  if [[ "$FILE_PATH" == *"$pattern"* ]]; then
    echo "保護対象: $FILE_PATH は '$pattern' に該当するため編集をブロックしました" >&2
    exit 2
  fi
done

exit 0
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}

5. コンテキスト圧縮後の情報再注入

Claude Codeはコンテキストウィンドウが逼迫すると自動圧縮(compaction)を実行します。圧縮時にプロジェクト固有の注意事項が失われることがあるため、SessionStartイベントの compact マッチャーで再注入するのが有効です。

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "compact",
        "hooks": [
          {
            "type": "command",
            "command": "echo '注意: パッケージマネージャーはpnpmを使用。テストはvitest。コミット前にlint必須。'"
          }
        ]
      }
    ]
  }
}

stdoutに出力したテキストがClaudeのコンテキストに追加されるため、動的な情報(直近のgitログなど)も注入可能です。

echo "直近のコミット:" && git log --oneline -5

非同期hookの活用

テストスイートの実行やデプロイなど完了まで時間がかかる処理は、"async": true を指定してバックグラウンド実行できます。

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/run-tests-async.sh",
            "async": true,
            "timeout": 300
          }
        ]
      }
    ]
  }
}

非同期hookの特性は次の通りです。

  • Claudeの処理をブロックせず、バックグラウンドで実行される
  • decisionpermissionDecision による判定制御は無効(既にアクションが進行済み)
  • 実行結果は次の会話ターンで systemMessage / additionalContext として配信される
  • commandタイプ限定(prompt / agentは非対応)

環境変数の永続化(CLAUDE_ENV_FILE)

SessionStartイベント限定で利用可能な CLAUDE_ENV_FILE 環境変数を使うと、セッション中に実行されるすべてのBashコマンドに環境変数を引き継がせることができます。

#!/bin/bash
if [ -n "$CLAUDE_ENV_FILE" ]; then
  echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE"
  echo 'export PATH="$PATH:./node_modules/.bin"' >> "$CLAUDE_ENV_FILE"
fi
exit 0

nvmやrbenvなどバージョンマネージャーの切り替え結果を永続化するパターンも有効です。

#!/bin/bash
ENV_BEFORE=$(export -p | sort)
source ~/.nvm/nvm.sh
nvm use 20
if [ -n "$CLAUDE_ENV_FILE" ]; then
  ENV_AFTER=$(export -p | sort)
  comm -13 <(echo "$ENV_BEFORE") <(echo "$ENV_AFTER") >> "$CLAUDE_ENV_FILE"
fi
exit 0

セキュリティのベストプラクティス

hooksはユーザーのシステム権限で動作します。悪意のある設定やミスは深刻な被害に直結するため、以下の対策を徹底してください。

対策具体的な実施方法
入力値の検証stdin経由のJSONは必ずバリデーション
シェル変数のクォート"$VAR" の形式で展開(スペース・特殊文字対策)
パストラバーサル対策ファイルパスに .. が含まれていないか検査
絶対パスの使用$CLAUDE_PROJECT_DIR でプロジェクトルートを参照
センシティブファイル除外.env.git/、秘密鍵を処理対象から除外
信頼できないプロジェクトへの警戒外部リポジトリの .claude/settings.json にhooksが仕込まれていないか確認

hooksの設定はセッション開始時にスナップショットとして読み込まれます。セッション途中で外部からファイルが書き換えられても即座に反映されないため、サプライチェーン攻撃に対する一定の防御が働きます。変更が検知された場合は /hooks メニューでレビューが求められます。

トラブルシューティング

hookが発火しない

  • /hooks で正しいイベントに登録されているか確認
  • マッチャーの正規表現がツール名と正確に一致しているか確認(大文字小文字の区別あり)
  • PermissionRequest hookは非対話モード(-p)では発火しません。PreToolUse を使ってください

Stopイベントの無限ループ

Stopイベントのhookが exit 2"decision": "block" を常に返すと、Claudeが停止できず無限ループに陥ります。入力JSONの stop_hook_active フィールドを必ず確認してください。

#!/bin/bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
  exit 0  # 二重発火を防止
fi
# ... 本来のチェック処理

JSON出力のパースエラー

~/.zshrc~/.bashrc に無条件の echo 文があると、hookスクリプトのstdoutにゴミが混入してJSONパースに失敗します。

# ~/.zshrc で対話シェルのみに限定
if [[ $- == *i* ]]; then
  echo "Shell ready"
fi

デバッグ方法

claude --debug で起動すると、hookのマッチング結果・終了コード・出力内容が詳細に表示されます。Ctrl+O でverboseモードを切り替えることもできます。

[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Found 1 hook matchers in settings
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Hook command completed with status 0: <出力内容>

スクリプト単体のテストはパイプでJSONを流し込む方法が確実です。

echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh
echo $?

hooksとCLAUDE.md・MCPサーバーの使い分け

Claude Codeには拡張ポイントが複数あり、用途に応じて選択する必要があります。

機能性質適した用途
hooks確定的・自動実行フォーマット、ブロック、通知、ログ
CLAUDE.mdLLMへの指示テキストコーディング規約、プロジェクトルール
MCPサーバー外部ツール連携DB操作、API呼び出し、ファイルシステム拡張
スキル呼び出し可能な手順書定型タスクの手順化(hookをfrontmatterで同梱可能)
サブエージェント隔離コンテキストでの並列実行調査、テスト、独立タスク

hooksは「LLMが忘れてもルールどおりに動く仕組み」、CLAUDE.mdは「LLMに知っておいてほしい背景情報」と整理すると迷いが減ります。

よくある質問

Q. hooksの実行順序は? 同一イベント・同一マッチャーに複数のhookが登録されている場合、並列に実行されます。完全に同一のコマンドは自動で重複排除されます。

Q. hooksは非対話モード(claude -p)でも動作しますか? PermissionRequest を除く全イベントが動作します。CI/CDパイプラインでも活用可能です。

Q. hookスクリプトから別のツールを呼び出せますか? hooksの通信手段はstdin / stdout / stderr / 終了コードに限定されます。Claude Codeのツール(Edit、Writeなど)を直接呼び出す仕組みはありません。外部コマンド(git、npm、curlなど)はシェル経由で自由に実行できます。

Q. updatedInput で何ができますか? PreToolUseまたはPermissionRequestのhookで、ツールに渡される入力パラメータを実行前に書き換えられます。たとえばBashコマンドの引数を安全な値に差し替えるといった使い方が可能です。

まとめ

Claude Code hooksは、全14イベント・3種類のハンドラタイプで開発ワークフローを精密に自動化できる拡張機構です。

セットアップの第一歩としておすすめの順序は次の通りです。

  1. 通知hook(Notification): ターミナル監視からの解放
  2. 自動フォーマット(PostToolUse + Edit|Write): コードスタイルの自動統一
  3. ファイル保護(PreToolUse + Edit|Write): センシティブファイルの誤編集防止
  4. 危険コマンドブロック(PreToolUse + Bash): 破壊的操作の抑止

公式ドキュメントは以下から確認できます。