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'"
}
]
}
]
}
}
スクリプトの解説
このコマンドは少し複雑なので、ステップを追って解説します。
$CLAUDE_FILE_PATHSに含まれるファイルパスを改行で分割grep -EでTypeScript/JavaScriptファイル(.ts、.tsx、.js、.jsx)だけを抽出- 対象ファイルが存在する場合のみESLintを実行
- 結果を
--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'"
}
]
}
]
}
}
この設定では、ファイルパスに production や prod.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アシスタントを「提案するだけ」から「自律的に品質を保つパートナー」へと進化させる強力な機能です。ぜひ活用してみてください。


