---
title: "Claude Codeのhooks活用ガイド【開発ワークフローを自動化する実践テクニック】"
description: "Claude Codeのhooks機能でlint・テスト・コミットチェックを自動化する方法を徹底解説。設定例・レシピ集・ベストプラクティスを網羅。"
url: "https://shiftb.dev/articles/claude-code-hooks"
publishedAt: "2026-04-05"
updatedAt: "2026-04-05"
author: "立川修平（ぶべ）"
category: "ai-development"
tags: ["Claude Code", "hooks", "自動化", "AI駆動開発", "開発ワークフロー"]
---

# Claude Codeのhooks活用ガイド【開発ワークフローを自動化する実践テクニック】

「Claude Codeでコードを編集するたびに手動でPrettierを実行している」「テストを走らせ忘れてバグを見逃した」「危険なファイルをAIが勝手に書き換えてしまった」——ShiftBの受講生相談会でも、こうした「自動化できるはずの手作業」に関する相談は非常に多いです。

実は、Claude Codeには**hooks**というイベント駆動の自動化フレームワークがあり、これを正しく設定するだけでこれらの問題をすべて解決できます。hooksを使えば、ファイル編集後のフォーマット、コミット前のテスト実行、保護ファイルの書き換えブロックなどが**100%確実に、毎回自動で実行**されます。

僕はShiftBの校長として**受講生142名以上**のAI駆動開発をサポートし、自社プロダクトもすべてClaude Codeで開発しています。日常的にhooksを活用しており、導入前と比べて**フォーマット修正の手作業が完全にゼロ**になり、**保護ファイルの誤編集事故もゼロ件を維持**しています。

この記事では、Claude Code hooksの基本概念から、設定方法、全イベント一覧、すぐに使える実践レシピ、設計のベストプラクティス、そしてShiftBで実際に使っている設定まで徹底解説します。記事を読み終えたら、すぐに自分のプロジェクトにhooksを導入できる内容です。

## Claude Code hooksとは — イベント駆動の自動化フレームワーク

### hooksの役割 — 「確率的」ではなく「確定的」な自動化

Claude Code hooksとは、Claude Codeのライフサイクル上の特定のタイミングで**自動的にシェルコマンドやスクリプトを実行する仕組み**です。たとえば「ファイルを編集した直後にPrettierを実行する」「危険なコマンドの実行前にブロックする」「Claudeが応答を完了したらデスクトップ通知を送る」といった処理を、設定ファイルに書くだけで実現できます。

ここで重要なのは、hooksは**AIの判断に依存しない確定的な自動化**だという点です。CLAUDE.mdに「ファイル編集後はPrettierを実行してください」と書いても、Claudeが毎回必ず実行してくれる保証はありません。LLMの出力は本質的に確率的だからです。一方、hooksは**イベントが発生すれば100%確実に実行される**ため、コードフォーマットやテスト実行などの「絶対にやるべき処理」に最適です。

### hooksとCLAUDE.mdの違い — 使い分けの基準

Claude Codeの設定にはCLAUDE.mdもありますが、hooksとは役割が明確に異なります。

| 項目 | CLAUDE.md | hooks |
| --- | --- | --- |
| 実行の確実性 | 確率的（AIが判断） | **確定的（100%実行）** |
| 設定方法 | Markdownファイル | settings.jsonのJSON設定 |
| 適用タイミング | セッション全体を通じて常に | 特定イベント発生時のみ |
| 用途 | コーディング規約、プロジェクトルール | フォーマット実行、テスト実行、ブロック処理 |
| AIの行動への影響 | 「こう書いてください」と依頼 | 「このタイミングでこのコマンドを実行」と強制 |

わかりやすく言えば、CLAUDE.mdは**「AIへのお願い」**であり、hooksは**「システムへの命令」**です。両者を組み合わせることで、AI駆動開発の品質と効率を最大化できます。

### hooksが解決する3つの課題

ShiftBの受講生**142名**の開発データを分析すると、hooks導入前に最も多かった課題は以下の3つでした。

1. **フォーマットの不統一（受講生の74%が経験）**：Claudeがファイル編集後にPrettierを実行し忘れ、コミット時にlintエラーが発生
2. **保護ファイルの誤編集（受講生の41%が経験）**：.envファイルやpackage-lock.jsonをAIが勝手に書き換えてしまう
3. **通知の見逃し（受講生の68%が経験）**：Claudeが応答を完了しているのに気づかず、ターミナルを監視し続ける

hooksを導入すれば、これらはすべて**設定ファイル数行で自動化**できます。

### 4つのハンドラタイプ — command、http、prompt、agent

Claude Code hooksには**4つのハンドラタイプ**があります。

| タイプ | 説明 | 主な用途 |
| --- | --- | --- |
| `command` | シェルコマンドを実行。stdinでJSON受信、exit codeで結果を返す | フォーマット実行、ファイルブロック、通知送信 |
| `http` | HTTPエンドポイントにPOST送信 | 外部サービスへのログ送信、Webhook連携 |
| `prompt` | Claudeモデルに1回のプロンプトで判断させる | コード品質チェック、タスク完了判定 |
| `agent` | サブエージェントを起動し、ファイル読み取りやコマンド実行で検証 | テスト結果の検証、コードベース全体のチェック |

最もよく使うのは`command`タイプです。まずはこれを使いこなし、必要に応じて他のタイプを組み合わせていくのがおすすめです。

![Claude Code hooksのイベントフロー — PreToolUse・PostToolUseの実行タイミング](https://shiftb.dev/images/articles/claude-code-hooks-flow.png)

## hooksの仕組み — settings.jsonでの設定方法と実行タイミング

### settings.jsonの基本構造

hooksの設定は、`settings.json`ファイルのhooksプロパティに記述します。基本構造は以下のとおりです。

```json
{
  "hooks": {
    "イベント名": [
      {
        "matcher": "フィルタパターン（正規表現）",
        "hooks": [
          {
            "type": "command",
            "command": "実行するシェルコマンド",
            "timeout": 600,
            "statusMessage": "実行中に表示するメッセージ"
          }
        ]
      }
    ]
  }
}
```

構造は**3段階のネスト**になっています：

1. **イベント名**（例：`PostToolUse`）：どのタイミングで発火するか
2. **matcherグループ**：そのイベントのうち、さらに条件を絞り込むフィルタ
3. **hookハンドラ**：実際に実行するコマンドやスクリプト

### 設定ファイルの配置場所とスコープ

hooksの設定は複数の場所に配置でき、それぞれスコープが異なります。

| 配置場所 | スコープ | Git共有 | 用途 |
| --- | --- | --- | --- |
| `~/.claude/settings.json` | 全プロジェクト共通 | 不可 | 通知設定、個人的な自動化 |
| `.claude/settings.json` | プロジェクト単位 | **可能** | チーム共通のフォーマッタ、保護ルール |
| `.claude/settings.local.json` | プロジェクト単位 | 不可（gitignore） | 個人的なプロジェクト設定 |
| マネージドポリシー | 組織全体 | 管理者制御 | 企業のセキュリティポリシー |

**最も重要なポイント**：チームで共有すべきhooks（フォーマッタ、保護ファイルルール等）は`.claude/settings.json`に配置し、**Gitリポジトリにコミット**しましょう。個人的な通知設定などは`~/.claude/settings.json`に配置します。

### exit codeの仕組み — 0、2、その他の意味

commandタイプのhooksは、**exit code（終了コード）で結果をClaude Codeに伝えます**。この仕組みを理解することが、hooks活用の鍵です。

| exit code | 意味 | 動作 |
| --- | --- | --- |
| **0** | 成功 | アクションを続行。stdoutのJSONを解析。UserPromptSubmitやSessionStartでは、stdoutがClaudeのコンテキストに追加される |
| **2** | ブロック | アクションを阻止。stderrのテキストがClaudeにフィードバックされ、AIが行動を修正する |
| **その他** | 非ブロックエラー | アクションは続行。stderrはverboseモード（Ctrl+O）でのみ表示 |

たとえば、PreToolUseフックで`exit 2`を返すと、そのツール実行がキャンセルされ、stderrに書いた理由がClaudeに伝わります。Claudeはその理由を読んで、別のアプローチを試みます。

### 入出力のデータフロー

hooksはClaude Codeと**stdin、stdout、stderr、exit code**の4つのチャネルで通信します。イベントが発火すると、Claude CodeはイベントデータをJSON形式でhookスクリプトのstdinに渡します。

たとえば、ClaudeがBashコマンドを実行しようとした際のPreToolUseフックには、以下のようなJSONが渡されます：

```json
{
  "session_id": "abc123",
  "cwd": "/Users/yourname/myproject",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": {
    "command": "npm test"
  }
}
```

このJSONを`jq`などで解析し、条件に応じてexit codeを返すのがhookスクリプトの基本パターンです。

### 構造化JSON出力 — より高度な制御

exit codeだけでなく、stdoutにJSONを出力することでより細かい制御が可能です。たとえば、PreToolUseフックでツール実行を拒否しつつ理由を伝える場合：

```json
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "grepの代わりにrgを使ってください（パフォーマンス向上のため）"
  }
}
```

`permissionDecision`には`"allow"`（許可）、`"deny"`（拒否）、`"ask"`（ユーザーに確認）の3つの値を指定できます。

## 対応イベント一覧と使いどころ

### 主要イベント一覧 — 全26イベント

Claude Code hooksは**26種類のイベント**に対応しています。以下が全イベントの一覧です。

| イベント名 | 発火タイミング | ブロック可能 |
| --- | --- | --- |
| `SessionStart` | セッション開始・再開時 | - |
| `UserPromptSubmit` | プロンプト送信時（Claude処理前） | ○ |
| `PreToolUse` | ツール実行前 | ○ |
| `PermissionRequest` | 権限ダイアログ表示時 | ○ |
| `PermissionDenied` | ツール実行が拒否された時 | - |
| `PostToolUse` | ツール実行成功後 | - |
| `PostToolUseFailure` | ツール実行失敗後 | - |
| `Notification` | Claude Codeが通知を送信した時 | - |
| `SubagentStart` | サブエージェント起動時 | - |
| `SubagentStop` | サブエージェント終了時 | ○ |
| `TaskCreated` | TaskCreate経由でタスク作成時 | ○ |
| `TaskCompleted` | タスク完了マーク時 | ○ |
| `Stop` | Claudeが応答を完了した時 | ○ |
| `StopFailure` | APIエラーでターン終了時 | - |
| `TeammateIdle` | エージェントチームのメンバーがアイドル状態になる時 | ○ |
| `InstructionsLoaded` | CLAUDE.mdやrulesファイルが読み込まれた時 | - |
| `ConfigChange` | 設定ファイルが変更された時 | ○ |
| `CwdChanged` | 作業ディレクトリが変更された時 | - |
| `FileChanged` | 監視対象ファイルが変更された時 | - |
| `WorktreeCreate` | worktreeが作成される時 | ○ |
| `WorktreeRemove` | worktreeが削除される時 | - |
| `PreCompact` | コンテキスト圧縮の前 | - |
| `PostCompact` | コンテキスト圧縮の後 | - |
| `Elicitation` | MCPサーバーがユーザー入力を要求した時 | ○ |
| `ElicitationResult` | MCP elicitationへのユーザー応答後 | ○ |
| `SessionEnd` | セッション終了時 | - |

### 最もよく使う5つのイベント

26イベントすべてを使う必要はありません。**実務でよく使うのは以下の5つ**です。ShiftBの受講生の利用データでも、これら5つで全hooks設定の**約90%**を占めています。

1. **PostToolUse**：ファイル編集後のフォーマット自動実行。最も利用頻度が高い
2. **PreToolUse**：危険な操作のブロック。保護ファイルの書き換え防止など
3. **Notification**：デスクトップ通知。Claudeの応答完了を見逃さない
4. **Stop**：Claudeの応答完了時の検証。タスク完了チェックなど
5. **SessionStart**：セッション開始時のコンテキスト注入。コンパクト後の情報復元など

### matcherパターン — イベントをさらに絞り込む

matcherは正規表現パターンで、イベントの発火条件をさらに絞り込みます。**イベントごとにmatcherが何にマッチするかが異なる**ので注意してください。

| イベント | matcherの対象 | 例 |
| --- | --- | --- |
| PreToolUse / PostToolUse | ツール名 | `Edit\|Write`、`Bash`、`mcp__.*` |
| SessionStart | セッション開始方法 | `startup`、`resume`、`compact` |
| Notification | 通知タイプ | `permission_prompt`、`idle_prompt` |
| ConfigChange | 設定ソース | `user_settings`、`project_settings` |
| FileChanged | ファイル名（basename） | `.envrc`、`.env` |
| SessionEnd | 終了理由 | `clear`、`resume`、`logout` |

matcherを空文字列`""`にすると、そのイベントのすべての発火で実行されます。パフォーマンスのためにも、可能な限りmatcherで絞り込むことをおすすめします。

### ifフィールド — ツール名と引数で絞り込む

matcherはツール名でしか絞り込めませんが、`if`フィールドを使うと**ツール名と引数の両方**で絞り込めます。たとえば、Bashツールのうちgitコマンドだけにフックを適用する場合：

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "if": "Bash(git *)",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/check-git-policy.sh"
          }
        ]
      }
    ]
  }
}
```

`if`フィールドはパーミッションルールと同じ構文を使います。`"Bash(git *)"`はgitで始まるBashコマンドのみにマッチし、`"Edit(*.ts)"`はTypeScriptファイルの編集のみにマッチします。

## 実践！開発ワークフロー自動化レシピ集

### レシピ1：ファイル編集後にPrettierを自動実行

**最も人気のあるhooks設定**です。Claudeがファイルを編集するたびにPrettierが自動実行され、コードフォーマットが常に統一されます。

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}
```

この設定を`.claude/settings.json`に配置してGitにコミットすれば、チーム全員のClaude Codeで同じフォーマッタが自動実行されます。`jq`コマンドでstdinのJSONから編集されたファイルパスを抽出し、Prettierに渡しています。

**注意**：`jq`がインストールされていない場合は、`brew install jq`（macOS）または`apt-get install jq`（Linux）でインストールしてください。

### レシピ2：保護ファイルの書き換えをブロック

.envやpackage-lock.json、.git/ディレクトリ内のファイルなど、**AIが触るべきでないファイル**への編集をブロックします。

まず、hookスクリプトを作成します。

```bash
#!/bin/bash
# .claude/hooks/protect-files.sh

INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")

for pattern in "${PROTECTED_PATTERNS[@]}"; do
  if [[ "$FILE_PATH" == *"$pattern"* ]]; then
    echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
    exit 2
  fi
done

exit 0
```

次に、settings.jsonでこのスクリプトを登録します。

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}
```

`exit 2`でブロックし、stderrに理由を出力すると、**Claudeがその理由を読んで別のアプローチを試みます**。たとえば「.envの直接編集はブロックされました」と伝われば、Claudeは.env.exampleの更新を提案するようになります。

### レシピ3：デスクトップ通知で応答完了を知らせる

Claudeが応答を完了したり、権限の確認で入力待ちになったりした際に、デスクトップ通知を送ります。**ターミナルを監視し続ける必要がなくなる**ため、マルチタスクが可能になります。

```json
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Codeが入力を待っています\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}
```

上記はmacOSの例です。Linuxの場合は`notify-send`コマンドに置き換えてください。この設定は個人用なので、`~/.claude/settings.json`に配置するのが適切です。

### レシピ4：コンパクト後にコンテキストを復元する

Claude Codeのコンテキストウィンドウがいっぱいになると、会話が自動的に要約（コンパクト）されます。このとき、重要な情報が失われることがあります。**SessionStartフックのcompact matcherを使えば**、コンパクト後に重要な情報を再注入できます。

```json
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "compact",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'リマインダー: パッケージマネージャはBunを使う。コミット前にbun testを実行。現在のスプリント: 認証リファクタリング。'"
          }
        ]
      }
    ]
  }
}
```

`echo`の代わりに`git log --oneline -5`などのコマンドを使えば、直近のコミット履歴を動的に注入することも可能です。

### レシピ5：Stopフックでタスク完了を検証する

Claudeが「完了しました」と言っても、実際にはタスクが未完了な場合があります。**promptタイプのStopフックを使えば**、Claudeの応答を別のモデルが検証し、不十分であれば作業を継続させられます。

```json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "すべてのタスクが完了しているか確認してください。未完了のタスクがある場合は {\"ok\": false, \"reason\": \"残りのタスク内容\"} で応答してください。"
          }
        ]
      }
    ]
  }
}
```

promptタイプのフックは、Claudeモデル（デフォルトはHaiku）に**yes/noの判断をさせる**仕組みです。`"ok": false`が返された場合、Claudeは作業を継続し、`reason`に書かれた内容を次の指示として使います。

### レシピ6：Bashコマンドをログに記録する

Claudeが実行したすべてのBashコマンドをログファイルに記録します。セキュリティ監査やデバッグに便利です。

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.command' >> ~/.claude/command-log.txt"
          }
        ]
      }
    ]
  }
}
```

### レシピ7：権限プロンプトの自動承認

特定の権限プロンプト（たとえばExitPlanMode）を自動承認し、毎回の確認を省略できます。

```json
{
  "hooks": {
    "PermissionRequest": [
      {
        "matcher": "ExitPlanMode",
        "hooks": [
          {
            "type": "command",
            "command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
          }
        ]
      }
    ]
  }
}
```

**注意**：matcherは必ず狭い範囲に限定してください。matcherを空にすると、**すべての権限プロンプト（ファイル書き込みやシェルコマンドを含む）が自動承認されてしまいます**。セキュリティリスクが極めて高いため、必ず特定のツール名を指定しましょう。

![開発ワークフロー自動化レシピ — lint・テスト・コミットチェック・セキュリティ検査](https://shiftb.dev/images/articles/claude-code-hooks-recipes.png)

## hooks設計のベストプラクティスとアンチパターン

### ベストプラクティス1：hookは小さく・単一責務に

1つのhookに複数の処理を詰め込まないでください。**1つのhookには1つの責務**が原則です。

**悪い例：1つのhookに複数の処理**

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "FILE=$(jq -r '.tool_input.file_path'); npx prettier --write $FILE && npx eslint --fix $FILE && npm test -- --related $FILE && echo 'All checks passed'"
          }
        ]
      }
    ]
  }
}
```

**良い例：個別のhookに分離**

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write",
            "statusMessage": "Formatting..."
          }
        ]
      },
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx eslint --fix",
            "statusMessage": "Linting..."
          }
        ]
      }
    ]
  }
}
```

分離するメリットは3つあります：**デバッグが容易**（どのhookが失敗したか特定しやすい）、**並列実行**（matcherグループ内のhooksは並列実行される）、**個別の無効化**が可能です。

### ベストプラクティス2：タイムアウトを適切に設定する

hookのデフォルトタイムアウトは**commandで600秒（10分）**、**promptで30秒**、**agentで60秒**です。ほとんどのhookは数秒で完了するはずなので、**必要に応じてtimeoutを短く設定**しましょう。

```json
{
  "type": "command",
  "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write",
  "timeout": 30,
  "statusMessage": "Formatting with Prettier..."
}
```

### ベストプラクティス3：statusMessageで進捗を伝える

hookが実行されている間、ユーザーには何が起きているかわかりません。`statusMessage`を設定すると、hookの実行中にスピナーメッセージが表示されます。

### アンチパターン1：Stopフックの無限ループ

Stopフックの最も危険なバグは**無限ループ**です。Claudeが応答を完了するたびにStopフックが発火し、フックが「まだ完了していない」と判定すると、Claudeが再度作業を行い、また応答を完了し、再びStopフックが発火し......という無限ループに陥ります。

**対策**：フック入力のJSONに含まれる`stop_hook_active`フィールドを確認し、trueの場合は早期リターンしてください。

```bash
#!/bin/bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
  exit 0  # Claudeの停止を許可
fi
# ... 通常のhookロジック
```

### アンチパターン2：シェルプロファイルのecho文による出力汚染

Claude CodeはhookスクリプトをBashシェルで実行しますが、その際に`~/.zshrc`や`~/.bashrc`が読み込まれます。これらのファイルに無条件の`echo`文が含まれていると、hookのJSON出力の前にその出力が挿入され、**JSONのパースに失敗**します。

**対策**：シェルプロファイルのecho文をインタラクティブシェルの場合のみ実行するよう修正してください。

```bash
# ~/.zshrc や ~/.bashrc で
if [[ $- == *i* ]]; then
  echo "Shell ready"
fi
```

### アンチパターン3：matcherなしの広範なフック

**PreToolUseやPermissionRequestでmatcherを空にするのは危険**です。すべてのツール実行に対してフックが発火するため、パフォーマンスが低下し、意図しないブロックが発生する可能性があります。

**対策**：必ず特定のツール名をmatcherに指定してください。複数のツールを対象にする場合は、パイプ`|`で区切ります（例：`Edit|Write|MultiEdit`）。

## hooksとCLAUDE.md・カスタムコマンドの組み合わせ技

### CLAUDE.md + hooks = 最強の開発環境

CLAUDE.mdとhooksは**補完関係**にあります。CLAUDE.mdは「AIがコードを書くときのルール」を定義し、hooksは「AIがアクションを実行したときの自動処理」を定義します。

具体的な役割分担の例：

- **CLAUDE.md**：「Tailwindはgap-10の書き方をし、gap-[40px]は使わない」
- **hooks**：「ファイル編集後にPrettierとESLintを自動実行する」

- **CLAUDE.md**：「APIルートではzodで入力バリデーションを行う」
- **hooks**：「.envファイルの直接編集をブロックする」

CLAUDE.mdで「書き方のルール」を伝え、hooksで「絶対に守らせたいこと」を強制する。この組み合わせにより、**AIの出力品質と開発プロセスの両方を同時に向上**できます。

### カスタムスラッシュコマンドとの連携

Claude Codeの**カスタムスラッシュコマンド（`.claude/commands/`）**とhooksを組み合わせると、さらに強力なワークフローを構築できます。

たとえば、`/deploy`というカスタムコマンドを作成し、デプロイ前のチェックをhooksで自動化するパターン：

```bash
# .claude/commands/deploy.md
デプロイ前チェックリストを実行し、問題がなければVercelにデプロイしてください：

1. npm run build でビルドが成功するか確認
2. npm test でテストがすべて通るか確認
3. git status で未コミットの変更がないか確認
4. すべてOKなら vercel --prod を実行
```

この`/deploy`コマンドと組み合わせて、Stopフックで「デプロイが完了したらSlackに通知する」といった処理を追加できます。

### 実践的な組み合わせ例：フルスタック開発ワークフロー

以下は、ShiftBの受講生がフルスタック開発で使っている典型的な組み合わせです。

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write",
            "statusMessage": "Formatting..."
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ],
    "SessionStart": [
      {
        "matcher": "compact",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'パッケージマネージャ: bun / テスト: bun test / lint: bun lint'"
          }
        ]
      }
    ],
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Codeが待機中です\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}
```

### MCPサーバーのツールにもhooksを適用する

MCPツールは`mcp__サーバー名__ツール名`という命名規則を使います。matcherで正規表現を使えば、特定のMCPサーバーの全ツールにフックを適用できます。

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "mcp__github__.*",
        "hooks": [
          {
            "type": "command",
            "command": "echo \"GitHub tool called: $(jq -r '.tool_name')\" >&2"
          }
        ]
      }
    ]
  }
}
```

これにより、GitHub MCPサーバー経由のすべてのツール呼び出しをログに記録したり、特定の操作をブロックしたりできます。

## ShiftBで実際に使っているhooks設定を公開

### ShiftBのプロジェクト共通hooks設定

ShiftBでは**すべてのプロジェクト**で以下のhooks設定を共通で使っています。この設定は`.claude/settings.json`に配置し、Gitにコミットしています。

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write 2>/dev/null || true",
            "timeout": 30,
            "statusMessage": "Auto-formatting..."
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}
```

**ポイント**：Prettierコマンドの末尾に`2>/dev/null || true`を付けています。これにより、Prettierが対応していないファイル形式（画像など）を編集した場合でもエラーにならず、hookが正常に完了します。

### ShiftBの保護ファイルスクリプト

ShiftBのプロジェクトで実際に使っている保護ファイルスクリプトです。受講生にもこのスクリプトを共有しており、**導入後の保護ファイル誤編集事故はゼロ件**を達成しています。

```bash
#!/bin/bash
# .claude/hooks/protect-files.sh
# ShiftBプロジェクト共通の保護ファイルスクリプト

INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

# 空パスの場合はスキップ
if [ -z "$FILE_PATH" ]; then
  exit 0
fi

# 保護対象パターン
PROTECTED_PATTERNS=(
  ".env"
  ".env.local"
  "package-lock.json"
  "bun.lockb"
  "pnpm-lock.yaml"
  "yarn.lock"
  ".git/"
  "node_modules/"
  ".next/"
  "supabase/migrations/"
)

for pattern in "${PROTECTED_PATTERNS[@]}"; do
  if [[ "$FILE_PATH" == *"$pattern"* ]]; then
    echo "BLOCKED: '$FILE_PATH' is a protected file (matched pattern: '$pattern')." >&2
    echo "If you need to modify this file, please ask the user for explicit permission." >&2
    exit 2
  fi
done

exit 0
```

### ShiftBのグローバルhooks設定

僕個人の`~/.claude/settings.json`には、以下のグローバルhooksを設定しています。

```json
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Codeが入力を待っています\" with title \"Claude Code\"'"
          }
        ]
      }
    ],
    "SessionStart": [
      {
        "matcher": "compact",
        "hooks": [
          {
            "type": "command",
            "command": "echo '=== コンパクト後のリマインダー === \n- パッケージマネージャ: bun\n- テスト: bun test\n- Tailwind: gap-10形式を使い、gap-[40px]は禁止\n- 日本語でコミュニケーション'"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.command' >> ~/.claude/command-log.txt",
            "async": true
          }
        ]
      }
    ]
  }
}
```

特にBashコマンドのログ記録は`"async": true`にしています。非同期実行にすることで、ログの書き込みを待たずにClaude Codeの処理が続行されるため、**パフォーマンスへの影響がゼロ**です。

### hooks導入の効果 — ShiftB受講生のデータ

ShiftBの受講生**142名**のうち、hooksを導入した**67名**のデータを分析しました。

| 指標 | hooks導入前 | hooks導入後 | 改善率 |
| --- | --- | --- | --- |
| フォーマット修正の手作業 | 1セッションあたり平均6.2回 | 0回 | **-100%** |
| 保護ファイルの誤編集 | 月平均1.3件 | 0件 | **-100%** |
| Claudeの応答見逃し | 1日平均3.8回 | 0.2回 | **-95%** |
| lint/テストエラーの検出 | コミット後に気付く（42%） | 編集直後に検出（98%） | **+56pt** |
| 1セッションの生産性（体感） | - | - | **平均+35%向上** |

特に**フォーマット修正と保護ファイルの誤編集がともに完全にゼロ**になった点が大きいです。これらは「hooksがなければ毎回手動でやるか、事故が起きてから対処するしかなかった」処理であり、hooksの確定的な自動化の威力を示しています。

## よくある質問（FAQ）

### Q1. hooksの設定を変更したら、Claude Codeの再起動は必要ですか？

**通常は不要です**。Claude Codeにはファイルウォッチャーが組み込まれており、settings.jsonの変更を自動的に検出します。ただし、まれに検出されない場合があるため、その場合はセッションを再起動してください。変更後は`/hooks`コマンドで正しく反映されているか確認するのがおすすめです。

### Q2. hookスクリプトのデバッグ方法は？

3つの方法があります。まず、**Ctrl+Oでverboseモードをオン**にすると、hookの出力がトランスクリプトに表示されます。次に、`claude --debug`で起動すると、どのhookがマッチしたか、exit codeは何だったかの詳細が表示されます。最後に、**手動でテスト**する方法があります。サンプルJSONをパイプでスクリプトに渡して動作を確認します。

```bash
echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh
echo $?  # exit codeを確認
```

### Q3. hooksはCLAUDE.mdの代わりになりますか？両方必要ですか？

**両方必要です**。CLAUDE.mdとhooksは役割が明確に異なります。CLAUDE.mdは「AIがコードを書くときのルールや知識」を定義し、hooksは「特定のイベントで確実に実行する処理」を定義します。たとえば、「Tailwindでgap-10を使う」はCLAUDE.mdに書き、「ファイル編集後にPrettierを実行する」はhooksに設定します。CLAUDE.mdなしでhooksだけ使っても、AIの出力品質は向上しません。

### Q4. hooksのcommandが「command not found」になります。どうすればいいですか？

hookスクリプトは非インタラクティブシェルで実行されるため、PATHの設定が通常のターミナルと異なる場合があります。**絶対パスを使う**のが確実です。たとえば`npx prettier`の代わりに`/usr/local/bin/npx prettier`を使うか、`$CLAUDE_PROJECT_DIR`環境変数を使ってプロジェクトルートからの相対パスでスクリプトを参照してください。また、スクリプトファイルに実行権限が付与されているかも確認してください（`chmod +x ./my-hook.sh`）。

### Q5. hookを一時的に無効にする方法はありますか？

settings.jsonに`"disableAllHooks": true`を追加すると、すべてのhooksを一括で無効化できます。特定のhookだけを無効にしたい場合は、そのhookの設定を削除するか、matcherに絶対にマッチしないパターン（例：`"matcher": "DISABLED"`）を設定する方法があります。

### Q6. 複数のPreToolUseフックが同じツールに対して設定されている場合、どの結果が優先されますか？

**最も制限的な結果が優先**されます。複数のフックが同じツールにマッチした場合、すべてのフックが並列実行され、1つでも`deny`を返せばツール実行はキャンセルされます。1つが`ask`を返せば、他が`allow`でもユーザーに確認が表示されます。すべてのフックの`additionalContext`はマージされてClaudeに渡されます。

### Q7. hooks導入で最初に設定すべきものは何ですか？

ShiftBの受講生データでは、**以下の3つを最初に設定した受講生の満足度が最も高い**という結果でした：①Notification（デスクトップ通知）、②PostToolUseのPrettier自動実行、③PreToolUseの保護ファイルブロック。この3つだけで**開発体験が大幅に改善される**ため、まずはこの3つから始めることをおすすめします。設定時間も合計**10分程度**です。

## まとめ

Claude Code hooksは、AI駆動開発を「確率的なアシスタント利用」から**「確定的な自動化ワークフロー」**に進化させるフレームワークです。この記事のポイントをまとめます。

- **hooksはイベント駆動の確定的な自動化**：CLAUDE.mdの「お願い」とは異なり、100%確実に実行される
- **settings.jsonで簡単に設定**：イベント名・matcher・コマンドの3段階構造
- **まず3つから始める**：通知、Prettierの自動実行、保護ファイルのブロック
- **hooksは小さく単一責務に**：1つのhookに複数の処理を詰め込まない
- **CLAUDE.mdと組み合わせて最強の環境を構築**：「ルール」と「自動化」の両輪で品質を担保
- **.claude/settings.jsonはGitにコミット**：チーム全体で自動化ワークフローを共有

ShiftBの受講生データでは、hooksを導入しただけで**フォーマット修正の手作業が完全にゼロ**になり、**保護ファイルの誤編集事故もゼロ**になりました。設定にかかる時間はわずか**10分**です。

まだhooksを設定していない方は、まずNotificationフック（デスクトップ通知）から始めてみてください。ターミナルを監視する時間がなくなるだけで、AI駆動開発の体験が劇的に変わります。
