> ## Documentation Index
> Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# イベントに mod で反応する

> mod から Claude Code イベントを処理する：観察、書き換え、またはツール呼び出し、プロンプト、ターンに答える、フック が処理するイベントをフィルタリングする、および他の mod を計画する。

hook はイベントハンドラです。Claude Code が名前付きイベントが発生したときに実行する関数です。Claude Code は、ツールを実行する、プロンプトを送信する、モデルにリクエストを送信する、またはセッションを開始または終了するなど、アクションを起こそうとしている各ポイントでイベントを発火させます。hook は Claude Code がアクションを起こす前に実行されるため、イベントを観察したり、書き換えたり、Claude Code の代わりに答えたりできます。hook は [`on(eventName, handler)`](/docs/ja/plugins/mods/reference#the-hook-function) で登録します。

ここから始める前に、[最初の mod を構築](/docs/ja/plugins/mods/create)してください。すべてのイベントとその正確なフィールドについては、[リファレンス](/docs/ja/plugins/mods/reference#events)を参照するか、[ビルド用の型を読んでください](/docs/ja/plugins/mods/create#get-the-types-for-your-build)。

<h2 id="how-a-hook-handles-an-event">
  hook がイベントを処理する方法
</h2>

hook はイベントと Claude Code がそれについて何をするかの間に位置するため、イベントを観察したり、書き換えたり、それ自体で答えたりできます。3 つの引数を受け取ります：[mods API](/docs/ja/plugins/mods/api) を `$` として、イベントを `e` として、次のハンドラを `next` として。イベントのハンドラはミドルウェアチェーンを形成します。`next(e)` は次のハンドラを呼び出します。これは別の mod の hook か、チェーンの最後では Claude Code 独自の動作であり、結果に解決されます。hook が `next` で何をするかが、3 つのうちどれをするかを決定します。

<h3 id="observe-an-event">
  イベントを観察する
</h3>

イベントを変更せずに観察するには、作業を行い、`next(e)` を返します。この hook は Claude が使用しようとしている各ツールをログに記録します：

```javascript theme={null}
on('tool.call', async ($, e, next) => {
  // ツールが実行される前に実行される
  $.ui.log('Claude is about to use ' + e.tool)
  // イベントを変更せずに渡す
  return next(e)
})
```

各ツールが実行される前に、`● my-mod: Claude is about to use Bash` のような薄い行がトランスクリプトに表示されます。ここで `my-mod` はプラグインの名前です。ツールは mod なしで実行されるのと同じように実行されます。

イベント後にアクションを実行するには、`await next(e)` を実行し、作業を行い、結果を返します。この hook は各ツールが実行された後にログに記録します：

```javascript theme={null}
on('tool.call', async ($, e, next) => {
  // ツールを実行し、その結果を待つ
  const result = await next(e)
  // ツールが実行された後に実行される
  $.ui.log(e.tool + ' finished')
  // 結果を変更せずに返す
  return result
})
```

行は各ツールが完了した後に表示されるようになります。hook が `next(e)` が解決したものを返すため、Claude は同じ結果を読みます。

<h3 id="rewrite-an-event">
  イベントを書き換える
</h3>

Claude Code が作用する内容（プロンプトのテキストなど）を変更するには、イベントの変更されたコピーで `next` を呼び出します。イベント自体は不変です：すべての深さで凍結されており、フィールドに割り当てるとスローされます。この hook は各プロンプトが送信される前にトリミングします：

```javascript theme={null}
on('prompt.submit', async ($, e, next) => {
  // イベントのコピーをテキストが変更された状態で渡す
  return next({ ...e, text: e.text.trim() })
})
```

後のハンドラと Claude Code は、トリミングされたプロンプトを受け取り、元のプロンプトを見ることはありません。結果を変更することもできます：`await next(e)` を実行してから、フィールドが置き換えられた結果のコピーを返します。

<h3 id="answer-an-event">
  イベントに答える
</h3>

イベント自体を処理するには、`next` を呼び出さずに結果を返します。これはチェーンをショートサーキットするため、後の mod と Claude Code 独自の動作は実行されません。この hook はすべての Bash コマンドを拒否します：

```javascript theme={null}
on('tool.call', { tool: 'Bash' }, async () => {
  // next への呼び出しがないため、コマンドは実行されない
  return { deny: 'Bash is turned off in this project. Use the file tools.' }
})
```

Claude が Bash コマンドを試みると、コマンドは実行されず、Claude は `deny` テキストをツールの結果として読みます。各イベントには独自の結果形状があり、[イベントリファレンス](/docs/ja/plugins/mods/reference#events)がリストアップしています。

<h3 id="filter-which-events-a-hook-handles">
  hook が処理するイベントをフィルタリングする
</h3>

hook を一部のイベントのみで実行するには、`on` の 2 番目の引数としてフィルタを渡します。Claude Code はフィルタを matcher と呼びます。これはイベントのフィールドと比較されるフィールドを持つオブジェクトであり、hook はすべてのフィールドが一致する場合にのみ実行されます。フィールドは値、許可された値の配列、または正規表現です。

この例の各行は、同じ関数 `hook` をより狭いツール呼び出しセットに登録します：

```javascript theme={null}
// 文字列は 1 つの値と一致する：Bash 呼び出しのみ
on('tool.call', { tool: 'Bash' }, hook)
// 配列は任意の値と一致する：Edit 呼び出しと Write 呼び出し
on('tool.call', { tool: ['Edit', 'Write'] }, hook)
// 正規表現はパターンで一致する：1 つの MCP サーバーのすべてのツール
on('tool.call', { tool: /^mcp__github__/ }, hook)
```

`hook` は Bash、Edit、または Write 呼び出しで 1 回実行され、名前が `mcp__github__` で始まるツールへの呼び出しで 1 回実行されます。Read などの他のツールへの呼び出しは 3 つのいずれにも一致しないため、`hook` はそれに対して実行されません。

イベント名はワイルドカードです。`'classic.*'` はすべての[設定 hook イベント](#hook-the-settings-hook-events)と一致します。`'*'` は[テレメトリイベント](/docs/ja/plugins/mods/reference#telemetry)を除くすべてのイベントと一致します。テレメトリイベントは名前で、または `'telemetry.*'` として hook します。

各イベントを matcher ごとに 1 回登録します。matcher なしで `session.start` に対して `on` を 2 回呼び出すと、モジュールは `on("session.start") is registered twice without a matcher` で読み込みに失敗します。mod がセッション開始時に行うすべてのことを 1 つの hook に入れます。

<h2 id="hook-what-claude-is-doing">
  Claude が何をしているかを hook する
</h2>

これらのイベントを hook して、ツール呼び出し、プロンプト、またはターンが発生しているのを見たり、変更したりします。すべてのイベントと hook が返すことができるものについては、[イベントリファレンス](/docs/ja/plugins/mods/reference#events)を参照してください。

<h3 id="guard-or-change-a-tool-call">
  ツール呼び出しをガードまたは変更する
</h3>

`tool.call` hook は Claude が使用しようとしている各ツールを見るため、呼び出しを拒否したり、その引数を変更したり、それを通したりできます。`tool.call` は Claude Code がツールを実行しようとしているときに発火します。これには subagent が行う呼び出しと MCP ツールへの呼び出しが含まれます。`e.tool` はツールの名前であり、ツールの引数は `e` のフィールドです。例えば Bash の場合は `e.command` です。`next(e)` を呼び出すと、Claude Code は権限チェックを実行してからツールを実行します。

この hook は force-push を行う Bash コマンドを拒否し、Claude に理由を伝えます：

```javascript theme={null}
// matcher は hook を Bash 呼び出しに制限するため、e.command はシェルコマンド
on('tool.call', { tool: 'Bash' }, async ($, e, next) => {
  if (/git push .*--force/.test(e.command)) {
    // next を呼び出さずに返すことでイベントに答えるため、コマンドは実行されない
    return { deny: 'Force pushes are not allowed in this repository. Push to a new branch instead.' }
  }
  // 他のすべてのコマンドは権限チェックを経由して Bash に進む
  return next(e)
})
```

Claude が `git push --force` を試みると、コマンドは実行されず、hook が `next` を呼び出さないため権限プロンプトは表示されません。Claude は `deny` テキストをツールの結果として読むため、Claude が作用できる指示として書いてください。他のすべての Bash コマンドは mod なしで実行されるのと同じように実行されます。

ツールが実行された後にアクションを実行するには、`await next(e)` を実行し、作業を行い、`next` が与えたものを返します。この hook は Claude が変更する各 `.mdx` ファイルをログに記録します。[`$.ui.log`](/docs/ja/plugins/mods/api#show-something-without-starting-a-turn) を使用します。これはトランスクリプトに薄い行を追加し、Claude は読みません：

```javascript theme={null}
on('tool.call', { tool: ['Edit', 'Write'] }, async ($, e, next) => {
  // 権限チェックとツールを待ち、それらが生成したものを保持する
  const result = await next(e)
  // 拒否された呼び出しは { deny } として戻り、失敗したものは isError が設定されている
  const changed = !result.deny && !result.isError
  if (changed && e.file_path.endsWith('.mdx')) $.ui.log('Claude changed ' + e.file_path)
  // ツールが返したものを Claude が読むように、結果をそのまま返す
  return result
})
```

Claude が `.mdx` ファイルを編集または書き込んだ後、トランスクリプトの薄い行がファイルに名前を付けます。別の種類のファイルの場合、または拒否または失敗した呼び出しの場合は何もログに記録されません。hook が受け取った結果を返すため、Claude の呼び出しの見方は変わりません。

呼び出しを変更するには、変更された引数を `next` に渡します。呼び出しを再試行するには、`next(e)` を再度呼び出します：最初の結果で `isError` を見る hook は、ツールを 2 番目の時間実行して、その結果を返すことができます。呼び出しに自分で答えるには、`next` を呼び出さずに `result` フィールドを持つオブジェクト（例えば `{ result: 'Skipped by my-mod' }` など）を返します。そうすると、権限プロンプトは表示されず、ツールは実行されないため、返す結果は Claude が何が起こったかについて学ぶすべてです。

組織の[管理設定](/docs/ja/server-managed-settings)の hook は、任意の mod の `tool.call` hook の前に実行され、そのうちの 1 つからのブロックは最終的です。

<h4 id="hold-a-tool-call-until-the-user-decides">
  ユーザーが決定するまでツール呼び出しを保持する
</h4>

hook はツール呼び出しを一時停止し、先に進む前にユーザーに何をするかを尋ねることができます。`tool.call` hook は `next` を呼び出す前または返す前に `await` でき、ツール呼び出しはそれまで保留されたままです。質問をユーザーに提示するには、`$.ui.ask` を呼び出します。これはあなたの質問を Claude があなたに何かを尋ねるために使用するダイアログで、番号付きのオプションリストの上に表示し、ユーザーが選んだラベルに解決されます。オプションの後、ダイアログは異なる答えを入力するための行と **Chat about this** 行を追加します。

この例の `RISKY` パターンは `rm -r`、`rm -rf`、`git reset --hard`、および `--force` を含む `git push` と一致し、`git push -f` などの他のスペルを見落とします。このモジュールは RISKY パターンと一致する Bash コマンドを実行する前に尋ねます：

```javascript theme={null}
const RISKY = /\brm\s+-rf?\b|\bgit\s+reset\s+--hard\b|\bgit\s+push\b.*--force/

export function register(on) {
  on('tool.call', { tool: 'Bash' }, async ($, e, next) => {
    // 質問なしで他のすべてのコマンドを通す
    if (!RISKY.test(e.command)) return next(e)
    // 安全な答えから始めるため、誰も答えない質問はコマンドを拒否する
    let answer = 'Refuse'
    try {
      // ツール呼び出しはここで待機し、ユーザーが 2 つのラベルのいずれかを選ぶまで
      answer = await $.ui.ask('Run this command? ' + e.command, ['Run it', 'Refuse'])
    } catch {
      // ユーザーが質問を却下したか、これは誰も尋ねる人がいない claude -p 実行
    }
    if (answer !== 'Run it') {
      // next を呼び出さずに答えるため、コマンドは実行されない
      return { deny: 'The user declined this command. Ask before trying a different approach.' }
    }
    return next(e)
  })
}
```

Claude が `rm -rf build` などのコマンドを試みると、質問がコマンドと共に表示され、コマンドは答えを待ちます：

* **ユーザーが Run it を選ぶ**：hook は `next(e)` を呼び出し、通常の権限チェックはその後も実行されます
* **ユーザーが Refuse を選ぶ**：コマンドは実行されず、Claude は `deny` テキストを読みます
* **ユーザーが答えを入力する**：`$.ui.ask` は入力されたテキストに解決されます。hook はそれを `Run it` と比較するため、他のテキストはコマンドを拒否します。
* **誰も答えない**：ユーザーが質問を却下するか **Chat about this** を選ぶと、または `claude -p` 実行では `$.ui.ask` が拒否されるため、`catch` ブロックは答えを `Refuse` のままにします

`$.ui.ask` などの mods API 呼び出しの中で待機を保持してください。その時間は hook の[10 秒の時間制限](/docs/ja/plugins/mods/reference#limits)に対してカウントされないためです。自分の promise を待つのに費やされた時間はカウントされます。Claude Code は時間切れになった hook をスキップするため、保持されたコマンドは実行されます。

<h3 id="rewrite-or-add-to-a-prompt">
  プロンプトを書き換えるまたは追加する
</h3>

`prompt.submit` hook は各プロンプトをターンが開始される前に見るため、テキストを書き換えたり、それに追加したりできます。`e.text` は入力されたものです。

| これを行うには | これを返す |
| :- | :- |
| プロンプトを書き換える。トランスクリプトのメッセージは新しいテキストを表示する。 | `next({ ...e, text: newText })` |
| Claude のみが読むテキストを追加し、プロンプトの後 | `next({ ...e, context: [...(e.context ?? []), extraText] })` |
| プロンプトが送信されるのを停止する | `{ drop: 'the reason' }` |

この hook は、プロンプトがプルリクエストに言及するたびに、Claude に現在のブランチ名を追加します：

```javascript theme={null}
on('prompt.submit', async ($, e, next) => {
  // プルリクエストに言及しないプロンプトをそのまま渡す
  if (!/\bPR\b|pull request/i.test(e.text)) return next(e)
  const git = await $.process.run(['git', 'branch', '--show-current'])
  // git リポジトリの外ではコマンドが失敗するため、追加するブランチはない
  if (git.exitCode !== 0) return next(e)
  // 前の hook が追加したコンテキストを保持し、Claude 用にもう 1 行追加する
  return next({ ...e, context: [...(e.context ?? []), 'Current branch: ' + git.stdout.trim()] })
})
```

`open a PR for this change` などのプロンプトを送信すると、メッセージはトランスクリプトで同じに見え、Claude は `Current branch: feature/auth` などの行もそれの後に読みます。プルリクエストに言及しないプロンプトは変更されずに通過し、`git` は実行されません。

[他のイベント](/docs/ja/plugins/mods/reference#prompts-and-what-claude-reads)は Claude が読むもののその他をカバーします：システムプロンプトの各セクションの `prompt.section`、最初のメッセージで送信されるコンテキストの `prompt.context`、スキルのテキストの `skill.prompt`。これらの hook からのテキストがリクエスト間で変更される場合、[プロンプトキャッシュが無効化されます](/docs/ja/prompt-caching)。

<h3 id="follow-a-turn">
  ターンをフォローする
</h3>

ターンは 1 つのプロンプトに答えて Claude が行うすべてです。`turn.start`、`turn.step`、および `turn.complete` を hook してフォローします：

| イベント | いつ発火するか | hook が何をできるか |
| :- | :- | :- |
| `turn.start` | ターンが開始される | 観察。`e.turnId` は他の 2 つのイベントでターンを識別します。 |
| `turn.step` | Claude Code がモデルに 1 つのリクエストを送信しようとしている。ツール呼び出しを持つターンは複数あります。`e.agentId` は subagent のリクエストに対して設定されます。 | 各リクエストのトークン使用量を読み、`next({ ...e, model })` で別のモデルに送信するか、モデルを呼び出さずに答える |
| `turn.complete` | ターンが終了した。ユーザーが中断したターンを含む。`e.isAborted` は `true` です。`e.answer` は Claude の最終テキスト、`e.durationMs` はそれにかかった時間、`e.usage` はターンのトークン合計です。subagent のターンは `e.agentId` が設定された状態で発火します。 | 観察するか、`{ text: 'Done in 12 seconds' }` などの `text` フィールドを持つオブジェクトを返して、答えの下に行を表示する |

`turn.step` hook を非同期ジェネレータとして書いてください。イベントがストリーミングされるためです。`yield* next(e)` はレスポンスをストリーミングされるときに転送し、完成した結果に評価されます。この hook は各リクエストの Claude API が[プロンプトキャッシュ](/docs/ja/prompt-caching)から提供した量をログに記録します：

```javascript theme={null}
// function* は hook をジェネレータにし、レスポンスを部分的に渡すことができる
on('turn.step', async function* ($, e, next) {
  // リクエストを送信し、到着時に各部分を転送し、完成した結果を保持する
  const result = yield* next(e)
  // トークン数を報告しない結果をスキップする
  if (result.usage) {
    $.ui.log('cache read ' + result.usage.cache_read_input_tokens + ' · wrote ' + result.usage.cache_creation_input_tokens)
  }
  // 結果を変更せずに返すため、ターンは通常通り続行される
  return result
})
```

Claude のレスポンスは mod なしで画面にストリーミングされます。各リクエストが完了した後、トランスクリプトの薄い行がキャッシュから読み取られたトークン数と書き込まれたトークン数を示します。ツール呼び出しを持つターンは複数のリクエストを持つため、複数の行を追加します。

`result.usage` は Claude API がリクエストに対して報告する 4 つのトークン数を保持します。さらに答えた `model`：`input_tokens`、`output_tokens`、`cache_read_input_tokens`、および `cache_creation_input_tokens`。hook は subagent のリクエストに対しても実行されるため、メインの会話のみが必要な場合は `e.agentId` をチェックしてください。

<h3 id="hook-the-settings-hook-events">
  設定 hook イベントを hook する
</h3>

設定 hook は、設定ファイルで構成するコマンド、HTTP、プロンプト、およびエージェント hook です。各[設定 hook イベント](/docs/ja/hooks#hook-events)（`Stop`、`SessionEnd`、`PostToolUse` など）は、`classic.` の後に設定 hook イベントの名前が続く `classic.Stop` などのイベントでもあります。`e` は設定 hook が stdin で受け取る JSON であり、`transcript_path` を含みます。

この hook は Claude が応答を終了したときに発火する `Stop` を使用して、セッションのトランスクリプトが保存されている場所をログに記録します：

```javascript theme={null}
on('classic.Stop', async ($, e, next) => {
  // e は設定ファイルの Stop hook が stdin から読む同じフィールドを持つ
  $.ui.log('Transcript saved at ' + e.transcript_path)
  // イベントを渡すため、設定ファイルの Stop hook はまだ実行される
  return next(e)
})
```

Claude が応答を終了するたびに、トランスクリプトの薄い行がトランスクリプトファイルのパスを示します。hook は `next(e)` を返すため、イベントを観察し、ターンの終了方法について何も変更しません。

<h2 id="run-alongside-other-mods">
  他の mod と並行して実行する
</h2>

複数の mod が同じイベントを hook でき、そのいずれかが失敗する可能性があります。mod がツール呼び出しをブロックする場合、チェーン内のその位置と hook が失敗したときに何が起こるかを確認してください。

<h3 id="the-order-mods-run-in">
  mod が実行される順序
</h3>

同じイベントの hook は 1 つのミドルウェアチェーンを形成します。各 mod の `next` は次の mod の hook を呼び出し、最後の `next` は Claude Code 独自の動作に到達します。最初の mod は最も外側です：他の前にイベントを見て、その後に結果を見て、他が実行されるかどうかを決定します。後の mod は前の mod がイベントを見るのを止めることはできません。

Claude Code は各 mod がどこから来るかによってチェーンを順序付けます：

1. 組み込みガード `sec-default@builtin`。Claude Code に組み込まれた mod。`/plugin` は `cc-plugin-sec-default` としてリストアップします。[ここで読み込まれます](/docs/ja/plugins/mods/admin#know-what-happens-by-default)。組織が [`prependPlugins`](/docs/ja/plugins/mods/admin#install-your-organizations-mods) にリストアップする mod。その後、組織に属し、`appendPlugins` にない他の mod
2. インストールする mod
3. 組織が `appendPlugins` にリストアップする mod
4. Claude Code に組み込まれた他の mod

インストールする mod の中で、mod はマニフェストの `dependencies` の下にリストアップする mod の前に実行されます。1 つのモジュール内で、hook は `register` が `on` を呼び出した順序で実行されます。

<h4 id="where-settings-hooks-run-in-the-order">
  設定 hook が順序で実行される場所
</h4>

設定ファイルで構成された `PreToolUse` hook はツール呼び出し中にも実行され、mod のチェーンの固定ポイントで実行されます：

* **管理設定からの `PreToolUse` hook**：最初の mod の `tool.call` hook の前に実行され、そのうちの 1 つからのブロックは最終的であるため、mod はその呼び出しを見ません。
* **他のすべての設定ファイルおよびプラグインの `hooks/hooks.json` からの `PreToolUse` hook**：最後の mod が `next` を呼び出した後、Claude Code 独自の動作の一部として実行されます。`tool.call` に答える mod が `next` を呼び出さずに、それらの実行を保持し、`next` を呼び出す mod はそれらの決定を返される結果で見ます。

[`tool.check`](/docs/ja/plugins/mods/reference#tools) は Claude Code がツール呼び出しの実行を許可するかどうかを決定するイベントです。これらの hook と権限ルールが決定した後に発火し、`next(e)` はそれらの決定に解決されます。`tool.check` の hook は異なる決定（例えば `{ decision: 'allow' }` など）を返すことができるため、2 番目のグループの hook がブロックした呼び出しを承認できます。[hook で権限を拡張する](/docs/ja/permissions#extend-permissions-with-hooks)は、mod を保持する決定をリストアップしています。

<h3 id="handle-a-hook-that-fails">
  失敗した hook を処理する
</h3>

失敗した hook はセッションを破壊しません。代わりに何が起こるかを決定できます。`.catch` ハンドラのない hook がスロー、タイムアウト、または間違った形の結果を返すと、次に何が起こるかは `next` を呼び出したかどうかに依存します：

* **`next` を呼び出す前に失敗した**：Claude Code はそれをスキップし、次のハンドラがその代わりに実行されます
* **`next` が解決した後に失敗した**：その結果は成立し、何も 2 番目の時間実行されません

1 行は mod、イベント、および理由に名前を付けます。例えば `my-mod: tool.call hook skipped: threw Error: boom`。それを読む場所はセッションに依存します。[mod が何もしない理由を見つけ出す](/docs/ja/plugins/mods/troubleshoot#find-out-why-a-mod-does-nothing)がリストアップしています。描画が検証されない `ui.render` hook は異なる方法で報告されます。[要素からツリーを構築する](/docs/ja/plugins/mods/interface#build-a-tree-from-elements)が説明しています。

呼び出しをブロックする hook を失敗クローズにするには、その代わりに答える `.catch` エラーハンドラを追加します。ここで、`guard` は hook 関数です：

```javascript theme={null}
// on は登録を返し、.catch はその 1 つの hook にハンドラを接続する
on('tool.call', { tool: 'Bash' }, guard).catch(async ($, e, next) => {
  // next.error.kind は 'throw' または 'timeout' であり、guard がどのように失敗したかを示す
  return { deny: 'The command guard failed, so this command was not run: ' + next.error.kind }
})
```

`guard` が機能している間、ハンドラは実行されません。`guard` が Bash 呼び出しでスロー、またはタイムアウトすると、Claude Code は同じイベントでハンドラを呼び出します。ハンドラは `{ deny }` を返すため、コマンドは実行されず、Claude はテキストを `throw` または `timeout` で終わるのを読みます。ハンドラなしでは、Claude Code は `guard` をスキップしてコマンドを実行します。ハンドラは[1 秒](/docs/ja/plugins/mods/reference#limits)で答える必要があります。

<h2 id="next-steps">
  次のステップ
</h2>

* [mods API を使用する](/docs/ja/plugins/mods/api)：コマンドとツールを追加し、モデルを呼び出し、タイマーで作業を実行する
* [インターフェースに描画する](/docs/ja/plugins/mods/interface)：hook が収集したものをペインまたはプロンプトの上に表示する
* [mod をテストする](/docs/ja/plugins/mods/test)：テストからこれらのイベントのいずれかを発火させる
* [Mods リファレンス](/docs/ja/plugins/mods/reference)：すべてのイベント、すべての mods API メソッド、および制限
