Claude Code hooks: コミットのたびにコードレビューを自動化する

Dev.to / 2026/4/8

💬 オピニオンDeveloper Stack & InfrastructureTools & Practical Usage

要点

  • Claude Code の「hooks」は、Claude がツールを実行する直前・直後、またはメッセージを送信したときなどの特定のワークフローイベントで、カスタムのシェルコマンドを実行できます。たとえば PreToolUse(Claude がツールを実行する前)、PostToolUse(完了後)、UserPromptSubmit(メッセージ送信時)です。
  • hooks は .claude/settings.json またはプロジェクトレベルの CLAUDE.md で設定でき、プロジェクトスコープでコード支援の挙動を自動化できます。
  • 記事の主要な例では、ツール入力コマンドを条件で確認することで、Claude が git commit を実行しようとしているときだけ PreToolUse hook をトリガーします。
  • 付属のスクリプトは、ステージ済みの差分(git diff --cached)を読み取り、コミットが進む前にレビュー処理を実行することで、自動レビューを行います。
  • このアプローチにより、毎回手作業で行う必要なく、コミットのワークフローにおいて軽量なコードレビューや品質チェックを標準化できます。

Claude Code のフックを使うと、ワークフローの特定のタイミングでカスタムスクリプトを実行できます。ツール実行の前、ツール実行の完了後、またはユーザーがプロンプトを送信したときです。最も価値のあるフックは、すべてのコミットの前に自動でコードレビューを行うことです。

フックとは何か

フックは、イベントに応じて発火するシェルコマンドです:

  • PreToolUse — Claude がツールを実行する前(Bash、Edit、Write など)
  • PostToolUse — ツールの実行が完了した後
  • UserPromptSubmit — メッセージを送信したとき

それらは .claude/settings.json またはプロジェクト単位の CLAUDE.md で設定します。

コミット前レビューのフック

以下は、すべての git コミットの前に素早いコードレビューを実行するフックの例です:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "node scripts/pre-commit-review.js",
        "condition": "toolInput.command.includes('git commit')"
      }
    ]
  }
}

condition フィールドにより、このフックは Claude が git commit を実行しようとしているときだけ発火し、すべての Bash コマンドで発火するわけではありません。

// scripts/pre-commit-review.js
const { execSync } = require('child_process');

// ステージされた差分を取得
const diff = execSync('git diff --cached').toString();

if (diff.length === 0) {
  console.log('ステージされた変更がありません');
  process.exit(0);
}

const checks = [];

// console.log が残っていないか確認
if (diff.includes('console.log')) {
  checks.push('警告: ステージされた変更内で console.log が見つかりました');
}

// TODO/FIXME がないか確認
const todoMatches = diff.match(/\+.*(?:TODO|FIXME|HACK|XXX)/gi);
if (todoMatches) {
  checks.push(\`警告: \${todoMatches.length} 個の TODO/FIXME コメントが見つかりました\`);
}

// .env やシークレットのチェック
if (diff.includes('.env') || diff.includes('API_KEY') || diff.includes('SECRET')) {
  checks.push('重大: ステージされた変更内に機密情報(シークレット)の可能性があります');
}

// 大きなファイルのチェック
const stagedFiles = execSync('git diff --cached --name-only').toString().split('
');
for (const file of stagedFiles) {
  if (!file) continue;
  try {
    const size = execSync(\`wc -c < "\${file}"\`).toString().trim();
    if (parseInt(size) > 1000000) {
      checks.push(\`警告: 大きなファイルがステージされています: \${file} (\${Math.round(parseInt(size)/1024)}KB)\`);
    }
  } catch {}
}

if (checks.length > 0) {
  console.log('事前コミットレビューの結果:');
  checks.forEach(c => console.log(\`  \${c}\`));
}

その他の便利なフック

書き込み時の自動フォーマット:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "npx prettier --write $TOOL_FILE_PATH",
        "condition": "toolInput.file_path?.endsWith('.ts') || toolInput.file_path?.endsWith('.tsx')"
      }
    ]
  }
}

編集後の Lint チェック:

{
  "PostToolUse": [
    {
      "matcher": "Edit",
      "command": "npx eslint $TOOL_FILE_PATH --quiet",
      "condition": "toolInput.file_path?.match(/\.(ts|tsx|js|jsx)$/)"
    }
  ]
}

起動時のセッションコンテキスト:

{
  "UserPromptSubmit": [
    {
      "matcher": "*",
      "command": "echo 'Branch: '$(git branch --show-current)' | Last commit: '$(git log --oneline -1)",
      "condition": "true"
    }
  ]
}

フックのライフサイクル

メッセージを入力する
  → UserPromptSubmit のフックが発火
    → Claude がツールを使うことを決定
      → PreToolUse のフックが発火(ツールをブロックできる)
        → ツールが実行される
          → PostToolUse のフックが発火(コンテキストを追加できる)

PreToolUse フックは、ゼロ以外の値を返してツールをブロックできます。これによって、Claude が破壊的なコマンドを実行したり、シークレットをコミットしたりするのを防げます。

実運用(Production)におけるフックのパターン

危険なコマンドをブロックする:

{
  "PreToolUse": [
    {
      "matcher": "Bash",
      "command": "echo 'BLOCKED: destructive command'",
      "condition": "toolInput.command.match(/rm -rf|drop table|force push/i)",
      "blocking": true
    }
  ]
}

実装後に自動テスト:

{
  "PostToolUse": [
    {
      "matcher": "Write",
      "command": "npm test -- --passWithNoTests 2>/dev/null",
      "condition": "toolInput.file_path?.includes('/src/')"
    }
  ]
}

ファイル変更を追跡する:

{
  "PostToolUse": [
    {
      "matcher": "Edit|Write",
      "command": "echo $(date) $TOOL_FILE_PATH >> .claude/change-log.txt"
    }
  ]
}

なぜフックが重要なのか

フックがなければ、Claude Code はリアクティブです——指示したことをそのまま実行します。フックがあると、プロアクティブになります——自動でチェックし、検証し、ガードします。コミット前レビューのフックだけでも、ステージされたファイル中のシークレット、サイズが大きすぎるバイナリ、そして本番に投入されてしまうはずだった残りのデバッグ文を見つけてくれました。

フックは、「コードを書くAI」と「責任を持ってコードを書くAI」の違いです。」

Ship Fast Skill Pack には、Claude Code のスキル 10 個に加えて、プロダクションでテスト済みのフック 5 個が含まれています。コミット前レビュー、 自動フォーマット、リントのゲート、テストランナー、そしてセッションコンテキスト——すべて設定済みで、すぐに使えます。