◉CLAUDE LABEN
●2.1.301 — vim の % モーション、VS Code パネルでの LaTeX 数式表示、使用量上限待ちのリトライ監視の上限が入りました(10/15)●2.1.299 — 200K トークン超で約54分放置した会話はアイドル圧縮。MCP の許可ルールは名指ししたサーバーだけに一致します●SONNET 4.5 — Claude API での提供終了は 11/30、残り45日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました●2.1.301 — vim の % モーション、VS Code パネルでの LaTeX 数式表示、使用量上限待ちのリトライ監視の上限が入りました(10/15)●2.1.299 — 200K トークン超で約54分放置した会話はアイドル圧縮。MCP の許可ルールは名指ししたサーバーだけに一致します●SONNET 4.5 — Claude API での提供終了は 11/30、残り45日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました
記事一覧/Claude Code
⟐ Claude Code/2026-07-01中級

Claude Code をアップデートしたら hook が発火しなくなった — ハイフン入り matcher の厳密一致化(v2.1.195)

Claude Code v2.1.195 でハイフンを含む hook matcher が部分一致から厳密一致に変わり、既存の PreToolUse フックが静かに発火しなくなりました。原因の切り分けと、壊れない matcher の書き方をまとめます。

Claude Code265hooks22トラブルシューティング51matcher自動化87

朝、いつものように差分を確認していて、手が止まりました。

コミット前に必ず走るはずの SwiftLint チェックが、通っていないのです。エラーで止まったのではありません。フックそのものが、一度も動いた形跡なく静かに素通りしていました。

前夜、Claude Code を最新へ上げたばかりでした。動かなくなったのではなく、「何も起きなくなった」。この種の無音の失敗が、いちばん時間を溶かします。

原因は、v2.1.195 で入った hook matcher の挙動変更でした。私と同じように、ハイフンを含む matcher を書いていた方は同じ落とし穴にはまっているかもしれません。切り分けの過程ごと、記録として残しておきます。

何が起きていたか

私の設定では、特定のツール実行に対してだけフックを差し込んでいました。settings.json の該当箇所は、おおよそこういう形です。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          { "type": "command", "command": ".claude/hooks/pre-edit-check.sh" }
        ]
      }
    ]
  }
}

これ自体は問題なく動いていました。問題は、別のプロジェクトで使っていた「独自のツール名」を狙った matcher のほうでした。

MCP 経由のツールには mcp__myserver__run-lint のような、ハイフンを含む名前が付きます。私はそれを狙って、次のように書いていました。

{ "matcher": "run-lint" }

v2.1.194 までは、この run-lint が mcp__myserver__run-lint に「部分一致」して発火していました。ところが v2.1.195 で、ハイフンを含む matcher は「厳密一致」として扱われるよう修正されました。

run-lint は mcp__myserver__run-lint と完全一致しません。だから、何のエラーも出さずに、ただ一致しなくなったのです。

最初に疑ったこと

順番に、間違った方向を疑いました。参考までに、私がたどった順路を残します。

最初はシェルスクリプトの権限を疑いました。chmod +x を確認し、直接叩いてみると、スクリプト自体は正しく動きます。ここでフック本体の不具合は消えました。

次に疑ったのは JSON の壊れです。settings.json を検証にかけても、構文は正常でした。

三番目に、claude --debug でセッションを起動し、フックの評価ログを追いました。ここで決定的な手がかりが出ます。PreToolUse の評価自体は走っているのに、私の matcher にマッチした hook が「0件」と記録されていたのです。

スクリプトは無事、JSON も無事、評価も走っている。残るのは matcher の一致判定だけ。ここでようやく、前夜のアップデートに意識が向きました。

原因の確定

変更履歴を確認すると、v2.1.195 に「ハイフンを含む hook matcher を部分一致ではなく厳密一致にする」旨の修正が入っていました。

つまり、これまで暗黙に部分一致で拾えていた matcher は、ハイフンをまたぐ瞬間に一致しなくなります。私の run-lint はその典型でした。

厄介なのは、これが「バグ修正」だという点です。以前の部分一致は、意図しないツールまで巻き込む副作用がありました。厳密化は正しい方向の変更です。ただ、既存設定にとっては挙動が変わる破壊的変更であり、しかもエラーを出さないため、気づくのが遅れます。

自分の設定が古い暗黙の挙動に依存していた、というのが結論でした。

解決策

対処は明快です。matcher を、実際のツール名に対して正しくマッチする形へ書き直します。選択肢は主に三つあります。

一つ目は、ツール名を厳密に書ききる方法です。もっとも安全で、意図も明確になります。

{ "matcher": "mcp__myserver__run-lint" }

二つ目は、正規表現で狙う方法です。MCP ツールをサーバー単位でまとめて拾いたいときに向きます。

{ "matcher": "mcp__myserver__.*" }

三つ目は、ワイルドカードで MCP ツール全体を対象にする方法です。範囲は広くなるので、フック側で本当に処理すべきか判定するのが前提になります。

{ "matcher": "mcp__.*" }

私は一つ目を採りました。狙ったツールが一つだけなら、名前を書ききるのが誤爆もなく読みやすいためです。書き換えた後、claude --debug で該当ツールを実行し、評価ログに hook が「1件」と出ることを確認しました。ここまで見て、ようやく安心できました。

念のため、修正前後の挙動を整理します。

matcher の記述v2.1.194 までv2.1.195 以降
run-lintmcp__myserver__run-lint に部分一致(発火)一致せず(発火しない)
mcp__myserver__run-lint一致(発火)一致(発火)
mcp__myserver__.*一致(発火)一致(発火)

ハイフンを含まない Edit や Write のような標準ツール名は、今回の変更の影響を受けません。影響が出るのは、ハイフンをまたいで部分一致に頼っていた matcher だけです。

再発を防ぐために

同じ無音の失敗を二度踏まないよう、運用側でいくつか手を打ちました。

まず、matcher は「部分一致に頼らず、ツール名を厳密に書く」ことを原則にしました。省略形は一見便利ですが、暗黙の一致仕様に寄りかかる分だけ、アップデートで足元をすくわれやすくなります。

次に、フックが「本当に発火したか」をログに残すようにしました。スクリプトの冒頭で標準エラーへ一行書き出すだけでも、素通りしたのか実行されたのかが後から判別できます。

#!/usr/bin/env bash
echo "[pre-edit-check] fired at $(date -u +%FT%TZ)" >&2
# 本来の処理

無音の失敗のいちばんの敵は、失敗が記録に残らないことです。フックが動いた事実そのものを残しておくと、次にアップデートで挙動が変わっても、切り分けの起点になります。

最後に、Claude Code をアップデートしたら、フックが絡む主要な操作を一度だけ手で動かして確認する、という小さな儀式を挟むことにしました。派手ではありませんが、無人で回すパイプラインほど、この確認が効きます。

個人開発で複数のプロジェクトを回している私自身、多くの作業を自動化のフックに預けています。それだけに今回の一件は「便利さのために暗黙仕様へ寄りかかると、静かに壊れる」という教訓として、胸に残りました。

フックの評価ログの読み方そのものに手こずった経験がある方は、Claude Code フックの本番デバッグ手法も合わせて参考になるかもしれません。matcher の書き方から丁寧に押さえたい場合はClaude Code フック完全ガイドを、アップデート起因の別の不具合についてはClaude Code の自動アップデート失敗の対処をご覧ください。

次に確認すべきこと。お使いの settings.json を開き、matcher にハイフンを含む文字列を部分一致で使っていないか、一度だけ見直してみてください。該当があれば、厳密なツール名か正規表現に置き換えておくと安心です。

同じ無音の失敗で時間を溶かす方が一人でも減れば嬉しいです。お読みいただきありがとうございました。

シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

⟐ Claude Code2026-10-05
「コミットは私がします」と書いたのに git log に一行増えていた朝、指示を強めるのをやめました
Claude Code に「コミットしないで」と頼んだのにコミットされたとき、まず git reset --soft で戻し、permissions.deny と PreToolUse hook の二層で物理的に止める手順です。deny ルールが素通しする git -c の形と、hook の試し方を書き残します。
⟐ Claude Code2026-09-02
モデル切り替えの記録と歯止めを、フック2本で作る
PreModelSwitch と PostModelSwitch を使い、無人実行中のモデル切り替えを記録するフックと、約束していない切り替えだけを止めるフックをゼロから作ります。実測値つきの手順です。
⟐ Claude Code2026-09-01
heredoc のクォートを1つ落とすと、ログに書いた金額や日付が別物になります
未クォートの heredoc は本文の変数とバックティックを実行します。実測した4通りの書き換わり方、3種類のクォート記法の比較、プレースホルダと sed で値を安全に埋める手順、既存スクリプトを棚卸しする検出コードまでをまとめました。