🐥

Claude Code Hook 完全ガイド

に公開

Claude Code Hook 完全ガイド

Claude Code自身が参照し、hookを作成・編集するための包括的なリファレンス

目次

  1. 概要
  2. 基本概念とアーキテクチャ
  3. Hook イベントの種類と機能
  4. 作成方法とAPIリファレンス
  5. 設定とカスタマイズ
  6. 実用例とベストプラクティス
  7. トラブルシューティング
  8. よくある質問

概要

Claude Code Hookとは

Claude Code Hookは、Claude Codeのライフサイクルの特定の時点で自動実行されるユーザー定義のシェルコマンドです。これにより、LLMの確率的な動作に依存するのではなく、決定論的な制御を提供し、開発ワークフローを自動化できます。

主な特徴

  • 決定論的制御: 特定のアクションが確実に実行されることを保証
  • ライフサイクル統合: Claude Codeの各段階でhookが実行
  • シェルコマンド実行: 任意のシェルコマンドを実行可能
  • 条件付き実行: 特定の条件でのみhookを実行
  • 並列処理: 複数のhookが同時に実行可能
  • MCP統合: Model Context Protocolツールとの連携

使用場面

  • 自動コードフォーマット: ファイル編集後のprettier、black、gofmtなどの実行
  • テスト実行: ファイル変更後の自動テスト実行
  • 通知システム: デスクトップ通知やSlack通知の送信
  • ログ記録: 実行コマンドの追跡と記録
  • 権限制御: 本番ファイルや重要なディレクトリへのアクセス制御
  • Git操作: 自動コミット、スタッシュ、ステータス確認

基本概念とアーキテクチャ

基本構造

{
  "hooks": {
    "EventName": [
      {
        "matcher": "ToolPattern",
        "hooks": [
          {
            "type": "command",
            "command": "your-command-here"
          }
        ]
      }
    ]
  }
}

Hook イベント

  1. PreToolUse: ツール呼び出し前
  2. PostToolUse: ツール完了後
  3. Notification: Claude通知送信時
  4. Stop: メインエージェント終了時
  5. SubagentStop: サブエージェント終了時

実行環境

  • 権限: フルユーザー権限で実行
  • 実行場所: 現在のディレクトリで実行
  • 環境変数: Claude Codeの環境変数を継承
  • 並列実行: 適合するすべてのhookが並列で実行
  • タイムアウト: デフォルト60秒(コマンドごとに設定可能)

セキュリティ考慮事項

⚠️ 重要: hookはフルユーザー権限で実行されるため、以下の点に注意:

  • 入力検証とサニタイズが必要
  • 絶対パスの使用が推奨
  • 機密ファイルへのアクセスを避ける
  • 適切なエラーハンドリングの実装

Hook イベントの種類と機能

1. PreToolUse Hook

目的: ツール実行前の制御

  • ツールの実行をブロックまたは変更可能
  • 権限制御や事前検証に使用
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": {
          "tool_name": "Edit",
          "file_paths": ["production/**/*"]
        },
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Production files are protected' && exit 1"
          }
        ]
      }
    ]
  }
}

2. PostToolUse Hook

目的: ツール実行後の処理

  • 自動コードフォーマット
  • テスト実行
  • Git操作
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": {
          "tool_name": "Edit",
          "file_paths": ["*.py"]
        },
        "hooks": [
          {
            "type": "command",
            "command": "black $CLAUDE_FILE_PATHS && ruff check --fix $CLAUDE_FILE_PATHS"
          }
        ]
      }
    ]
  }
}

3. Notification Hook

目的: 通知送信時の処理

  • カスタム通知の実装
  • 外部システムとの統合
{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "notify-send 'Claude Code' '$CLAUDE_NOTIFICATION'"
          }
        ]
      }
    ]
  }
}

4. Stop Hook

目的: セッション終了時の処理

  • ログ記録や状態保存
  • 後処理の実行
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Task completed at $(date)' >> ~/.claude/activity.log"
          }
        ]
      }
    ]
  }
}

5. SubagentStop Hook

目的: サブエージェント完了時の処理

  • サブタスクの完了処理
  • 階層的な処理制御

作成方法とAPIリファレンス

設定ファイルの場所

優先度(高→低):
1. .claude/settings.local.json  # ローカル設定(Git管理対象外)
2. .claude/settings.json        # プロジェクト設定
3. ~/.claude/settings.json      # ユーザー設定

基本的な作成手順

  1. 設定ファイルの作成
mkdir -p .claude
touch .claude/settings.json
  1. Hook設定の記述
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": {
          "tool_name": "Edit",
          "file_paths": ["*.py"]
        },
        "hooks": [
          {
            "type": "command",
            "command": "ruff check --fix $CLAUDE_FILE_PATHS && black $CLAUDE_FILE_PATHS"
          }
        ]
      }
    ]
  }
}
  1. Hook の有効化
claude --reload-config

環境変数

Hook実行時に利用可能な環境変数:

$CLAUDE_TOOL_NAME        # 実行されたツール名
$CLAUDE_FILE_PATHS       # 操作対象ファイルのパス
$CLAUDE_NOTIFICATION     # 通知メッセージ
$CLAUDE_WORKING_DIR      # 現在の作業ディレクトリ
$CLAUDE_EVENT_TYPE       # Hookイベントの種類

Matcherの設定

{
  "matcher": {
    "tool_name": "Edit",                    # 特定のツールにマッチ
    "file_paths": ["*.py", "src/**/*.ts"],  # ファイルパターンにマッチ
    "exclude_paths": ["**/node_modules/**"] # 除外パターン
  }
}

設定とカスタマイズ

TOML形式での設定

# .claude/settings.toml
[[hooks]]
event = "PostToolUse"

[hooks.matcher]
tool_name = "Edit"
file_paths = ["*.py"]

command = "ruff check --fix $CLAUDE_FILE_PATHS && black $CLAUDE_FILE_PATHS"
run_in_background = false

複数条件の組み合わせ

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": {
          "tool_name": "Edit",
          "file_paths": ["src/**/*.py"],
          "content_patterns": ["^import "]
        },
        "hooks": [
          {
            "type": "command",
            "command": "isort $CLAUDE_FILE_PATHS && black $CLAUDE_FILE_PATHS"
          }
        ]
      }
    ]
  }
}

環境別設定

{
  "env": {
    "ENVIRONMENT": "development"
  },
  "hooks": {
    "PostToolUse": [
      {
        "matcher": {
          "tool_name": "Edit",
          "file_paths": ["*.py"]
        },
        "hooks": [
          {
            "type": "command",
            "command": "if [ \"$ENVIRONMENT\" = \"development\" ]; then black $CLAUDE_FILE_PATHS; fi"
          }
        ]
      }
    ]
  }
}

パフォーマンス最適化

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": {
          "tool_name": "Edit",
          "file_paths": ["*.py"]
        },
        "hooks": [
          {
            "type": "command",
            "command": "black --fast $CLAUDE_FILE_PATHS",
            "timeout": 5000,
            "run_in_background": true
          }
        ]
      }
    ]
  }
}

実用例とベストプラクティス

1. 自動コードフォーマット

Python

[[hooks]]
event = "PostToolUse"
[hooks.matcher]
tool_name = "Edit"
file_paths = ["*.py"]
command = "ruff check --fix $CLAUDE_FILE_PATHS && black $CLAUDE_FILE_PATHS"

JavaScript/TypeScript

[[hooks]]
event = "PostToolUse"
[hooks.matcher]
tool_name = "Edit"
file_paths = ["*.js", "*.ts", "*.tsx"]
command = "prettier --write $CLAUDE_FILE_PATHS && eslint --fix $CLAUDE_FILE_PATHS"

Go

[[hooks]]
event = "PostToolUse"
[hooks.matcher]
tool_name = "Edit"
file_paths = ["*.go"]
command = "gofmt -w $CLAUDE_FILE_PATHS && golint $CLAUDE_FILE_PATHS"

2. テスト実行

[[hooks]]
event = "PostToolUse"
[hooks.matcher]
tool_name = "Edit"
file_paths = ["src/**/*.py", "tests/**/*.py"]
command = "pytest tests/ -v --tb=short"

3. 通知システム

デスクトップ通知(Linux)

[[hooks]]
event = "PostToolUse"
[hooks.matcher]
tool_name = "Edit"
command = "notify-send 'Claude Code' 'ファイルが編集されました: $CLAUDE_FILE_PATHS'"
run_in_background = true

Slack通知

[[hooks]]
event = "PostToolUse"
[hooks.matcher]
tool_name = "Edit"
command = '''
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"Claude Codeでファイルが編集されました: $CLAUDE_FILE_PATHS"}' \
$SLACK_WEBHOOK_URL
'''
run_in_background = true

4. Git操作の自動化

[[hooks]]
event = "PostToolUse"
[hooks.matcher]
tool_name = "Edit"
command = '''
git add $CLAUDE_FILE_PATHS
git commit -m "Claude Code auto-commit: Updated $(basename $CLAUDE_FILE_PATHS)"
'''

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

入力検証

[[hooks]]
event = "PostToolUse"
command = '''
# パストラバーサル攻撃の防止
for file in $CLAUDE_FILE_PATHS; do
    if [[ "$file" == *".."* ]]; then
        echo "不正なファイルパスが検出されました: $file"
        exit 1
    fi
done

# 許可されたファイルタイプのみ処理
case "$file" in
    *.py|*.js|*.ts|*.go)
        echo "処理中: $file"
        ;;
    *)
        echo "許可されていないファイルタイプ: $file"
        exit 1
        ;;
esac
'''

エラーハンドリング

[[hooks]]
event = "PostToolUse"
command = '''
set -e  # エラー時に終了
set -u  # 未定義変数でエラー
set -o pipefail  # パイプラインでエラー

error_handler() {
    echo "エラーが発生しました。行番号: $1"
    echo "コマンド: $2"
}

trap 'error_handler $LINENO "$BASH_COMMAND"' ERR

# メイン処理
for file in $CLAUDE_FILE_PATHS; do
    if [ -f "$file" ]; then
        process_file "$file"
    fi
done
'''

避けるべき実装パターン

# 危険:入力検証なし
command = "rm -rf $CLAUDE_FILE_PATHS"  # 危険!

# 危険:コマンドインジェクション
command = "echo $CLAUDE_FILE_PATHS | sh"  # 危険!

# 危険:同期的な重い処理
command = "sleep 60; heavy_computation.sh $CLAUDE_FILE_PATHS"
run_in_background = false  # 避けるべき

トラブルシューティング

よくある問題

1. Hookが実行されない

原因と解決方法:

# 設定ファイルの構文チェック
jq . ~/.claude/settings.json

# Claude Codeの再起動
claude --restart

# デバッグモードで実行
claude --debug

2. 権限エラー

# 実行権限の付与
chmod +x ~/.claude/hooks/my_hook.sh

# ファイル所有者の確認・変更
sudo chown -R $(whoami) ~/.claude/

3. パフォーマンスの問題

# タイムアウトの調整
[[hooks]]
event = "PostToolUse"
command = "timeout 10s black $CLAUDE_FILE_PATHS"
run_in_background = true

デバッグ方法

デバッグモードの有効化

# デバッグモードでClaude Codeを実行
claude --debug

# 環境変数を設定
export CLAUDE_DEBUG=1
claude

ログの確認

# Claude Codeのログファイル
tail -f ~/.claude/logs/claude-code.log

# Hook実行ログ
tail -f ~/.claude/hook_debug.log

エラーメッセージの解釈

  • "Template variable interpolation failed": テンプレート変数が正しく展開されない
  • "Hook command timed out": hookの実行時間が制限を超過
  • "Permission denied": ファイルまたはコマンドの実行権限がない
  • "Invalid JSON in settings file": 設定ファイルの構文エラー

よくある質問

Q: Hookの設定変更が反映されない

A: 設定ファイルの直接編集は即座に反映されません。Claude Codeを完全に再起動する必要があります。

claude --restart

Q: 複数のHookを順次実行したい

A: 単一のコマンド内で&&を使用するか、order プロパティを使用します。

{
  "hooks": [
    {
      "type": "command",
      "command": "isort $CLAUDE_FILE_PATHS && black $CLAUDE_FILE_PATHS && flake8 $CLAUDE_FILE_PATHS",
      "order": 1
    }
  ]
}

Q: Hookでエラーが発生した場合にツール操作をブロックしたい

A: PreToolUse hookでexit 1を使用します。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": {"tool_name": "Edit"},
        "hooks": [
          {
            "type": "command",
            "command": "if [[ condition ]]; then exit 1; fi"
          }
        ]
      }
    ]
  }
}

Q: 特定のファイルパターンを除外したい

A: exclude_pathsを使用します。

{
  "matcher": {
    "tool_name": "Edit",
    "file_paths": ["*.py"],
    "exclude_paths": ["**/migrations/**", "**/venv/**"]
  }
}

Q: Hook実行を高速化したい

A: 以下の方法を使用します:

  1. バックグラウンド実行: run_in_background: true
  2. 軽量なコマンド: black --fast
  3. 条件付き実行: ファイルサイズやタイプによる分岐
  4. キャッシュの活用

まとめ

Claude Code Hookは、開発ワークフローを自動化し、一貫性のある品質を保つための強力なツールです。適切に設定することで:

主な利点

  1. 自動化による効率化: 繰り返し作業の自動化
  2. 品質保証: 一貫したコード品質の維持
  3. エラー防止: 事前チェックによる問題の早期発見
  4. ワークフロー統合: CI/CDパイプラインとの連携
  5. チーム統一: 開発チーム全体での一貫した作業方法

重要な注意点

  • セキュリティ: フルユーザー権限で実行されるため、セキュリティに十分注意
  • パフォーマンス: 重い処理はバックグラウンドで実行
  • エラーハンドリング: 適切なエラーハンドリングを実装
  • テスト: 本番環境で使用する前に十分テスト
  • 実験的機能: 現在experimental状態で、仕様変更の可能性

Claude Code Hookを効果的に活用することで、より効率的で品質の高い開発環境を構築できます。プロジェクトの特性に応じて、適切なhookを設定し、継続的な改善を行うことが重要です。

Discussion