68 68
69イベント、matcher、ハンドラーがどのように組み合わさるかを理解するために、破壊的なシェル コマンドをブロックする次の `PreToolUse` フックを考えてみましょう。69イベント、matcher、ハンドラーがどのように組み合わさるかを理解するために、破壊的なシェル コマンドをブロックする次の `PreToolUse` フックを考えてみましょう。
70 70
71**macOS/Linux**71> [tab] macOS/Linux
72 72>
73`matcher` は Bash ツール呼び出しに絞り込み、`if` 条件は `rm *` にマッチする Bash サブコマンドにさらに絞り込むため、`block-rm.sh` は両方のフィルターがマッチするときのみ生成されます。73> `matcher` は Bash ツール呼び出しに絞り込み、`if` 条件は `rm *` にマッチする Bash サブコマンドにさらに絞り込むため、`block-rm.sh` は両方のフィルターがマッチするときのみ生成されます。
74 74>
75```json theme={null}75> ```json theme={null}
76{76> {
77 "hooks": {77> "hooks": {
78 "PreToolUse": [78> "PreToolUse": [
79 {79> {
80 "matcher": "Bash",80> "matcher": "Bash",
81 "hooks": [81> "hooks": [
82 {82> {
83 "type": "command",83> "type": "command",
84 "if": "Bash(rm *)",84> "if": "Bash(rm *)",
85 "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.sh",85> "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.sh",
86 "args": []86> "args": []
87 }87> }
88 ]88> ]
89 }89> }
90 ]90> ]
91 }91> }
92}92> }
93```93> ```
94 94>
95スクリプトは stdin から JSON 入力を読み取り、コマンドを抽出し、`rm -rf` が含まれている場合は `permissionDecision` として `"deny"` を返します。Claude Code が実行できるように、プロジェクト内の `.claude/hooks/block-rm.sh` に保存し、`chmod +x .claude/hooks/block-rm.sh` で実行可能にしてください。95> スクリプトは stdin から JSON 入力を読み取り、コマンドを抽出し、`rm -rf` が含まれている場合は `permissionDecision` として `"deny"` を返します。Claude Code が実行できるように、プロジェクト内の `.claude/hooks/block-rm.sh` に保存し、`chmod +x .claude/hooks/block-rm.sh` で実行可能にしてください。
96 96>
97```bash theme={null}97> ```bash theme={null}
98#!/bin/bash98> #!/bin/bash
99# .claude/hooks/block-rm.sh99> # .claude/hooks/block-rm.sh
100COMMAND=$(jq -r '.tool_input.command')100> COMMAND=$(jq -r '.tool_input.command')
101 101>
102if echo "$COMMAND" | grep -q 'rm -rf'; then102> if echo "$COMMAND" | grep -q 'rm -rf'; then
103 jq -n '{103> jq -n '{
104 hookSpecificOutput: {104> hookSpecificOutput: {
105 hookEventName: "PreToolUse",105> hookEventName: "PreToolUse",
106 permissionDecision: "deny",106> permissionDecision: "deny",
107 permissionDecisionReason: "Destructive command blocked by hook"107> permissionDecisionReason: "Destructive command blocked by hook"
108 }108> }
109 }'109> }'
110else110> else
111 exit 0 # no decision; normal permission flow applies111> exit 0 # no decision; normal permission flow applies
112fi112> fi
113```113> ```
114 114>
115このスクリプトは、JSON 入力を解析するこのページの他の Bash の例と同様に `jq` を使用します。試す前に `jq` をインストールし、`PATH` 上にあることを確認してください。115> このスクリプトは、JSON 入力を解析するこのページの他の Bash の例と同様に `jq` を使用します。試す前に `jq` をインストールし、`PATH` 上にあることを確認してください。
116
117**Windows (PowerShell)**
118
119matcher `Bash|PowerShell` は、Bash に加えて [PowerShell ツール](#powershell)も対象にします。1 つの `if` ルールは 1 つのツールの呼び出しにしかマッチしないため、ツールごとに個別のハンドラーを用意します。1 つ目は `rm *` にマッチする Bash サブコマンドに、2 つ目は `Remove-Item *` にマッチする PowerShell コマンドに絞り込みます。どちらも `powershell.exe` を通じて同じスクリプトを実行します。
120
121```json theme={null}
122{
123 "hooks": {
124 "PreToolUse": [
125 {
126 "matcher": "Bash|PowerShell",
127 "hooks": [
128 {
129 "type": "command",
130 "if": "Bash(rm *)",
131 "command": "powershell.exe",
132 "args": [
133 "-NoProfile",
134 "-ExecutionPolicy",
135 "Bypass",
136 "-File",
137 "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.ps1"
138 ]
139 },
140 {
141 "type": "command",
142 "if": "PowerShell(Remove-Item *)",
143 "command": "powershell.exe",
144 "args": [
145 "-NoProfile",
146 "-ExecutionPolicy",
147 "Bypass",
148 "-File",
149 "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.ps1"
150 ]
151 }
152 ]
153 }
154 ]
155 }
156}
157```
158
159`-NoProfile` フラグは PowerShell プロファイルの読み込みをスキップしてフックをすばやく起動させ、`-ExecutionPolicy Bypass` は PowerShell がローカルのスクリプト ファイルを実行できるようにします。
160
161スクリプトは stdin から JSON 入力を読み取り、コマンドを抽出し、`rm -rf` または `-Recurse` が後に続く `Remove-Item` が含まれている場合は `permissionDecision` として `"deny"` を返します。プロジェクト内の `.claude/hooks/block-rm.ps1` に保存してください。
162
163```powershell theme={null}
164# .claude/hooks/block-rm.ps1
165$callInput = [Console]::In.ReadToEnd() | ConvertFrom-Json
166$command = $callInput.tool_input.command
167 116
168if ($command -match 'rm -rf|Remove-Item.*-Recurse') {117> [tab] Windows (PowerShell)
169 @{118>
170 hookSpecificOutput = @{119> matcher `Bash|PowerShell` は、Bash に加えて [PowerShell ツール](#powershell)も対象にします。1 つの `if` ルールは 1 つのツールの呼び出しにしかマッチしないため、ツールごとに個別のハンドラーを用意します。1 つ目は `rm *` にマッチする Bash サブコマンドに、2 つ目は `Remove-Item *` にマッチする PowerShell コマンドに絞り込みます。どちらも `powershell.exe` を通じて同じスクリプトを実行します。
171 hookEventName = "PreToolUse"120>
172 permissionDecision = "deny"121> ```json theme={null}
173 permissionDecisionReason = "Destructive command blocked by hook"122> {
174 }123> "hooks": {
175 } | ConvertTo-Json124> "PreToolUse": [
176} else {125> {
177 exit 0 # no decision; normal permission flow applies126> "matcher": "Bash|PowerShell",
178}127> "hooks": [
179```128> {
129> "type": "command",
130> "if": "Bash(rm *)",
131> "command": "powershell.exe",
132> "args": [
133> "-NoProfile",
134> "-ExecutionPolicy",
135> "Bypass",
136> "-File",
137> "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.ps1"
138> ]
139> },
140> {
141> "type": "command",
142> "if": "PowerShell(Remove-Item *)",
143> "command": "powershell.exe",
144> "args": [
145> "-NoProfile",
146> "-ExecutionPolicy",
147> "Bypass",
148> "-File",
149> "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.ps1"
150> ]
151> }
152> ]
153> }
154> ]
155> }
156> }
157> ```
158>
159> `-NoProfile` フラグは PowerShell プロファイルの読み込みをスキップしてフックをすばやく起動させ、`-ExecutionPolicy Bypass` は PowerShell がローカルのスクリプト ファイルを実行できるようにします。
160>
161> スクリプトは stdin から JSON 入力を読み取り、コマンドを抽出し、`rm -rf` または `-Recurse` が後に続く `Remove-Item` が含まれている場合は `permissionDecision` として `"deny"` を返します。プロジェクト内の `.claude/hooks/block-rm.ps1` に保存してください。
162>
163> ```powershell theme={null}
164> # .claude/hooks/block-rm.ps1
165> $callInput = [Console]::In.ReadToEnd() | ConvertFrom-Json
166> $command = $callInput.tool_input.command
167>
168> if ($command -match 'rm -rf|Remove-Item.*-Recurse') {
169> @{
170> hookSpecificOutput = @{
171> hookEventName = "PreToolUse"
172> permissionDecision = "deny"
173> permissionDecisionReason = "Destructive command blocked by hook"
174> }
175> } | ConvertTo-Json
176> } else {
177> exit 0 # no decision; normal permission flow applies
178> }
179> ```
180 180
181ここで、macOS/Linux の設定に対して Claude Code が `Bash "rm -rf /tmp/build"` を実行することにしたとします。以下が起こります。181ここで、macOS/Linux の設定に対して Claude Code が `Bash "rm -rf /tmp/build"` を実行することにしたとします。以下が起こります。
182 182
601 601
602パス プレースホルダーを参照するフックには [exec フォーム](#exec-form-and-shell-form)を優先してください。シェル フォームでは、各プレースホルダーをダブル クォートで囲みます。602パス プレースホルダーを参照するフックには [exec フォーム](#exec-form-and-shell-form)を優先してください。シェル フォームでは、各プレースホルダーをダブル クォートで囲みます。
603 603
604**プロジェクト スクリプト**604> [tab] プロジェクト スクリプト
605 605>
606この例は `${CLAUDE_PROJECT_DIR}` を使用して、`Write` または `Edit` ツール呼び出しの後、プロジェクトの `.claude/hooks/` ディレクトリからスタイル チェッカーを実行します。606> この例は `${CLAUDE_PROJECT_DIR}` を使用して、`Write` または `Edit` ツール呼び出しの後、プロジェクトの `.claude/hooks/` ディレクトリからスタイル チェッカーを実行します。
607 607>
608```json theme={null}608> ```json theme={null}
609{609> {
610 "hooks": {610> "hooks": {
611 "PostToolUse": [611> "PostToolUse": [
612 {612> {
613 "matcher": "Write|Edit",613> "matcher": "Write|Edit",
614 "hooks": [614> "hooks": [
615 {615> {
616 "type": "command",616> "type": "command",
617 "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/check-style.sh",617> "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/check-style.sh",
618 "args": []618> "args": []
619 }619> }
620 ]620> ]
621 }621> }
622 ]622> ]
623 }623> }
624}624> }
625```625> ```
626 626
627**プラグイン スクリプト**627> [tab] プラグイン スクリプト
628 628>
629`hooks/hooks.json` でプラグイン フックを定義し、オプションのトップレベル `description` フィールドを使用します。プラグインが有効な場合、そのフックはユーザーおよびプロジェクト フックとマージされます。629> `hooks/hooks.json` でプラグイン フックを定義し、オプションのトップレベル `description` フィールドを使用します。プラグインが有効な場合、そのフックはユーザーおよびプロジェクト フックとマージされます。
630 630>
631この例は、プラグインにバンドルされたフォーマット スクリプトを実行します。631> この例は、プラグインにバンドルされたフォーマット スクリプトを実行します。
632 632>
633```json theme={null}633> ```json theme={null}
634{634> {
635 "description": "Automatic code formatting",635> "description": "Automatic code formatting",
636 "hooks": {636> "hooks": {
637 "PostToolUse": [637> "PostToolUse": [
638 {638> {
639 "matcher": "Write|Edit",639> "matcher": "Write|Edit",
640 "hooks": [640> "hooks": [
641 {641> {
642 "type": "command",642> "type": "command",
643 "command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh",643> "command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh",
644 "args": [],644> "args": [],
645 "timeout": 30645> "timeout": 30
646 }646> }
647 ]647> ]
648 }648> }
649 ]649> ]
650 }650> }
651}651> }
652```652> ```
653 653>
654プラグイン フックの作成の詳細については、[プラグイン コンポーネント リファレンス](https://code.claude.com/docs/ja/plugins/components.md#hooks)を参照してください。654> プラグイン フックの作成の詳細については、[プラグイン コンポーネント リファレンス](https://code.claude.com/docs/ja/plugins/components.md#hooks)を参照してください。
655 655
656### スキルとエージェントのフック656### スキルとエージェントのフック
657 657
1180 1180
1181各パターンの実行例を以下に示します。1181各パターンの実行例を以下に示します。
1182 1182
1183**トップレベル決定**1183> [tab] トップレベル決定
1184 1184>
1185`decision` の唯一の値は `"block"` です。アクションを進行させるには、JSON から `decision` を省略するか、JSON なしで終了 0 で終了します。1185> `decision` の唯一の値は `"block"` です。アクションを進行させるには、JSON から `decision` を省略するか、JSON なしで終了 0 で終了します。
1186 1186>
1187```json theme={null}1187> ```json theme={null}
1188{1188> {
1189 "decision": "block",1189> "decision": "block",
1190 "reason": "Test suite must pass before proceeding"1190> "reason": "Test suite must pass before proceeding"
1191}1191> }
1192```1192> ```
1193 1193
1194**PreToolUse**1194> [tab] PreToolUse
1195 1195>
1196より豊かな制御のために `hookSpecificOutput` を使用します。許可、拒否、またはユーザーへのエスカレーション。ツール入力を実行前に変更したり、Claude 用に追加コンテキストを注入することもできます。オプションの完全なセットについては、[PreToolUse 決定制御](#pretooluse-decision-control)を参照してください。1196> より豊かな制御のために `hookSpecificOutput` を使用します。許可、拒否、またはユーザーへのエスカレーション。ツール入力を実行前に変更したり、Claude 用に追加コンテキストを注入することもできます。オプションの完全なセットについては、[PreToolUse 決定制御](#pretooluse-decision-control)を参照してください。
1197 1197>
1198```json theme={null}1198> ```json theme={null}
1199{1199> {
1200 "hookSpecificOutput": {1200> "hookSpecificOutput": {
1201 "hookEventName": "PreToolUse",1201> "hookEventName": "PreToolUse",
1202 "permissionDecision": "deny",1202> "permissionDecision": "deny",
1203 "permissionDecisionReason": "Database writes are not allowed"1203> "permissionDecisionReason": "Database writes are not allowed"
1204 }1204> }
1205}1205> }
1206```1206> ```
1207 1207
1208**PermissionRequest**1208> [tab] PermissionRequest
1209 1209>
1210`hookSpecificOutput` を使用して、ユーザーに代わって権限リクエストを許可または拒否します。許可する場合、ツールの入力を変更したり、権限ルールを適用して、ユーザーが再度プロンプトされないようにすることもできます。オプションの完全なセットについては、[PermissionRequest 決定制御](#permissionrequest-decision-control)を参照してください。1210> `hookSpecificOutput` を使用して、ユーザーに代わって権限リクエストを許可または拒否します。許可する場合、ツールの入力を変更したり、権限ルールを適用して、ユーザーが再度プロンプトされないようにすることもできます。オプションの完全なセットについては、[PermissionRequest 決定制御](#permissionrequest-decision-control)を参照してください。
1211 1211>
1212```json theme={null}1212> ```json theme={null}
1213{1213> {
1214 "hookSpecificOutput": {1214> "hookSpecificOutput": {
1215 "hookEventName": "PermissionRequest",1215> "hookEventName": "PermissionRequest",
1216 "decision": {1216> "decision": {
1217 "behavior": "allow",1217> "behavior": "allow",
1218 "updatedInput": {1218> "updatedInput": {
1219 "command": "npm run lint"1219> "command": "npm run lint"
1220 }1220> }
1221 }1221> }
1222 }1222> }
1223}1223> }
1224```1224> ```
1225 1225
1226Bash コマンド検証、プロンプト フィルタリング、自動承認スクリプトを含む拡張例については、ガイドの[自動化できること](https://code.claude.com/docs/ja/hooks-guide.md#what-you-can-automate)と [Bash コマンド バリデーター リファレンス実装](https://github.com/anthropics/claude-code/blob/main/examples/hooks/bash_command_validator_example.py)を参照してください。1226Bash コマンド検証、プロンプト フィルタリング、自動承認スクリプトを含む拡張例については、ガイドの[自動化できること](https://code.claude.com/docs/ja/hooks-guide.md#what-you-can-automate)と [Bash コマンド バリデーター リファレンス実装](https://github.com/anthropics/claude-code/blob/main/examples/hooks/bash_command_validator_example.py)を参照してください。
1227 1227
1656 1656
1657この例では、プレーンテキストで表示するために Claude の応答から markdown の書式を除去します。スクリプトは stdin から各バッチを読み取り、`delta` から太字マーカーとインラインコードのバッククォートを削除して、結果を `displayContent` として返します。1657この例では、プレーンテキストで表示するために Claude の応答から markdown の書式を除去します。スクリプトは stdin から各バッチを読み取り、`delta` から太字マーカーとインラインコードのバッククォートを削除して、結果を `displayContent` として返します。
1658 1658
1659**macOS/Linux**1659> [tab] macOS/Linux
1660 1660>
1661設定ファイルでこのイベントのコマンドフックを登録します:1661> 設定ファイルでこのイベントのコマンドフックを登録します:
1662 1662>
1663```json theme={null}1663> ```json theme={null}
1664{1664> {
1665 "hooks": {1665> "hooks": {
1666 "MessageDisplay": [1666> "MessageDisplay": [
1667 {1667> {
1668 "hooks": [1668> "hooks": [
1669 {1669> {
1670 "type": "command",1670> "type": "command",
1671 "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/plain-display.sh",1671> "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/plain-display.sh",
1672 "args": []1672> "args": []
1673 }1673> }
1674 ]1674> ]
1675 }1675> }
1676 ]1676> ]
1677 }1677> }
1678}1678> }
1679```1679> ```
1680 1680>
1681このスクリプトをプロジェクトの `.claude/hooks/plain-display.sh` に保存し、`chmod +x` で実行可能にします:1681> このスクリプトをプロジェクトの `.claude/hooks/plain-display.sh` に保存し、`chmod +x` で実行可能にします:
1682 1682>
1683```bash theme={null}1683> ```bash theme={null}
1684#!/bin/bash1684> #!/bin/bash
1685jq '{hookSpecificOutput: {hookEventName: "MessageDisplay", displayContent: (.delta | gsub("\\*\\*"; "") | gsub("`"; ""))}}'1685> jq '{hookSpecificOutput: {hookEventName: "MessageDisplay", displayContent: (.delta | gsub("\\*\\*"; "") | gsub("`"; ""))}}'
1686```1686> ```
1687
1688**Windows (PowerShell)**
1689
1690PowerShell を通じてスクリプトを実行するコマンドフックを登録します:
1691
1692```json theme={null}
1693{
1694 "hooks": {
1695 "MessageDisplay": [
1696 {
1697 "hooks": [
1698 {
1699 "type": "command",
1700 "command": "powershell.exe",
1701 "args": [
1702 "-NoProfile",
1703 "-ExecutionPolicy",
1704 "Bypass",
1705 "-File",
1706 "${CLAUDE_PROJECT_DIR}/.claude/hooks/plain-display.ps1"
1707 ]
1708 }
1709 ]
1710 }
1711 ]
1712 }
1713}
1714```
1715
1716`-NoProfile` フラグは PowerShell プロファイルの読み込みをスキップしてフックを高速に起動させ、`-ExecutionPolicy Bypass` は PowerShell がローカルのスクリプトファイルを実行できるようにします。
1717
1718このスクリプトをプロジェクトの `.claude/hooks/plain-display.ps1` に保存します:
1719 1687
1720```powershell theme={null}1688> [tab] Windows (PowerShell)
1721$batch = [Console]::In.ReadToEnd() | ConvertFrom-Json1689>
1722$text = $batch.delta -replace '\*\*', '' -replace '`', ''1690> PowerShell を通じてスクリプトを実行するコマンドフックを登録します:
1723@{1691>
1724 hookSpecificOutput = @{1692> ```json theme={null}
1725 hookEventName = "MessageDisplay"1693> {
1726 displayContent = $text1694> "hooks": {
1727 }1695> "MessageDisplay": [
1728} | ConvertTo-Json1696> {
1729```1697> "hooks": [
1698> {
1699> "type": "command",
1700> "command": "powershell.exe",
1701> "args": [
1702> "-NoProfile",
1703> "-ExecutionPolicy",
1704> "Bypass",
1705> "-File",
1706> "${CLAUDE_PROJECT_DIR}/.claude/hooks/plain-display.ps1"
1707> ]
1708> }
1709> ]
1710> }
1711> ]
1712> }
1713> }
1714> ```
1715>
1716> `-NoProfile` フラグは PowerShell プロファイルの読み込みをスキップしてフックを高速に起動させ、`-ExecutionPolicy Bypass` は PowerShell がローカルのスクリプトファイルを実行できるようにします。
1717>
1718> このスクリプトをプロジェクトの `.claude/hooks/plain-display.ps1` に保存します:
1719>
1720> ```powershell theme={null}
1721> $batch = [Console]::In.ReadToEnd() | ConvertFrom-Json
1722> $text = $batch.delta -replace '\*\*', '' -replace '`', ''
1723> @{
1724> hookSpecificOutput = @{
1725> hookEventName = "MessageDisplay"
1726> displayContent = $text
1727> }
1728> } | ConvertTo-Json
1729> ```
1730 1730
1731markdown を含まないバッチはそのまま通過します。スクリプトが失敗した場合(たとえば `jq` がない場合)、Claude Code は元のテキストを表示し、失敗はセッション内ではなく[デバッグ出力](#debug-hooks)でのみ通知されます。1731markdown を含まないバッチはそのまま通過します。スクリプトが失敗した場合(たとえば `jq` がない場合)、Claude Code は元のテキストを表示し、失敗はセッション内ではなく[デバッグ出力](#debug-hooks)でのみ通知されます。
1732 1732
3357 3357
3358matcher は、完全な名前、`claude-opus-4-6|claude-opus-5` のような `|` 区切りのリスト、または `.*opus.*` のような正規表現で記述します。次の例では完全な名前の matcher を使用し、さらにフックの入力の `to_model` も確認しています。これにより、終了コード 2 で終了して Opus 4.6 への切り替えを拒否し、それ以外の切り替え先は通過させます。3358matcher は、完全な名前、`claude-opus-4-6|claude-opus-5` のような `|` 区切りのリスト、または `.*opus.*` のような正規表現で記述します。次の例では完全な名前の matcher を使用し、さらにフックの入力の `to_model` も確認しています。これにより、終了コード 2 で終了して Opus 4.6 への切り替えを拒否し、それ以外の切り替え先は通過させます。
3359 3359
3360**macOS/Linux**3360> [tab] macOS/Linux
3361 3361>
3362このコマンドは `jq` で `to_model` を確認します。3362> このコマンドは `jq` で `to_model` を確認します。
3363 3363>
3364```json theme={null}3364> ```json theme={null}
3365{3365> {
3366 "hooks": {3366> "hooks": {
3367 "PreModelSwitch": [3367> "PreModelSwitch": [
3368 {3368> {
3369 "matcher": "claude-opus-4-6",3369> "matcher": "claude-opus-4-6",
3370 "hooks": [3370> "hooks": [
3371 {3371> {
3372 "type": "command",3372> "type": "command",
3373 "command": "jq -e '.to_model | test(\"opus-4-6\")' > /dev/null && { echo 'Opus 4.6 is retired for this project. Use a newer model.' >&2; exit 2; }; exit 0"3373> "command": "jq -e '.to_model | test(\"opus-4-6\")' > /dev/null && { echo 'Opus 4.6 is retired for this project. Use a newer model.' >&2; exit 2; }; exit 0"
3374 }3374> }
3375 ]3375> ]
3376 }3376> }
3377 ]3377> ]
3378 }3378> }
3379}3379> }
3380```3380> ```
3381 3381
3382**Windows (PowerShell)**3382> [tab] Windows (PowerShell)
3383 3383>
3384PowerShell でスクリプトを実行するコマンドフックを登録します。3384> PowerShell でスクリプトを実行するコマンドフックを登録します。
3385 3385>
3386```json theme={null}3386> ```json theme={null}
3387{3387> {
3388 "hooks": {3388> "hooks": {
3389 "PreModelSwitch": [3389> "PreModelSwitch": [
3390 {3390> {
3391 "matcher": "claude-opus-4-6",3391> "matcher": "claude-opus-4-6",
3392 "hooks": [3392> "hooks": [
3393 {3393> {
3394 "type": "command",3394> "type": "command",
3395 "command": "powershell.exe",3395> "command": "powershell.exe",
3396 "args": [3396> "args": [
3397 "-NoProfile",3397> "-NoProfile",
3398 "-ExecutionPolicy",3398> "-ExecutionPolicy",
3399 "Bypass",3399> "Bypass",
3400 "-File",3400> "-File",
3401 "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-opus-46.ps1"3401> "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-opus-46.ps1"
3402 ]3402> ]
3403 }3403> }
3404 ]3404> ]
3405 }3405> }
3406 ]3406> ]
3407 }3407> }
3408}3408> }
3409```3409> ```
3410 3410>
3411このスクリプトをプロジェクト内の `.claude/hooks/block-opus-46.ps1` に保存します。3411> このスクリプトをプロジェクト内の `.claude/hooks/block-opus-46.ps1` に保存します。
3412 3412>
3413```powershell theme={null}3413> ```powershell theme={null}
3414$hookInput = [Console]::In.ReadToEnd() | ConvertFrom-Json3414> $hookInput = [Console]::In.ReadToEnd() | ConvertFrom-Json
3415if ($hookInput.to_model -match 'opus-4-6') {3415> if ($hookInput.to_model -match 'opus-4-6') {
3416 [Console]::Error.WriteLine('Opus 4.6 is retired for this project. Use a newer model.')3416> [Console]::Error.WriteLine('Opus 4.6 is retired for this project. Use a newer model.')
3417 exit 23417> exit 2
3418}3418> }
3419exit 03419> exit 0
3420```3420> ```
3421 3421
3422フックが動作することを確認するには、別のモデルで実行中のセッションから `/model claude-opus-4-6` を実行します。Claude Code は現在のモデルを維持し、PreModelSwitch フックが切り替えをブロックしたことを、指定したメッセージを理由として報告します。3422フックが動作することを確認するには、別のモデルで実行中のセッションから `/model claude-opus-4-6` を実行します。Claude Code は現在のモデルを維持し、PreModelSwitch フックが切り替えをブロックしたことを、指定したメッセージを理由として報告します。
3423 3423
3705 3705
3706この例では、繰り返し尋ねられる 1 つの質問にユーザーの代わりに回答します。`issue-tracker` という名前の MCP サーバーがフォームでプロジェクトキーを尋ね、フックが `DOCS` を入力します。スクリプトは、`project_key` がフォームの唯一のフィールドである場合に受け入れます。それ以外のリクエストでは何も出力しないため、ダイアログが表示されます。3706この例では、繰り返し尋ねられる 1 つの質問にユーザーの代わりに回答します。`issue-tracker` という名前の MCP サーバーがフォームでプロジェクトキーを尋ね、フックが `DOCS` を入力します。スクリプトは、`project_key` がフォームの唯一のフィールドである場合に受け入れます。それ以外のリクエストでは何も出力しないため、ダイアログが表示されます。
3707 3707
3708**macOS/Linux**3708> [tab] macOS/Linux
3709 3709>
3710設定ファイルで、サーバー名を matcher としてこのイベントのコマンドフックを登録します。3710> 設定ファイルで、サーバー名を matcher としてこのイベントのコマンドフックを登録します。
3711 3711>
3712```json theme={null}3712> ```json theme={null}
3713{3713> {
3714 "hooks": {3714> "hooks": {
3715 "Elicitation": [3715> "Elicitation": [
3716 {3716> {
3717 "matcher": "issue-tracker",3717> "matcher": "issue-tracker",
3718 "hooks": [3718> "hooks": [
3719 {3719> {
3720 "type": "command",3720> "type": "command",
3721 "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/answer-project-key.sh",3721> "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/answer-project-key.sh",
3722 "args": []3722> "args": []
3723 }3723> }
3724 ]3724> ]
3725 }3725> }
3726 ]3726> ]
3727 }3727> }
3728}3728> }
3729```3729> ```
3730 3730>
3731このスクリプトをプロジェクト内の `.claude/hooks/answer-project-key.sh` に保存し、`chmod +x` で実行可能にします。3731> このスクリプトをプロジェクト内の `.claude/hooks/answer-project-key.sh` に保存し、`chmod +x` で実行可能にします。
3732 3732>
3733```bash theme={null}3733> ```bash theme={null}
3734#!/bin/bash3734> #!/bin/bash
3735input=$(cat)3735> input=$(cat)
3736fields=$(jq -c '.requested_schema.properties // {} | keys' <<<"$input")3736> fields=$(jq -c '.requested_schema.properties // {} | keys' <<<"$input")
3737 3737>
3738if [ "$fields" = '["project_key"]' ]; then3738> if [ "$fields" = '["project_key"]' ]; then
3739 jq -n '{hookSpecificOutput: {hookEventName: "Elicitation", action: "accept", content: {project_key: "DOCS"}}}'3739> jq -n '{hookSpecificOutput: {hookEventName: "Elicitation", action: "accept", content: {project_key: "DOCS"}}}'
3740fi3740> fi
3741```3741> ```
3742
3743**Windows (PowerShell)**
3744
3745サーバー名を matcher として、PowerShell でスクリプトを実行するコマンドフックを登録します。
3746
3747```json theme={null}
3748{
3749 "hooks": {
3750 "Elicitation": [
3751 {
3752 "matcher": "issue-tracker",
3753 "hooks": [
3754 {
3755 "type": "command",
3756 "command": "powershell.exe",
3757 "args": [
3758 "-NoProfile",
3759 "-ExecutionPolicy",
3760 "Bypass",
3761 "-File",
3762 "${CLAUDE_PROJECT_DIR}/.claude/hooks/answer-project-key.ps1"
3763 ]
3764 }
3765 ]
3766 }
3767 ]
3768 }
3769}
3770```
3771
3772このスクリプトをプロジェクト内の `.claude/hooks/answer-project-key.ps1` に保存します。
3773
3774```powershell theme={null}
3775$request = [Console]::In.ReadToEnd() | ConvertFrom-Json
3776$fields = @($request.requested_schema.properties.PSObject.Properties.Name)
3777 3742
3778if ($fields.Count -eq 1 -and $fields[0] -eq 'project_key') {3743> [tab] Windows (PowerShell)
3779 @{3744>
3780 hookSpecificOutput = @{3745> サーバー名を matcher として、PowerShell でスクリプトを実行するコマンドフックを登録します。
3781 hookEventName = "Elicitation"3746>
3782 action = "accept"3747> ```json theme={null}
3783 content = @{ project_key = "DOCS" }3748> {
3784 }3749> "hooks": {
3785 } | ConvertTo-Json -Depth 33750> "Elicitation": [
3786}3751> {
3787```3752> "matcher": "issue-tracker",
3753> "hooks": [
3754> {
3755> "type": "command",
3756> "command": "powershell.exe",
3757> "args": [
3758> "-NoProfile",
3759> "-ExecutionPolicy",
3760> "Bypass",
3761> "-File",
3762> "${CLAUDE_PROJECT_DIR}/.claude/hooks/answer-project-key.ps1"
3763> ]
3764> }
3765> ]
3766> }
3767> ]
3768> }
3769> }
3770> ```
3771>
3772> このスクリプトをプロジェクト内の `.claude/hooks/answer-project-key.ps1` に保存します。
3773>
3774> ```powershell theme={null}
3775> $request = [Console]::In.ReadToEnd() | ConvertFrom-Json
3776> $fields = @($request.requested_schema.properties.PSObject.Properties.Name)
3777>
3778> if ($fields.Count -eq 1 -and $fields[0] -eq 'project_key') {
3779> @{
3780> hookSpecificOutput = @{
3781> hookEventName = "Elicitation"
3782> action = "accept"
3783> content = @{ project_key = "DOCS" }
3784> }
3785> } | ConvertTo-Json -Depth 3
3786> }
3787> ```
3788 3788
3789フックが動作することを確認するには、`claude --debug` で Claude Code を起動し、サーバーがプロジェクトキーを尋ねるようなタスクを Claude に与えます。ダイアログは表示されず、[デバッグログ](#debug-hooks)に `Elicitation resolved by hook: {"action":"accept","content":{"project_key":"DOCS"}}` で終わる行が記録されます。3789フックが動作することを確認するには、`claude --debug` で Claude Code を起動し、サーバーがプロジェクトキーを尋ねるようなタスクを Claude に与えます。ダイアログは表示されず、[デバッグログ](#debug-hooks)に `Elicitation resolved by hook: {"action":"accept","content":{"project_key":"DOCS"}}` で終わる行が記録されます。
3790 3790