Nexeed Lab

Claude CodeのHooks機能で自動コードレビューを実現する

Claude CodeのHooks機能で自動コードレビューを実現する

はじめに:コードレビューの「見落とし」に悩んでいませんか?

チーム開発をしていると、こんな場面に遭遇したことはないでしょうか。

  • プルリクエストを出したら「このファイル、フォーマットがバラバラだよ」と指摘された
  • 本番デプロイ後に「console.logが残ってた」と気づいた
  • 毎回同じような指摘コメントをレビュアーが書いている

こういった「機械的に検出できるはずの問題」に、人間の時間を使うのはもったいないですよね。本来レビュアーは、設計の妥当性やビジネスロジックの正しさに集中すべきです。

そこで今回紹介するのが、Claude CodeのHooks(フック)機能です。Hooksを使えば、「ファイルを保存したとき」「コードを編集したとき」などのタイミングに自動でスクリプトを実行できます。これをうまく活用すると、コードの自動フォーマット・静的解析・AIによる自動レビューコメント生成までを、Claude Codeのワークフローに組み込めます。

この記事では、Claude CodeのHooks機能の仕組みから始めて、実際に動く設定ファイルのサンプルを交えながら、自動コードレビューの仕組みを構築する手順を丁寧に解説します。


Claude CodeのHooks機能とは?

Claude CodeのHooks機能は、特定のイベントが発生したタイミングで、任意のシェルコマンドやスクリプトを自動実行する仕組みです。Git のフック機能(pre-commit など)に似たコンセプトですが、Claude Codeの操作フローに直接組み込まれている点が大きな違いです。

利用できる主なフックイベント

現在Claude Codeでは、以下のようなイベントに対してフックを設定できます。

イベント名 発火タイミング
PreToolUse ツール(コード編集・実行など)が実行される直前
PostToolUse ツールの実行が完了した直後
Notification Claude Codeが通知を送るとき
Stop Claude Codeのレスポンスが終了したとき

この中で、コードレビュー自動化に特に役立つのが PostToolUse です。Claude Codeがファイルを編集した直後に自動でリンターや解析スクリプトを走らせることができます。

Hooksの設定場所

Hooksの設定は、プロジェクトルートの .claude/settings.json(プロジェクト固有)または ~/.claude/settings.json(ユーザーグローバル)に記述します。

プロジェクト固有の設定を使うことで、「このリポジトリではPythonのblackを走らせる」「あのリポジトリではESLintを走らせる」といった使い分けが可能になります。


実践①:ファイル編集後に自動フォーマットをかける

まず最もシンプルなユースケースとして、Claude Codeがファイルを編集した直後に自動でコードフォーマッターを実行する設定を作ってみましょう。

ここではJavaScript/TypeScriptプロジェクトでPrettierを使う例を紹介します。

設定ファイルの作成

プロジェクトルートに .claude/settings.json を作成し、以下の内容を記述します。

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write $CLAUDE_FILE_PATHS 2>&1 | head -20"
          }
        ]
      }
    ]
  }
}

設定の解説

  • matcher: どのツール実行後に動かすかを指定します。Write(新規ファイル書き込み)、Edit(既存ファイル編集)、MultiEdit(複数箇所の一括編集)を対象にしています。パイプ(|)で複数指定できます。
  • $CLAUDE_FILE_PATHS: Claude Codeが自動的にセットする環境変数で、直前に操作されたファイルのパスが入ります。
  • 2>&1 | head -20: エラー出力も標準出力にまとめて、最大20行に制限しています。大量の出力がClaude Codeのコンテキストを圧迫しないようにするための配慮です。

これだけで、Claude Codeがファイルを書き換えるたびにPrettierが自動実行されます。コードスタイルの不統一が根本から解消できます。

Pythonプロジェクト向けの設定例

Pythonプロジェクトの場合は、BlackとisortをPostToolUseで実行するとよいでしょう。

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "black $CLAUDE_FILE_PATHS 2>&1"
          },
          {
            "type": "command",
            "command": "isort $CLAUDE_FILE_PATHS 2>&1"
          }
        ]
      }
    ]
  }
}

このように hooks 配列に複数のコマンドを並べると、順番に実行されます。blackでフォーマット→isortでimport整理、という流れを自動化できます。


実践②:ESLintによる静的解析結果をClaude Codeに返す

次に、もう少し高度なユースケースを見ていきましょう。ESLintの静的解析結果をClaude Codeのフィードバックとして返す設定です。

これにより、Claude CodeがTypeScriptファイルを編集した後、自動でESLintが実行され、エラーや警告があればClaude Codeがそれを認識して追加修正を行えるようになります。

設定ファイル

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'files=$(echo $CLAUDE_FILE_PATHS | tr \" \" \"\\n\" | grep -E \"\\.(ts|tsx|js|jsx)$\" | tr \"\\n\" \" \"); if [ -n \"$files\" ]; then npx eslint $files --format compact 2>&1 | head -30; fi'"
          }
        ]
      }
    ]
  }
}

スクリプトの解説

このコマンドは少し複雑なので、ステップを追って解説します。

  1. $CLAUDE_FILE_PATHS に含まれるファイルパスを改行で分割
  2. grep -E でTypeScript/JavaScriptファイル(.ts.tsx.js.jsx)だけを抽出
  3. 対象ファイルが存在する場合のみESLintを実行
  4. 結果を --format compact でコンパクトな形式で出力し、最大30行に制限

.ts.tsx 以外のファイル(CSSやMarkdownなど)にはESLintを実行しない制御が重要です。不要なエラーがClaude Codeのコンテキストに流れ込むのを防げます。

フックの出力がClaude Codeに渡される仕組み

Hooksコマンドの標準出力は、Claude Codeのコンテキストに自動的にフィードバックとして渡されます。つまり、ESLintが「no-unused-vars エラーが3行目にある」と出力すれば、Claude Codeはその情報を受け取って「あ、変数が使われていないから修正しよう」と判断できるわけです。

この連携によって、人間が指摘しなくても自動でコードが修正されるループが生まれます。


実践③:カスタムシェルスクリプトでAIレビューコメントを生成する

最も高度な活用として、Hooksからシェルスクリプトを呼び出し、差分に対するレビューコメントを生成してファイルに書き出す仕組みを紹介します。

これはCI/CDのゲートとしても機能させられます。

プロジェクト構成

my-project/
├── .claude/
│   ├── settings.json
│   └── scripts/
│       └── review-check.sh
├── src/
│   └── ...
└── package.json

.claude/scripts/review-check.sh の内容

#!/bin/bash
# Claude Code PostToolUse フックから呼び出されるレビュースクリプト

FILE_PATHS="$CLAUDE_FILE_PATHS"
REVIEW_LOG=".claude/review-log.md"

# タイムスタンプ付きでログファイルに書き込む関数
log_review() {
  local file="$1"
  local issues="$2"
  echo "## $(date '+%Y-%m-%d %H:%M:%S') - ${file}" >> "$REVIEW_LOG"
  echo "${issues}" >> "$REVIEW_LOG"
  echo "---" >> "$REVIEW_LOG"
}

# 対象ファイルをループ
for file in $FILE_PATHS; do
  # ファイルが存在しない場合はスキップ
  [ -f "$file" ] || continue

  issues=""

  # 1. console.log が残っていないかチェック
  if grep -n "console\.log" "$file" > /dev/null 2>&1; then
    lines=$(grep -n "console\.log" "$file" | awk -F: '{print $1}' | tr '\n' ',')
    issues+="⚠️ console.log が残っています(行: ${lines%,})\n"
  fi

  # 2. TODO コメントが増えていないかチェック
  todo_count=$(grep -c "TODO\|FIXME\|HACK" "$file" 2>/dev/null || echo 0)
  if [ "$todo_count" -gt 0 ]; then
    issues+="📝 TODO/FIXME/HACK コメントが ${todo_count} 件あります\n"
  fi

  # 3. 関数が長すぎないかチェック(50行超の関数を警告)
  long_funcs=$(awk '
    /function |=>/ { start=NR }
    start && NR-start > 50 { print NR; start=0 }
  ' "$file" 2>/dev/null)
  if [ -n "$long_funcs" ]; then
    issues+="🔍 50行を超える関数が検出されました。分割を検討してください\n"
  fi

  # 問題があればログに記録し、標準出力にも出す
  if [ -n "$issues" ]; then
    echo "=== ${file} のレビュー結果 ==="
    echo -e "$issues"
    log_review "$file" "$issues"
  fi
done

.claude/settings.json への組み込み

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/scripts/review-check.sh"
          }
        ]
      }
    ]
  }
}

スクリプトを実行可能にするため、初回に以下のコマンドを実行しておく必要があります。

chmod +x .claude/scripts/review-check.sh

このアプローチのメリット

  • カスタマイズ性: シェルスクリプトなので、プロジェクト固有のルール(特定の関数名の禁止など)を自由に追加できます
  • ログ蓄積: .claude/review-log.md にレビュー結果が蓄積されるため、後から「どんな問題が多かったか」を振り返れます
  • CIとの連携: 同じスクリプトをCI/CD(GitHub Actionsなど)でも実行すれば、ローカルとCIで同じ基準のチェックが走ります

実践④:PreToolUseで危険な操作を事前にブロックする

HooksはPostToolUseだけでなく、**PreToolUse(ツール実行前)**にも使えます。これを使うと、特定の操作をClaude Codeが実行しようとした瞬間にブロックできます。

本番環境ファイルへの誤編集を防ぐ

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'for f in $CLAUDE_FILE_PATHS; do if echo \"$f\" | grep -qE \"production|prod\\.env|\\.env\\.prod\"; then echo \"ERROR: 本番環境ファイル ($f) への編集はブロックされています\"; exit 1; fi; done'"
          }
        ]
      }
    ]
  }
}

この設定では、ファイルパスに productionprod.env などが含まれる場合、編集を試みる前にエラーを返してブロックします。Claude Codeはフックのコマンドが非ゼロの終了コードを返した場合、その操作を中止する仕様になっています。

誤って本番DBの接続情報ファイルを書き換えてしまうリスクをゼロにできます。


実践⑤:Stopフックで作業完了をSlackに通知する

最後に少し変わったユースケースとして、Claude Codeが一連のタスクを完了したタイミングでSlackに通知する設定を紹介します。

長いコード生成タスクを依頼して、「終わったら教えて」という用途に使えます。

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "curl -s -X POST $SLACK_WEBHOOK_URL -H 'Content-type: application/json' -d '{\"text\": \"✅ Claude Code がタスクを完了しました\"}' > /dev/null 2>&1 || true"
          }
        ]
      }
    ]
  }
}

$SLACK_WEBHOOK_URL は環境変数として設定しておきます(.env ファイルや ~/.bashrc などで管理)。

|| true をつけることで、Slack通知が失敗してもClaude Codeのワークフロー全体には影響しないようにしています。


Hooks設定のベストプラクティス

Hooks機能を運用する上で、押さえておきたいポイントをまとめます。

1. コマンドの実行時間に注意する

Hooksのコマンドが重い処理を行うと、Claude Codeの応答がその分遅くなります。たとえば型チェック(tsc --noEmit)はプロジェクトが大きいと数十秒かかることがあります。フォーマッターやLinterなど、高速に完了するものを優先しましょう。

2. 出力行数を制限する

head -N で出力を制限しておくことをおすすめします。大量の出力がClaude Codeのコンテキストウィンドウを消費し、メインの作業に使えるトークン数が減ってしまいます。

3. エラー時の終了コードを意識する

PreToolUseでは終了コード1がブロック、PostToolUseでは終了コードの扱いが異なります。PostToolUseでコマンドが失敗しても、Claude Codeの処理は止まりません。ブロックしたい場合はPreToolUseを使いましょう。

4. プロジェクトごとに設定を分ける

ユーザーグローバル(~/.claude/settings.json)よりも、プロジェクト固有(.claude/settings.json)の設定を優先して使いましょう。チームメンバーとリポジトリを共有すれば、全員が同じフックを自動的に使えるようになります。

5. .gitignoreの管理

.claude/review-log.md のようなログファイルはGitの管理対象から外すことをおすすめします。

# .gitignoreに追加
.claude/review-log.md

一方、.claude/settings.json.claude/scripts/ はチームで共有するためにGit管理下に置くとよいでしょう。


まとめ:Hooksで「気づく」から「自動修正」へ

Claude CodeのHooks機能を使えば、これまで人間の目と手が必要だった「機械的なコードチェック」をClaude Codeのワークフローに完全に組み込めます。

今回紹介した内容を振り返ると:

  • PostToolUse × Prettierやblack → コード編集のたびに自動フォーマット
  • PostToolUse × ESLint → 静的解析結果をClaude Codeにフィードバックして自動修正
  • カスタムシェルスクリプト → プロジェクト固有のレビュールールを柔軟に定義
  • PreToolUse → 危険な操作を事前にブロック
  • Stop × Slack通知 → タスク完了を自動で知らせる

まず取り組みやすいのは、PostToolUse × フォーマッターの組み合わせです。設定ファイルは5行程度で済み、導入の手間がほとんどありません。ぜひ今日のうちに .claude/settings.json を作ってみてください。

次のステップとしては、Hooksで検出した問題をGitHub Actionsにも連携させ、CIのゲートとして機能させると、ローカルとCI両方で品質を自動保証できる仕組みが完成します。Claude CodeのHooks機能は、AIアシスタントを「提案するだけ」から「自律的に品質を保つパートナー」へと進化させる強力な機能です。ぜひ活用してみてください。

この記事をシェア

XFacebookはてブ