Windows で Claude Code のフックが動かない: 原因と対処法
Mac では問題なく動くフックが、Windows では何もしなかったり、さらに悪いことにすべてのコマンドをブロックしたりします。原因はほぼ必ずシェルです。Windows で Claude Code がフックをどう実行するのか、そしてフックを確実に動かす方法を説明します。
要点
Windows では、Claude Code はフックの command を Git Bash で実行し、Git Bash がインストールされていない場合は PowerShell で実行します。"shell": "powershell" または "shell": "bash" でどちらを使うかを明示し、stdout には JSON オブジェクト 1 つだけを出力し(プロファイルの echo は不可)、ブロックするには終了コード 2 を使い、Claude Code を更新してください(Windows のフックに関する不具合が 2.1.310 までのバージョンでいくつも修正されています)。デバッグには /hooks と claude --debug を使います。
フックを実行するシェル
Claude Code は command の文字列をシェルに渡します。macOS と Linux では sh -c、Windows では Git Bash、Git Bash がインストールされていなければ PowerShell です。フックリファレンスにあるこの一文で、「Mac では動くのに」という報告のほとんどが説明できます。PowerShell 向けに書いたコマンドは Git Bash では失敗し、bash スクリプトは PowerShell では失敗します。そしてどちらになるかは、たまたま Git for Windows がインストールされているかどうかで決まります。
shell フィールドを使えば推測の余地がなくなります。指定できる値は "bash" または "powershell" です。
Git Bash を使いたいのに Claude Code が見つけられない場合は、Git for Windows をインストールするか、CLAUDE_CODE_GIT_BASH_PATH にその場所を設定してから、新しいセッションを開始してください。
症状とその原因
| 症状 | 考えられる原因 | 対処法 |
|---|---|---|
| フックがまったく実行されないように見える | 古い Claude Code バージョン、イベントやマッチャーの誤り、設定内の不正な JSON | 更新する。/hooks を確認する。コメントと末尾のカンマを削除する |
ParserError または「unexpected token」 | PowerShell の構文が Git Bash に渡っている、またはその逆 | shell を明示的に設定する |
| フックの出力が「does not start with {」 | JSON の前に何かが出力されている。多くはシェルプロファイル | プロファイルの出力を抑える。ログは stderr に送る |
\ と / が混在したパスが見つからない | Windows のパス変数に Unix 形式のサフィックスを連結している | exec 形式を使う。プログラムは command に、各引数は args に書く |
Git Bash から powershell: Permission denied | 2.1.283 と 2.1.304〜2.1.305 で断続的に報告されている(#103910、未解決) | "shell": "powershell" を使い、間に Git Bash を挟まないようにする |
| ガード用のフックがすべてを通してしまう | 終了コードが 2 ではなく 1、または古いバージョンのフェイルオープンの不具合 | ブロックするには 2 で終了する。2.1.310 以降に更新する |
| フックが出力なしで即座に戻る | シェルが終了を待たない GUI サブシステムのプログラム | コンソールプログラムを使うか、プロセスの終了を待つ |
stdout には JSON だけを
Claude Code はフックの標準出力を応答として読み取ります。ドキュメントのルールは簡潔で、stdout には JSON オブジェクト以外を何も出力しないこと、です。Windows ではこれが気づきにくい形で壊れます。Git Bash や一部の環境ではシェルプロファイルが読み込まれ、プロファイル内の無条件の echo が JSON の前に付け加えられてしまうのです。するとフックはターミナルでは「動く」のに、Claude Code の中では失敗します。
ログは代わりにファイルか stderr に書き出し、プロファイルの出力は対話型シェルの場合だけに限定してください。
終了コード: 2 はブロックし、1 はブロックしない
終了コード 0 は成功です。終了コード 2 はブロッキングエラーで、ブロック可能なイベントでは Claude Code が操作を止めて stderr の内容を表示します。有効な JSON なしの終了コード 1 は非ブロッキングエラーで、操作はそのまま進みます。 フックでポリシーを強制するなら、終了コード 2 を使ってください。
すべてのイベントがこの方法でブロックできるわけではありません。Notification フックの終了コードは無視されます。Stop フックが 2 で終了すると、Claude は作業を続けます。PermissionRequest フックは終了コード 2 を完全に無視し、JSON 内の decision オブジェクトで判断を伝えます。
Claude Code 2.1.309 で、フックのプログラムが終了コード 2 で終了しても PowerShell フックがブロックしない不具合が修正されました。PowerShell のガードが無視されているように見える場合は、まずバージョンを確認してください。
更新する価値のある Windows 向け修正
Anthropic の変更履歴には、Windows のフックに関する修正が長く続いています。古いフォーラムのスレッドの内容を説明するものは次のとおりです。
| バージョン | 修正内容 |
|---|---|
| 2.1.47 | Windows で PreToolUse と PostToolUse のフックがエラーを出さずに失敗していた。現在は cmd.exe ではなく Git Bash で実行される |
| 2.1.161 | bash を明示的に呼び出すフック(/usr/bin/bash script.sh)が「command not found」で失敗していた |
| 2.1.299 | shell を指定していない PreToolUse と PermissionRequest のフックが、Git for Windows がない環境でフェイルオープンしていた。現在は失敗したガードがブロックする |
| 2.1.309 | PowerShell フックが終了コード 2 でブロックしなかった。"shell": "powershell" のガードが Git for Windows がない環境でフェイルオープンしていた |
| 2.1.310 | コマンドが引用符付き文字列だけ(引用符で囲んだパスなど)のガードが、Git Bash がない環境でフェイルオープンしていた |
「No hook is working on Windows」という古い issue(#10450)は 2.0.27 で報告されたもので、コメント投稿者が、stdin がフックのコマンドに届いていないことを原因として突き止めています。そこまで古いバージョンを使っているなら、他のデバッグより先に更新してください。
プログラムを直接呼び出す
フックがコンパイル済みのプログラムなら、exec 形式(args フィールド。args を設定すると shell は無視されます)でシェルを経由せずに実行できます。Windows の exec 形式では、command が .exe のような実際の実行ファイルに解決される必要があります。.cmd や .bat のシム(npm がインストールするものの大半を含む)は、シェルなしでは起動できません。.exe を指定するか、シェル形式を使ってください。
自分たちのフックヘルパーを作って学んだ教訓を 1 つ。Windows では、GUI サブシステム向けにビルドされたプログラムをシェルから起動すると、シェルはその終了を待ちません。シェルはすぐに戻り、エージェントは空の出力を読み取り、フックはまったく動いていないように見えます。フックのプログラムはコンソールプログラムでなければなりません。
プラグインのフックとパス
${CLAUDE_PLUGIN_ROOT}/hooks/run.sh のようにパスを組み立てるプラグインのフックは、v2.1.2 から v2.1.12 の間 Windows で動きませんでした(#18610)。変数はバックスラッシュのパスに展開され、そこにスラッシュのサフィックスを付けると、bash が解決できない混在パスになるためです。現在のドキュメントにはすっきりした解決策が載っています。フックがパスのプレースホルダーを参照するときは、必ず exec 形式を使うことです。プログラムを command に、各引数を args に書きます。例: "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/scripts/format.js"]。各要素は 1 つの引数として渡され、間にシェルが入らないので壊されることがありません。
デバッグのチェックリスト
/hooksを実行すると、設定済みのすべてのフックとその出どころが読み取り専用の一覧で表示されます。claude --debug(セッション中なら/debug)で、各フックの実行、出力、終了コードが表示されます。claude --debug-file <path>を使うとファイルに書き出せます。- JSON を検証します。 設定ファイルは厳密な JSON です。末尾のカンマが 1 つあるだけで、ファイル全体が無効になります。
- マッチャーを確認します。 マッチャーは大文字と小文字を区別します。
"*"、""、またはマッチャーなしはすべてに一致します。 - コマンドを自分で実行します。 Claude Code が使うのと同じシェルで、サンプルの JSON をパイプで渡して試します。
- タイムアウトを確認します。 コマンドフックのデフォルトは 600 秒です。人の応答を待つフックには、それだけの余裕が必要です。
調査中にすべてのフックをオフにするには、"disableAllHooks": true を設定します。
通知と承認だけが目的なら
Windows でフックを設定する理由の多くは 1 つです。Claude Code があなたを必要としているときに気づき、応答することです。Pet Island なら、スクリプトを書かずにそれができます。ワンクリックで Claude Code に接続し、Windows 特有の細かい点を代わりに処理して、すべての許可リクエスト、質問、プランを、コマンドや差分とともに画面上部の小さなアイランドに表示します。そこで許可または拒否を選べます。Claude Code を WSL 内で実行している場合にも動作します。
よくある質問
Windows で Claude Code のフックを実行するのはどのシェルですか?
Git Bash です。Git Bash がインストールされていない場合は PowerShell です。明示的に選ぶには、フックに "shell": "powershell" または "shell": "bash" を設定します。
フックがターミナルでは動くのに Claude Code では動かないのはなぜですか?
多くの場合、余分な出力が原因です。テキストを echo するシェルプロファイルの出力が、フックの JSON の前に付け加えられます。stdout には JSON オブジェクトだけを出力してください。
フックでツール呼び出しをブロックするには?
終了コード 2 で終了します(または JSON で deny の判断を返します)。終了コード 1 は非ブロッキングエラーで、操作はそのまま進みます。PermissionRequest フックは終了コード 2 を無視し、代わりに decision オブジェクトを使います。
フックのコマンドに .cmd や .bat ファイルを使えますか?
exec 形式では使えません。Windows では .exe のような実際の実行ファイルに解決される必要があります。.cmd や .bat ファイルを実行するにはシェル形式を使います。
フックが失敗した理由を確認するには?
claude --debug を実行するか /debug と入力します。どのフックが読み込まれているかは /hooks で確認できます。
出典
このページの設定と動作はすべて、2026年10月26日 に以下のページと照らし合わせて確認しました。エージェントは変化が速いため、内容が一致しなくなった場合は公式ページの記述を優先してください。
- Claude Code ドキュメント: Hooks reference
- Claude Code ドキュメント: Hooks guide
- Claude Code: CHANGELOG
- Issue #10450: Windows でフックがまったく動かない
- Issue #18610: Windows でプラグインのフックがスクリプトを実行できない
- Issue #103910: フックが断続的に powershell を起動できない(Git Bash)