例を含むクイックスタート ガイドについては、Claude Code フックの開始 を参照してください。

設定

Claude Code フックは、設定ファイル で設定されます:

  • ~/.claude/settings.json - ユーザー設定
  • .claude/settings.json - プロジェクト設定
  • .claude/settings.local.json - ローカル プロジェクト設定(コミットされない)
  • エンタープライズ管理ポリシー設定

構造

フックはマッチャーによって整理され、各マッチャーは複数のフックを持つことができます:

{
  "hooks": {
    "EventName": [
      {
        "matcher": "ToolPattern",
        "hooks": [
          {
            "type": "command",
            "command": "your-command-here"
          }
        ]
      }
    ]
  }
}
  • matcher: ツール名にマッチするパターン、大文字小文字を区別(PreToolUsePostToolUse にのみ適用)
    • 単純な文字列は完全一致:Write は Write ツールのみにマッチ
    • 正規表現をサポート:Edit|Write または Notebook.*
    • すべてのツールにマッチするには * を使用。空文字列("")を使用するか、matcher を空白のままにすることもできます。
  • hooks: パターンがマッチしたときに実行するコマンドの配列
    • type: 現在は "command" のみサポート
    • command: 実行する bash コマンド($CLAUDE_PROJECT_DIR 環境変数を使用可能)
    • timeout: (オプション)特定のコマンドをキャンセルするまでの実行時間(秒)

UserPromptSubmitNotificationStopSubagentStop などのマッチャーを使用しないイベントでは、matcher フィールドを省略できます:

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/prompt-validator.py"
          }
        ]
      }
    ]
  }
}

プロジェクト固有のフック スクリプト

環境変数 CLAUDE_PROJECT_DIR(Claude Code がフック コマンドを起動するときのみ利用可能)を使用して、プロジェクトに保存されたスクリプトを参照できます。これにより、Claude の現在のディレクトリに関係なく動作することが保証されます:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/check-style.sh"
          }
        ]
      }
    ]
  }
}

フック イベント

PreToolUse

Claude がツール パラメーターを作成した後、ツール呼び出しを処理する前に実行されます。

一般的なマッチャー:

  • Task - サブエージェント タスク(サブエージェント ドキュメント を参照)
  • Bash - シェル コマンド
  • Glob - ファイル パターン マッチング
  • Grep - コンテンツ検索
  • Read - ファイル読み取り
  • EditMultiEdit - ファイル編集
  • Write - ファイル書き込み
  • WebFetchWebSearch - Web 操作

PostToolUse

ツールが正常に完了した直後に実行されます。

PreToolUse と同じマッチャー値を認識します。

Notification

Claude Code が通知を送信するときに実行されます。通知は以下の場合に送信されます:

  1. Claude がツールを使用する許可が必要な場合。例:「Claude needs your permission to use Bash」
  2. プロンプト入力が少なくとも 60 秒間アイドル状態の場合。「Claude is waiting for your input」

UserPromptSubmit

ユーザーがプロンプトを送信したとき、Claude が処理する前に実行されます。これにより、プロンプト/会話に基づいて追加のコンテキストを追加したり、プロンプトを検証したり、特定の種類のプロンプトをブロックしたりできます。

Stop

メインの Claude Code エージェントが応答を完了したときに実行されます。ユーザーの中断による停止の場合は実行されません。

SubagentStop

Claude Code サブエージェント(Task ツール呼び出し)が応答を完了したときに実行されます。

PreCompact

Claude Code がコンパクト操作を実行しようとする前に実行されます。

マッチャー:

  • manual - /compact から呼び出し
  • auto - 自動コンパクトから呼び出し(コンテキスト ウィンドウが満杯のため)

SessionStart

Claude Code が新しいセッションを開始するか、既存のセッションを再開するとき(現在は内部的に新しいセッションを開始)に実行されます。既存の問題やコードベースへの最近の変更などの開発コンテキストを読み込むのに便利です。

マッチャー:

  • startup - 起動から呼び出し
  • resume - --resume--continue、または /resume から呼び出し
  • clear - /clear から呼び出し
  • compact - 自動または手動コンパクトから呼び出し

SessionEnd

Claude Code セッションが終了するときに実行されます。クリーンアップ タスク、セッション統計のログ記録、またはセッション状態の保存に便利です。

フック入力の reason フィールドは以下のいずれかになります:

  • clear - /clear コマンドでセッションがクリアされた
  • logout - ユーザーがログアウトした
  • prompt_input_exit - プロンプト入力が表示されている間にユーザーが終了した
  • other - その他の終了理由

フック入力

フックは、セッション情報とイベント固有のデータを含む JSON データを stdin 経由で受信します:

{
  // 共通フィールド
  session_id: string
  transcript_path: string  // 会話 JSON へのパス
  cwd: string              // フックが呼び出されたときの現在の作業ディレクトリ

  // イベント固有のフィールド
  hook_event_name: string
  ...
}

PreToolUse 入力

tool_input の正確なスキーマはツールによって異なります。

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "PreToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  }
}

PostToolUse 入力

tool_inputtool_response の正確なスキーマはツールによって異なります。

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "PostToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  },
  "tool_response": {
    "filePath": "/path/to/file.txt",
    "success": true
  }
}

Notification 入力

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "Notification",
  "message": "Task completed successfully"
}

UserPromptSubmit 入力

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "UserPromptSubmit",
  "prompt": "Write a function to calculate the factorial of a number"
}

Stop と SubagentStop 入力

stop_hook_active は、Claude Code がストップ フックの結果として既に継続している場合に true になります。Claude Code が無限に実行されることを防ぐために、この値をチェックするか、トランスクリプトを処理してください。

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "hook_event_name": "Stop",
  "stop_hook_active": true
}

PreCompact 入力

manual の場合、custom_instructions はユーザーが /compact に渡すものから取得されます。auto の場合、custom_instructions は空です。

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "hook_event_name": "PreCompact",
  "trigger": "manual",
  "custom_instructions": ""
}

SessionStart 入力

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "hook_event_name": "SessionStart",
  "source": "startup"
}

SessionEnd 入力

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "SessionEnd",
  "reason": "exit"
}

フック出力

フックが Claude Code に出力を返す方法は 2 つあります。出力は、ブロックするかどうかと、Claude とユーザーに表示すべきフィードバックを伝達します。

シンプル:終了コード

フックは終了コード、stdout、stderr を通じてステータスを伝達します:

  • 終了コード 0: 成功。stdout はトランスクリプト モード(CTRL-R)でユーザーに表示されますが、UserPromptSubmitSessionStart では stdout がコンテキストに追加されます。
  • 終了コード 2: ブロッキング エラー。stderr が Claude に自動的にフィードバックされ処理されます。以下のフック イベント別の動作を参照してください。
  • その他の終了コード: 非ブロッキング エラー。stderr がユーザーに表示され、実行が継続されます。

注意:終了コードが 0 の場合、Claude Code は stdout を見ません。ただし、UserPromptSubmit フックでは stdout がコンテキストとして注入されます。

終了コード 2 の動作

フック イベント動作
PreToolUseツール呼び出しをブロックし、stderr を Claude に表示
PostToolUsestderr を Claude に表示(ツールは既に実行済み)
NotificationN/A、stderr をユーザーのみに表示
UserPromptSubmitプロンプト処理をブロックし、プロンプトを消去し、stderr をユーザーのみに表示
Stop停止をブロックし、stderr を Claude に表示
SubagentStop停止をブロックし、stderr を Claude サブエージェントに表示
PreCompactN/A、stderr をユーザーのみに表示
SessionStartN/A、stderr をユーザーのみに表示
SessionEndN/A、stderr をユーザーのみに表示

高度:JSON 出力

フックは、より洗練された制御のために stdout で構造化 JSON を返すことができます:

共通 JSON フィールド

すべてのフック タイプは、これらのオプション フィールドを含めることができます:

{
  "continue": true, // フック実行後に Claude が継続すべきかどうか(デフォルト:true)
  "stopReason": "string", // continue が false の場合に表示されるメッセージ

  "suppressOutput": true, // トランスクリプト モードから stdout を隠す(デフォルト:false)
  "systemMessage": "string" // ユーザーに表示されるオプションの警告メッセージ
}

continue が false の場合、Claude はフック実行後に処理を停止します。

  • PreToolUse の場合、これは "permissionDecision": "deny" とは異なり、特定のツール呼び出しのみをブロックし、Claude に自動フィードバックを提供します。
  • PostToolUse の場合、これは "decision": "block" とは異なり、Claude に自動フィードバックを提供します。
  • UserPromptSubmit の場合、これはプロンプトが処理されることを防ぎます。
  • StopSubagentStop の場合、これは任意の "decision": "block" 出力よりも優先されます。
  • すべての場合において、"continue" = false は任意の "decision": "block" 出力よりも優先されます。

stopReasoncontinue に伴い、ユーザーに表示される理由を提供しますが、Claude には表示されません。

PreToolUse 決定制御

PreToolUse フックは、ツール呼び出しが進行するかどうかを制御できます。

  • "allow" は許可システムをバイパスします。permissionDecisionReason はユーザーに表示されますが、Claude には表示されません。
  • "deny" はツール呼び出しの実行を防ぎます。permissionDecisionReason は Claude に表示されます。
  • "ask" はユーザーに UI でツール呼び出しを確認するよう求めます。permissionDecisionReason はユーザーに表示されますが、Claude には表示されません。
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow" | "deny" | "ask",
    "permissionDecisionReason": "My reason here"
  }
}

PreToolUse フックの decisionreason フィールドは非推奨です。 代わりに hookSpecificOutput.permissionDecisionhookSpecificOutput.permissionDecisionReason を使用してください。非推奨フィールド "approve""block" はそれぞれ "allow""deny" にマップされます。

PostToolUse 決定制御

PostToolUse フックは、ツール実行後に Claude にフィードバックを提供できます。

  • "block" は自動的に Claude に reason でプロンプトします。
  • undefined は何もしません。reason は無視されます。
  • "hookSpecificOutput.additionalContext" は Claude が考慮するコンテキストを追加します。
{
  "decision": "block" | undefined,
  "reason": "Explanation for decision",
  "hookSpecificOutput": {
    "hookEventName": "PostToolUse",
    "additionalContext": "Additional information for Claude"
  }
}

UserPromptSubmit 決定制御

UserPromptSubmit フックは、ユーザー プロンプトが処理されるかどうかを制御できます。

  • "block" はプロンプトが処理されることを防ぎます。送信されたプロンプトはコンテキストから消去されます。"reason" はユーザーに表示されますが、コンテキストには追加されません。
  • undefined はプロンプトが正常に進行することを許可します。"reason" は無視されます。
  • "hookSpecificOutput.additionalContext" は、ブロックされていない場合に文字列をコンテキストに追加します。
{
  "decision": "block" | undefined,
  "reason": "Explanation for decision",
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "My additional context here"
  }
}

Stop/SubagentStop 決定制御

StopSubagentStop フックは、Claude が継続する必要があるかどうかを制御できます。

  • "block" は Claude の停止を防ぎます。Claude がどのように進行すべきかを知るために、reason を設定する必要があります。
  • undefined は Claude の停止を許可します。reason は無視されます。
{
  "decision": "block" | undefined,
  "reason": "Must be provided when Claude is blocked from stopping"
}

SessionStart 決定制御

SessionStart フックは、セッション開始時にコンテキストを読み込むことができます。

  • "hookSpecificOutput.additionalContext" は文字列をコンテキストに追加します。
  • 複数のフックの additionalContext 値は連結されます。
{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "My additional context here"
  }
}

SessionEnd 決定制御

SessionEnd フックは、セッション終了時に実行されます。セッション終了をブロックすることはできませんが、クリーンアップ タスクを実行できます。

終了コード例:Bash コマンド検証

#!/usr/bin/env python3
import json
import re
import sys

# 検証ルールを(正規表現パターン、メッセージ)タプルのリストとして定義
VALIDATION_RULES = [
    (
        r"\bgrep\b(?!.*\|)",
        "Use 'rg' (ripgrep) instead of 'grep' for better performance and features",
    ),
    (
        r"\bfind\s+\S+\s+-name\b",
        "Use 'rg --files | rg pattern' or 'rg --files -g pattern' instead of 'find -name' for better performance",
    ),
]


def validate_command(command: str) -> list[str]:
    issues = []
    for pattern, message in VALIDATION_RULES:
        if re.search(pattern, command):
            issues.append(message)
    return issues


try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
    sys.exit(1)

tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
command = tool_input.get("command", "")

if tool_name != "Bash" or not command:
    sys.exit(1)

# コマンドを検証
issues = validate_command(command)

if issues:
    for message in issues:
        print(f"• {message}", file=sys.stderr)
    # 終了コード 2 はツール呼び出しをブロックし、stderr を Claude に表示
    sys.exit(2)

JSON 出力例:コン テキスト追加と検証のための UserPromptSubmit

UserPromptSubmit フックの場合、どちらの方法でもコンテキストを注入できます:

  • 終了コード 0 と stdout:Claude がコンテキストを見る(UserPromptSubmit の特別なケース)
  • JSON 出力:動作をより詳細に制御
#!/usr/bin/env python3
import json
import sys
import re
import datetime

# stdin から入力を読み込み
try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
    sys.exit(1)

prompt = input_data.get("prompt", "")

# 機密パターンをチェック
sensitive_patterns = [
    (r"(?i)\b(password|secret|key|token)\s*[:=]", "Prompt contains potential secrets"),
]

for pattern, message in sensitive_patterns:
    if re.search(pattern, prompt):
        # JSON 出力を使用して特定の理由でブロック
        output = {
            "decision": "block",
            "reason": f"Security policy violation: {message}. Please rephrase your request without sensitive information."
        }
        print(json.dumps(output))
        sys.exit(0)

# 現在時刻をコンテキストに追加
context = f"Current time: {datetime.datetime.now()}"
print(context)

"""
以下も同等です:
print(json.dumps({
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": context,
  },
}))
"""

# 追加コンテキストでプロンプトの進行を許可
sys.exit(0)

JSON 出力例:承認付き PreToolUse

#!/usr/bin/env python3
import json
import sys

# stdin から入力を読み込み
try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
    sys.exit(1)

tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})

# 例:ドキュメント ファイルのファイル読み取りを自動承認
if tool_name == "Read":
    file_path = tool_input.get("file_path", "")
    if file_path.endswith((".md", ".mdx", ".txt", ".json")):
        # JSON 出力を使用してツール呼び出しを自動承認
        output = {
            "decision": "approve",
            "reason": "Documentation file auto-approved",
            "suppressOutput": True  # トランスクリプト モードで表示しない
        }
        print(json.dumps(output))
        sys.exit(0)

# その他の場合は、通常の許可フローを進行させる
sys.exit(0)

MCP ツールとの連携

Claude Code フックは Model Context Protocol (MCP) ツール とシームレスに連携します。MCP サーバーがツールを提供する場合、フックでマッチできる特別な命名パターンで表示されます。

MCP ツール命名

MCP ツールは mcp__<server>__<tool> パターンに従います。例:

  • mcp__memory__create_entities - Memory サーバーの create entities ツール
  • mcp__filesystem__read_file - Filesystem サーバーの read file ツール
  • mcp__github__search_repositories - GitHub サーバーの search ツール

MCP ツール用のフック設定

特定の MCP ツールまたは MCP サーバー全体をターゲットにできます:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "mcp__memory__.*",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
          }
        ]
      },
      {
        "matcher": "mcp__.*__write.*",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/scripts/validate-mcp-write.py"
          }
        ]
      }
    ]
  }
}

コード フォーマット、通知、ファイル保護を含む実用的な例については、開始ガイドのその他の例 を参照してください。

セキュリティ上の考慮事項

免責事項

自己責任で使用してください:Claude Code フックは、システム上で任意のシェル コマンドを自動的に実行します。フックを使用することで、以下を認めることになります:

  • 設定するコマンドについて単独で責任を負う
  • フックは、ユーザー アカウントがアクセスできる任意のファイルを変更、削除、またはアクセスできる
  • 悪意のあるまたは不適切に書かれたフックは、データ損失やシステム損傷を引き起こす可能性がある
  • Anthropic は保証を提供せず、フック使用による損害について一切の責任を負わない
  • 本番環境で使用する前に、安全な環境でフックを十分にテストする必要がある

設定に追加する前に、常にフック コマンドを確認し理解してください。

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

より安全なフックを書くための主要なプラクティス:

  1. 入力を検証・サニタイズ - 入力データを盲目的に信頼しない
  2. 常にシェル変数を引用符で囲む - $VAR ではなく "$VAR" を使用
  3. パス トラバーサルをブロック - ファイル パスで .. をチェック
  4. 絶対パスを使用 - スクリプトの完全パスを指定(プロジェクト パスには $CLAUDE_PROJECT_DIR を使用)
  5. 機密ファイルをスキップ - .env.git/、キーなどを避ける

設定の安全性

設定ファイルでのフックの直接編集は、すぐには有効になりません。Claude Code は:

  1. 起動時にフックのスナップショットを取得
  2. セッション全体でこのスナップショットを使用
  3. フックが外部で変更された場合に警告
  4. 変更を適用するために /hooks メニューでの確認が必要

これにより、悪意のあるフック変更が現在のセッションに影響することを防ぎます。

フック実行の詳細

  • タイムアウト:デフォルトで 60 秒の実行制限、コマンドごとに設定可能。
    • 個別のコマンドのタイムアウトは、他のコマンドに影響しません。
  • 並列化:マッチするすべてのフックが並列実行
  • 重複排除:同一のフック コマンドは自動的に重複排除
  • 環境:Claude Code の環境で現在のディレクトリで実行
    • CLAUDE_PROJECT_DIR 環境変数が利用可能で、プロジェクト ルート ディレクトリ(Claude Code が開始された場所)への絶対パスが含まれます
  • 入力:stdin 経由の JSON
  • 出力
    • PreToolUse/PostToolUse/Stop/SubagentStop:トランスクリプト(Ctrl-R)で進行状況表示
    • Notification/SessionEnd:デバッグのみにログ記録(--debug
    • UserPromptSubmit/SessionStart:stdout が Claude のコンテキストとして追加

デバッグ

基本的なトラブルシューティング

フックが動作しない場合:

  1. 設定を確認 - /hooks を実行してフックが登録されているかを確認
  2. 構文を検証 - JSON 設定が有効であることを確認
  3. コマンドをテスト - 最初にフック コマンドを手動で実行
  4. 権限を確認 - スクリプトが実行可能であることを確認
  5. ログを確認 - claude --debug を使用してフック実行の詳細を確認

一般的な問題:

  • 引用符がエスケープされていない - JSON 文字列内で \" を使用
  • 間違ったマッチャー - ツール名が正確にマッチすることを確認(大文字小文字を区別)
  • コマンドが見つからない - スクリプトの完全パスを使用

高度なデバッグ

複雑なフック問題の場合:

  1. フック実行を検査 - claude --debug を使用して詳細なフック実行を確認
  2. JSON スキーマを検証 - 外部ツールでフック入力/出力をテスト
  3. 環境変数を確認 - Claude Code の環境が正しいことを確認
  4. エッジ ケースをテスト - 異常なファイル パスや入力でフックを試す
  5. システム リソースを監視 - フック実行中のリソース枯渇をチェック
  6. 構造化ログを使用 - フック スクリプトでログを実装

デバッグ出力例

claude --debug を使用してフック実行の詳細を確認:

[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
[DEBUG] Found 1 hook matchers in settings
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Found 1 hook commands to execute
[DEBUG] Executing hook command: <Your command> with timeout 60000ms
[DEBUG] Hook command completed with status 0: <Your stdout>

進行状況メッセージは、トランスクリプト モード(Ctrl-R)で以下を表示します:

  • 実行中のフック
  • 実行されるコマンド
  • 成功/失敗ステータス
  • 出力またはエラー メッセージ