# Hooks システム

Hooks を使うと、Claude Code のライフサイクルの要所に独自のロジックを差し込めます — コードの自動整形、危険なコマンドの遮断、通知の送信、監査ログの記録など。Hooks は Claude Code で最も強力な拡張機構のひとつです。

---

## 一、コアコンセプト

Hook は 3 つの要素で構成されます：

```
イベント（When）  →  マッチャー（Which）  →  ハンドラー（What）
PreToolUse           matcher: "Bash"         command: "check_safety.sh"
```

- **イベント**：発火のタイミング（例：`PreToolUse` — ツール実行前）
- **マッチャー**：任意のツール名フィルター（`Bash` だけ、`Write` だけ など）
- **ハンドラー**：シェルコマンド、プロンプト注入、またはサブエージェント

---

## 二、イベント完全リスト

### コアイベント

| イベント | 発火タイミング | 遮断可否 | 代表的な用途 |
|------|---------|--------|---------|
| **PreToolUse** | ツール実行前 | 可（exit 2） | セキュリティ遮断、引数の検証 |
| **PostToolUse** | ツール実行後 | 不可 | 自動整形、ログ記録 |
| **Notification** | Claude が通知を送るとき | 不可 | Slack / Feishu / DingTalk への通知 |
| **Stop** | Claude が応答を終えたとき | 不可 | 品質チェック、自動コミット |
| **UserPromptSubmit** | ユーザーがプロンプトを送信したとき | 可 | コンテキスト注入、ポリシーチェック |
| **SessionStart** | セッション開始時 | 不可 | 環境の初期化、ウェルカムメッセージ |

### 拡張イベント（2026 年に追加）

| イベント | 発火タイミング | 遮断可否 | 代表的な用途 |
|------|---------|--------|---------|
| **SubagentStop** | サブエージェント完了時 | 不可 | サブエージェントの結果を収集 |
| **SubagentToolUse** | サブエージェントがツールを使うとき | 可 | サブエージェントの権限を制限 |
| **FileChanged** | ファイルが変更されたとき | 不可 | 自動 lint、ビルドのトリガー |
| **CwdChanged** | 作業ディレクトリが変わったとき | 不可 | ディレクトリ固有の設定を読み込む |
| **ModelChange** | モデルを切り替えたとき | 不可 | モデル利用状況の記録 |
| **CompactComplete** | /compact 完了時 | 不可 | コンテキスト圧縮後の処理 |
| **ToolError** | ツールがエラーになったとき | 不可 | エラー収集、リトライ処理 |

---

## 三、ハンドラーの種類

### 種類 1：Command（シェルコマンド）

最もよく使う種類で、シェルコマンドを実行します：

```json
{
  "type": "command",
  "command": "npx prettier --write $FILEPATH"
}
```

**環境変数**：
| 変数 | 説明 | 利用できるイベント |
|------|------|---------|
| `$FILEPATH` | 対象ファイルのパス | PreToolUse/PostToolUse |
| `$TOOL_INPUT` | ツール入力の JSON | PreToolUse |
| `$TOOL_NAME` | ツール名 | PreToolUse/PostToolUse |
| `$SESSION_ID` | セッション ID | すべて |
| `$NOTIFICATION_MESSAGE` | 通知の本文 | Notification |

**stdin 入力**：Hook スクリプトには **stdin** からも JSON が渡され、`session_id`・`tool_name`・`tool_input` が含まれます。構造化データが必要なときは環境変数を解析するよりこちらのほうが確実です。

**終了コード**：
- `0`：続行を許可
- `2`：操作を遮断（PreToolUse/UserPromptSubmit のみ）
- それ以外：エラー扱いだが遮断はしない

### 種類 2：Prompt（プロンプト注入）

テキストを Claude のコンテキストに注入します：

```json
{
  "type": "prompt",
  "prompt": "重要：データベース操作は必ずトランザクションを使うこと"
}
```

向いている場面：SessionStart でプロジェクト固有のルールを追加で注入する。

### 種類 3：Subagent（サブエージェント）

イベントを処理するサブエージェントを生成します：

```json
{
  "type": "subagent",
  "prompt": "たった今変更されたコードをレビューし、セキュリティ上の脆弱性がないか確認して"
}
```

向いている場面：PostToolUse の後に自動でコード品質をレビューする。

---

## 四、設定方法

`.claude/settings.json`（プロジェクト単位）または `~/.claude/settings.json`（ユーザー単位）で設定します：

```json
{
  "hooks": {
    "イベント名": [
      {
        "matcher": "ツール名（任意。| で複数指定可）",
        "hooks": [
          {
            "type": "command|prompt|subagent",
            "command": "..."
          }
        ]
      }
    ]
  }
}
```

---

## 五、実践レシピ

### レシピ 1：ファイル保存後に自動整形する

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write $FILEPATH 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}
```

### レシピ 2：危険なシェルコマンドを遮断する

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo $TOOL_INPUT | grep -qE 'rm -rf /|sudo rm|git push --force|DROP TABLE|DROP DATABASE' && echo '危険なコマンドを遮断しました' && exit 2 || exit 0"
          }
        ]
      }
    ]
  }
}
```

### レシピ 3：機密ファイルを保護する

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Read|Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "echo $TOOL_INPUT | grep -qE '\\.env|\\.env\\.|credentials|secrets?\\.ya?ml|private.key' && echo '機密ファイルへのアクセスを遮断しました' && exit 2 || exit 0"
          }
        ]
      }
    ]
  }
}
```

### レシピ 4：タスク完了時にシステム通知を出す

**macOS：**
```json
{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"$NOTIFICATION_MESSAGE\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}
```

**Linux：**
```json
{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "notify-send 'Claude Code' \"$NOTIFICATION_MESSAGE\""
          }
        ]
      }
    ]
  }
}
```

### レシピ 5：Slack へ通知する

```json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "curl -s -X POST https://hooks.slack.com/services/xxx/yyy/zzz -H 'Content-Type: application/json' -d '{\"text\": \"Claude Code のタスクが完了しました\"}'"
          }
        ]
      }
    ]
  }
}
```

### レシピ 6：ESLint の自動修正

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx eslint --fix $FILEPATH 2>/dev/null; npx prettier --write $FILEPATH 2>/dev/null; exit 0"
          }
        ]
      }
    ]
  }
}
```

### レシピ 7：監査ログ

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo \"$(date -u +%Y-%m-%dT%H:%M:%SZ) | session=$SESSION_ID | tool=$TOOL_NAME | file=$FILEPATH\" >> ~/.claude/audit.log"
          }
        ]
      }
    ]
  }
}
```

### レシピ 8：テストを自動実行する

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "echo $FILEPATH | grep -qE '\\.(ts|tsx|js|jsx)$' && echo $FILEPATH | grep -qvE '\\.test\\.|\\.spec\\.' && npx vitest related $FILEPATH --run 2>/dev/null || exit 0"
          }
        ]
      }
    ]
  }
}
```

### レシピ 9：マイグレーションファイルを保護する

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "echo $FILEPATH | grep -qE 'migrations/|alembic/versions/' && echo '既存のマイグレーションは変更禁止です。新しいマイグレーションを作成してください' && exit 2 || exit 0"
          }
        ]
      }
    ]
  }
}
```

### レシピ 10：セッション開始時にコンテキストを注入する

```json
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "重要なお知らせ：本プロジェクトは v3.0 の大規模リファクタリング中です。新しいコードは必ず React Server Components を使い、pages/ ディレクトリはもう使いません。"
          }
        ]
      }
    ]
  }
}
```

---

## 六、エンタープライズ向け Hooks

### managed-settings.d/ の設定

企業の管理者は `managed-settings.d/` ディレクトリを使って、組織全体にセキュリティポリシーを強制できます：

```bash
# 企業管理ディレクトリにポリシーファイルを作成する
mkdir -p /etc/claude-code/managed-settings.d/
```

```json
// /etc/claude-code/managed-settings.d/security.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/opt/claude-policy/check_command.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/opt/claude-policy/audit_log.sh"
          }
        ]
      }
    ]
  }
}
```

企業ポリシーは **ユーザー単位やプロジェクト単位の設定では上書きできません**。

---

## 七、デバッグとトラブルシューティング

### Verbose モード

`Ctrl+O` で verbose モードをオンにすると、次が見えます：
- Hook が発火したタイミング
- Hook スクリプトの stdout / stderr
- Hook の終了コード

### よくある問題

| 問題 | 原因 | 対処 |
|------|------|---------|
| Hook が発火しない | matcher のつづり間違い | ツール名の大文字小文字を確認：`Bash`、`Write`、`Edit`、`Read` |
| Hook が正常な操作まで遮断する | 終了コードのロジック誤り | 正常時は `exit 0`、遮断したいときだけ `exit 2` にする |
| Hook が遅い | スクリプトに時間がかかりすぎ | Hook は 1〜2 秒で終わるように。長い処理はバックグラウンドで |
| 環境変数が空 | そのイベントでは提供されない | 上の環境変数表で、そのイベントで使えるか確認する |

### Hook スクリプトをテストする

設定に入れる前に、ターミナルで手動テストします：

```bash
# PreToolUse の環境変数を模擬する
FILEPATH="src/main.ts" TOOL_INPUT="rm -rf /" bash -c 'echo $TOOL_INPUT | grep -qE "rm -rf" && echo "blocked" && exit 2 || exit 0'
```

---

## 八、Codex Hooks との比較

| 項目 | Claude Code Hooks | Codex Hooks |
|------|------------------|-------------|
| イベント数 | 17 種類 | 少なめ |
| 設定方法 | settings.json | config.toml |
| ハンドラーの種類 | command/prompt/subagent | command |
| 企業管理 | managed-settings.d/ | なし |
| 遮断機能 | 終了コード 2 | 限定的 |

---

## 次のステップ

- [Skills](/docs/advanced/skills) — さらに高度な拡張手段
- [MCP サーバー](/docs/advanced/mcp) — 外部ツールに接続する
- [自動化と CI/CD](/docs/advanced/headless) — ヘッドレスモードの使い方
- [CLI の便利な使い方](/docs/usage/cli-tips) — コマンドラインのテクニック