mcpField
H
hook-development

hook-development

github.com/josiahsiegelエージェントワークフロー59110 回インストール19 週間前に更新
リポジトリ

hook-development について

Claude Code プラグインのイベント駆動型フックを開発するためのリファレンスです。イベント、設定形式、プロンプト型・コマンド型フック、入出力、セキュリティ、デバッグを説明します。

主な機能

  1. 01フックイベントと用途
  2. 02プラグインと設定の形式
  3. 03プロンプト型・コマンド型フック
  4. 04フックの入出力スキーマ
  5. 05セキュリティとデバッグのガイド

活用シーン

  1. 01ツール操作の検証や制限
  2. 02ファイル変更後のテスト実行
  3. 03セッション開始時のプロジェクト情報読み込み
  4. 04フック設定と出力の確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill hook-development

インストール後、Claude Code で/hook-developmentを入力して読み込まれたか確認します。

詳細

Claude Code プラグイン向けフック開発

概要

フックは、Claude Code のイベントに応じて実行されるイベント駆動型の自動化機能です。フックを使って、操作の検証、ポリシーの適用、コンテキストの読み込み、外部ツールとの統合を行えます。

フックの種類:

  • プロンプトベース(推奨):LLM 主導の、コンテキストを考慮した判断
  • コマンドベース:高速で決定論的なチェックを行うシェルコマンド

フックイベントのリファレンス

イベントタイミング主な用途
PreToolUseツールの実行前検証、承認/拒否、入力の変更
PostToolUseツールの完了後テスト、Lint、ログ記録、フィードバックの提供
Stopメインエージェントの停止時タスクの完了度を確認
SubagentStopサブエージェントの停止時サブエージェントの作業を検証
UserPromptSubmitユーザーがプロンプトを送信した時コンテキストの追加、検証、前処理
SessionStartセッションの開始時コンテキストの読み込み、環境の設定
SessionEndセッションの終了時クリーンアップ、ログ記録
PreCompactコンテキストの圧縮前重要な情報の保持
Notification通知の表示時カスタム通知への応答

設定形式

プラグインの hooks.json(hooks/hooks.json 内)

hooks フィールドを使うラッパー形式です:

{
  "description": "What these hooks do (optional)",
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh",
            "timeout": 10
          }
        ]
      }
    ]
  }
}
ユーザー設定形式(.claude/settings.json 内)

ラッパーを使わない直接形式です:

{
  "PreToolUse": [
    {
      "matcher": "Write|Edit",
      "hooks": [{ "type": "command", "command": "script.sh" }]
    }
  ]
}

重要な違い: プラグインの hooks.json では、イベントを {"hooks": {...}} 内にラップします。設定形式では、イベントをトップレベルに配置します。

プロンプトベースのフック(推奨)

コンテキストを考慮した判断には、LLM の推論を使います:

{
  "type": "prompt",
  "prompt": "Evaluate if this tool use is appropriate. Check for: system paths, credentials, path traversal. Return 'approve' or 'deny'.",
  "timeout": 30
}

対応イベント: PreToolUse、PostToolUse、Stop、SubagentStop、UserPromptSubmit

利点: コンテキストを考慮でき、柔軟で、エッジケースへの対応に優れ、保守も容易です。

コマンドフック

決定論的なチェックには、シェルコマンドを実行します:

{
  "type": "command",
  "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh",
  "timeout": 60
}

移植可能なパスには、常に ${CLAUDE_PLUGIN_ROOT} を使ってください。

終了コード
コード意味
0成功(標準出力がトランスクリプトに表示されます)
2ブロッキングエラー(標準エラーが Claude にフィードバックされます)
その他非ブロッキングエラー

マッチャー

フックをトリガーするツールを制御します:

"matcher": "Write"              // Exact match
"matcher": "Write|Edit|Bash"    // Multiple tools
"matcher": "mcp__.*__delete.*"  // Regex (all MCP delete tools)
"matcher": "*"                  // All tools (use sparingly)

マッチャーでは大文字と小文字が区別されます。

フックの入出力

入力(すべてのフックが標準入力から受け取ります)
{
  "session_id": "abc123",
  "transcript_path": "/path/to/transcript.txt",
  "cwd": "/current/working/dir",
  "hook_event_name": "PreToolUse",
  "tool_name": "Write",
  "tool_input": { "file_path": "/path/to/file" }
}

イベント固有のフィールド:tool_name、tool_input、tool_result、user_prompt、reason

プロンプトでのアクセス方法:$TOOL_INPUT、$TOOL_RESULT、$USER_PROMPT

出力

標準(すべてのフック):

{
  "continue": true,
  "suppressOutput": false,
  "systemMessage": "Message for Claude"
}

PreToolUse の判断:

{
  "hookSpecificOutput": {
    "permissionDecision": "allow|deny|ask",
    "updatedInput": { "field": "modified_value" }
  }
}

Stop/SubagentStop の判断:

{
  "decision": "approve|block",
  "reason": "Explanation"
}

環境変数

変数使用可能な範囲用途
$CLAUDE_PLUGIN_ROOTすべてのフックプラグインディレクトリ(移植可能なパス)
$CLAUDE_PROJECT_DIRすべてのフックプロジェクトのルートパス
$CLAUDE_ENV_FILESessionStart のみセッション用の環境変数を永続化

SessionStart では変数を永続化できます:

echo "export PROJECT_TYPE=nodejs" >> "$CLAUDE_ENV_FILE"

一般的なパターン

ファイル書き込みの検証(PreToolUse)
{
  "PreToolUse": [{
    "matcher": "Write|Edit",
    "hooks": [{
      "type": "prompt",
      "prompt": "Check if this file write is safe. Deny writes to: .env, credentials, system paths, or files with path traversal (..). Return 'approve' or 'deny' with reason."
    }]
  }]
}
変更後の自動テスト(PostToolUse)
{
  "PostToolUse": [{
    "matcher": "Write|Edit",
    "hooks": [{
      "type": "command",
      "command": "npm test -- --bail",
      "timeout": 60
    }]
  }]
}
タスク完了の確認(Stop)
{
  "Stop": [{
    "matcher": "*",
    "hooks": [{
      "type": "prompt",
      "prompt": "Verify: tests run, build succeeded, all questions answered. Return 'approve' to stop or 'block' with reason to continue."
    }]
  }]
}
プロジェクトコンテキストの読み込み(SessionStart)
{
  "SessionStart": [{
    "matcher": "*",
    "hooks": [{
      "type": "command",
      "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/load-context.sh",
      "timeout": 10
    }]
  }]
}

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

コマンドフックのスクリプト内:
#!/bin/bash
set -euo pipefail

input=$(cat)
file_path=$(echo "$input" | jq -r '.tool_input.file_path')

# Always validate inputs
if [[ ! "$file_path" =~ ^[a-zA-Z0-9_./-]+$ ]]; then
  echo '{"decision": "deny", "reason": "Invalid path"}' >&2
  exit 2
fi

# Block path traversal
if [[ "$file_path" == *".."* ]]; then
  echo '{"decision": "deny", "reason": "Path traversal detected"}' >&2
  exit 2
fi

# Block sensitive files
if [[ "$file_path" == *".env"* ]]; then
  echo '{"decision": "deny", "reason": "Sensitive file"}' >&2
  exit 2
fi

# Always quote variables
echo "$file_path"

ライフサイクルと制限事項

フックはセッション開始時に読み込まれます。 フック設定を変更した場合は、Claude Code を再起動する必要があります。

  • hooks/hooks.json を編集しても、現在のセッションには反映されません
  • 新しいフックスクリプトを追加しても、再起動するまでは認識されません
  • 条件に一致するすべてのフックは並列で実行されます(順次ではありません)
  • フック同士は互いの出力を参照できません。独立して動作するように設計してください

変更をテストするには: Claude Code を終了し、claude または claude --debug で再起動します。

デバッグ

# Enable debug mode to see hook execution
claude --debug

# Test hook scripts directly
echo '{"tool_name": "Write", "tool_input": {"file_path": "/test"}}' | \
  bash ${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh

# Validate hook JSON output
output=$(./hook-script.sh < test-input.json)
echo "$output" | jq .

# View loaded hooks in session
# Use /hooks command

検証チェックリスト

  • hooks.json が正しい形式を使用している(プラグインラッパーまたは設定を直接指定)
  • すべてのスクリプトパスで ${CLAUDE_PLUGIN_ROOT} を使用している(ハードコードされたパスがない)
  • スクリプトに実行権限があり、エラーを処理する(set -euo pipefail)
  • スクリプトですべての入力を検証し、すべての変数を引用符で囲んでいる
  • マッチャーが具体的である(必要な場合を除き * を避ける)
  • タイムアウトが適切に設定されている(デフォルト:コマンドは60秒、プロンプトは30秒)
  • フックの出力が有効なJSONである
  • claude --debug でテスト済み

コメント