0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Codeのhookマッチャー、ハイフン名がv2.1.195で動かなくなった

0
Posted at

はじめに

この記事を読むと、以下がわかります。

  • Claude Code の hooks で matcher フィールドがどう評価されるか(exact-match と regex フォールバックの分岐条件)
  • v2.1.195(2026-06-26)でハイフン付き識別子の扱いが変わった具体的な内容
  • 自分のリポジトリの hooks 設定が影響を受けるかどうかの点検方法

前提知識として、Claude Code の hooks(PreToolUse / PostToolUse 等のイベントで外部コマンドを発火させる仕組み)を一度でも設定したことがあると理解が早いです。

TL;DR

  • Claude Code v2.1.195(2026-06-26)で、hook の matcher フィールドの評価ルールが変わった
  • 変更前は code-reviewer のようなハイフン付き識別子が 意図せず regex(部分一致)として評価 されていた
  • 変更後は英数字・_-・空白・,| のみで構成される matcher は 完全一致(exact-match) として評価される
  • この変更により、code-reviewersenior-code-reviewerもうマッチしなくなる
  • エラーは一切出ない。hook が静かに発火しなくなるだけなので、自分で気づかないと放置しがち

公式ドキュメントで matcher の評価ルールを確認する

まず一次情報を確認します。Claude Code 公式 Changelog の該当箇所です。

Fixed hook matchers with hyphenated identifiers (e.g. code-reviewer, mcp__brave-search) accidentally substring-matching — they now exact-match. Use mcp__brave-search__.* to match all tools from a hyphenated MCP server.

Claude Code Changelog

「バグ修正」という体裁ですが、動いていた設定が動かなくなるという意味では実質的に破壊的変更です。

hooks ドキュメントには、matcher の評価ルールが表で整理されています。

matcher の値 評価のされ方
"*"""、または省略 全イベントにマッチ
英数字・_-・空白・,| のみで構成 完全一致(| または , 区切りで複数指定可)
上記以外の文字を含む JavaScript の正規表現として評価(アンカーなし)

そして、ハイフンの扱いについてはこう明記されています。

Hyphens in the exact-match set require Claude Code v2.1.195 or later. On earlier versions a hyphenated name like code-reviewer is evaluated as an unanchored regular expression, so it also fires for senior-code-reviewer; anchor it as ^code-reviewer$ on those versions to match only that name.

Claude Code Hooks Reference

つまり:

  • v2.1.195より前: - は「その他の文字」扱いなので、code-reviewer という matcher はアンカーなし正規表現として評価され、senior-code-reviewer にも部分一致でマッチしていた
  • v2.1.195以降: - が完全一致文字集合に追加されたため、code-reviewer は完全一致専用になり、senior-code-reviewer にはマッチしなくなる

ちなみに FileChangedStopFailure の2イベントだけは完全一致文字集合がさらに狭く、英数字・_| のみ(ハイフンを含まない)なので、この2イベントに限っては v2.1.195以降もハイフン付き matcher は regex フォールバックのままです。

v2.1.195 前後の挙動差を再現する

公式ドキュメントの記述をもとに、評価ロジックを Python で再現してみます。

import re

def evaluate(matcher: str, tool_name: str, hyphen_in_exact_set: bool) -> bool:
    if matcher in ("*", "", None):
        return True
    allowed = r"a-zA-Z0-9_ ,|"
    if hyphen_in_exact_set:
        allowed += "-"
    if re.fullmatch(f"[{allowed}]*", matcher):
        candidates = [c.strip() for c in re.split(r"[|,]", matcher)]
        return tool_name in candidates
    return re.search(matcher, tool_name) is not None

cases = [
    ("mcp__kinako-mocchi", "mcp__kinako-mocchi__generate_image"),
    ("mcp__kinako-mocchi", "mcp__kinako-mocchi__check_status"),
    ("mcp__kinako-mocchi__.*", "mcp__kinako-mocchi__generate_image"),
    ("code-reviewer", "code-reviewer"),
    ("code-reviewer", "senior-code-reviewer"),
]

for matcher, tool in cases:
    old = evaluate(matcher, tool, hyphen_in_exact_set=False)
    new = evaluate(matcher, tool, hyphen_in_exact_set=True)
    print(f"{matcher:<24} {tool:<38} v2.1.195より前={old} v2.1.195以降={new}")

実行結果:

mcp__kinako-mocchi       mcp__kinako-mocchi__generate_image     v2.1.195より前=True v2.1.195以降=False
mcp__kinako-mocchi       mcp__kinako-mocchi__check_status       v2.1.195より前=True v2.1.195以降=False
mcp__kinako-mocchi__.*   mcp__kinako-mocchi__generate_image     v2.1.195より前=True v2.1.195以降=True
code-reviewer            code-reviewer                          v2.1.195より前=True v2.1.195以降=True
code-reviewer            senior-code-reviewer                   v2.1.195より前=True v2.1.195以降=False

注目すべきは1〜2行目です。mcp__kinako-mocchi という matcher(サーバー名だけを書いて、個別ツール名まで書いていない)は、v2.1.195より前なら部分一致で mcp__kinako-mocchi__generate_image 等の実ツール名を拾えていましたが、v2.1.195以降は完全一致専用になるため 一切マッチしなくなります。3行目のように mcp__kinako-mocchi__.* と明示的にワイルドカード化していれば、両バージョンで動作は変わりません。

自分のリポジトリの設定を点検する

このリポジトリの .claude/settings.json に実際に定義されている hook matcher を確認してみます。

{
  "PreToolUse": [
    { "matcher": "Bash", "hooks": [ /* ... */ ] },
    { "matcher": "mcp__github__create_pull_request|mcp__github__merge_pull_request", "hooks": [ /* ... */ ] }
  ],
  "PostToolUseFailure": [
    { "matcher": "Bash", "hooks": [ /* ... */ ] }
  ]
}

Bashmcp__github__create_pull_request|mcp__github__merge_pull_request はいずれもハイフンを含まないため、今回の変更の影響を受けません。一方で、このリポジトリが接続している MCP サーバーには kinako-mocchi というハイフン付きの名前があります(.mcp.jsonmcpServers に定義)。もし今後 mcp__kinako-mocchi という matcher(個別ツール名やワイルドカードなし)を hooks に追加してしまうと、v2.1.195以降ではその hook は一切発火しなくなります。

自分のリポジトリを点検する手順はシンプルです。

  1. .claude/settings.jsonhooks 配下にある全ての matcher を列挙する
  2. ハイフンを含む値だけを抽出する
  3. その値が「個別ツール名まで完全一致で書かれているか」「ワイルドカード(.* 等)で終わっているか」を確認する
  4. どちらでもない場合(例: mcp__kinako-mocchi のようにサーバー名だけを書いている)は、mcp__kinako-mocchi__.* のように明示的に正規表現化するか、個別ツール名を , または \| 区切りで列挙する

なぜこの変更が地味に危険か

この手の変更が厄介なのは、エラーが一切出ない ことです。matcher の評価に失敗しても Claude Code は何も警告しません。単に「その hook が発火しなくなる」だけなので、CI が落ちるわけでも、ログにワーニングが出るわけでもありません。

特に影響を受けやすいのは以下のパターンです。

  • ハイフン付きの MCP サーバー名を、個別ツール名やワイルドカードなしで matcher に直書きしている
  • ハイフン付きのサブエージェント名(例: code-reviewer)を matcher にしていて、実は senior-code-reviewer のような派生名にも当ててほしかった(元々の部分一致に依存していた)
  • Changelog を「バグ修正」の一言で読み流し、自分の設定への影響を確認していない

まとめ

  • Claude Code v2.1.195(2026-06-26)で、hook matcher の完全一致文字集合にハイフンが追加された
  • ハイフン付き matcher は「部分一致(regex フォールバック)」から「完全一致」に評価方法が変わった
  • 影響を受けるのは、ハイフン付きの MCP サーバー名・サブエージェント名を matcher に使っていて、個別ツール名やワイルドカードを明示していない設定
  • エラーは出ないため、自分の .claude/settings.json を能動的に点検する必要がある

著者視点の発見ポイント

今回、自分のリポジトリで実際に運用している MCP サーバー名(kinako-mocchi)を材料に検証したことで、「ドキュメントを読んだだけでは気づかない罠」が具体的に見えました。mcp__kinako-mocchi のようにサーバー名だけを matcher に書く設定は一見自然に見えますが、v2.1.195以降ではワイルドカードを明示しない限り機能しません。Changelog の1行だけでは「バグ修正」としか読めず、破壊的変更としての重大さが伝わりにくい典型例だと感じました。自分の hooks 設定を棚卸しする良いきっかけになったので、同様にハイフン付きのMCPサーバー名やサブエージェント名を使っている方は、この記事の点検手順を使って一度確認することをおすすめします。

参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?