OSS · Bash CLI · Claude Code

hook-chain-lens

Claude Codeのhookは4 scopeから加算的に発火する。実際に何が走るかを見る。

現在のcwdでClaude Codeがマージするhook定義 (user・project・local・有効な各plugin) を全部読み込んで、${CLAUDE_PLUGIN_ROOT}を展開し、event別にマージ後chainを表示する読み取り専用CLIです。scope・matcher・timeout・出典ファイルつき。Bash + jq、書き込みなし、hook実行なし。

GitHubで見る doctorが検出するもの →

ターミナルデモ: hook-chain-lens list が現cwdのマージ後chainを表示し、PreCompact (空matcherの2 handler)・SessionStart・PostCompact・UserPromptSubmit をscope・matcher・timeout・出典ファイルつきで並べる。続いて hook-chain-lens doctor が [W1] "PreCompact" has 2 handlers with empty matcher を出す。
list はhookをevent別にグループし、scopeと出典ファイルまで表示します。doctor は同じデータをpass / warn / errorに解釈し、CIゲートに使えるexit codeを返します。

doctorが検出するもの

マージ後chainに対する8つのルール。errorはexit 1で返るので、doctorはClaude Code設定に対するCIゲートやpre-commitチェックとしても使えます。

コード 深刻度 検出内容
W1 warn 同一eventに空matcherのhandlerが2つ以上 — 全部が毎回発火する (順序保持)。意図的なことも意図的でないこともある
W2 warn 同一eventで同じmatcherを2つ以上のhandlerが共有 — 既存pluginのhookをコピペした痕跡が多い
W3 error ${CLAUDE_PLUGIN_ROOT}展開後にcommand参照先ファイルが存在しない — 発火のたびに失敗する
W4 warn commandファイルは存在するが読み取り/実行不可 — インストール手順でパーミッションが落ちている疑い
W5 warn timeoutが異常に低い (1秒未満) — 意図した値のtypoの可能性
I1 info timeoutが異常に高い (300秒超) — 本当にその予算が必要か確認する価値あり
W6 error Claude Codeが認識しないevent名 — ほぼ確実にtypo (PreToolUse を PreToolUsage 等)
W7 warn matcher非対応eventにmatcherフィールドが書かれている — フィールドはdeadで、handlerは毎回発火する

インストール

repoをcloneしてCLIをPATHにシンボリックリンクします。依存: bash 4+, jq, coreutils。Linux・macOS対応。

git clone https://github.com/kenimo49/hook-chain-lens.git
ln -s "$(pwd)/hook-chain-lens/bin/hook-chain-lens" ~/.local/bin/hook-chain-lens

# requires: bash 4+, jq, coreutils

使い方

サブコマンドは3つ。どれも --cwd で project / local scope の読み込み元を切り替えられ、list は --json でjqへのパイプに使えます。

hook-chain-lens list                       # merged chain, grouped by event
hook-chain-lens list --event PreToolUse    # filter to one event
hook-chain-lens list --cwd ~/other-repo    # read project/local scope from elsewhere
hook-chain-lens list --json | jq '.'       # machine-readable output

hook-chain-lens doctor                     # 8 rules; exit 1 on errors, 0 otherwise
hook-chain-lens events                     # every event Claude Code knows, grouped by matcher support

4つの設計判断

面白い判断はぜんぶ「何をしないか」に集約されています。

  1. 読み取り専用を貫く

    hook-chain-lensは settings.json を編集せず、hookをインストールせず、hookを実行しません。壊れたものを黙って無効化することはできず、次の Claude Code 実行の挙動を変えることもできません。静的解析だけなので、セッション途中でも安全に走らせられ、CIに置いても副作用がありません。

  2. 加算型を素直に映す (上書きしない)

    Claude Codeはhookを加算的にマージします。user・project・local・pluginの各scopeで同じeventが定義されていれば、その順で全部走ります。list はこれをそのまま反映します。上位scopeが下位を隠すことはありません。pluginが4個入って全部が UserPromptSubmit に登録した瞬間に驚くやつです。

  3. 「有効」= 「installedかつ opt-in」

    pluginがhookを拠出するのは、installed_plugins.jsonに載っていて、かつ settings.json の enabledPlugins["<key>"] が true のときだけです。install済みだが無効化されているpluginは対象外で、これは Claude Code 実行時の挙動と一致します。マージ結果が実行時と同じになる保証です。

  4. doctorはerrorで非0終了

    warningやinfoは表示するだけで失敗にはしません。error (W3 = ファイル欠落、W6 = 未知のevent名) はexit 1を返すので、hook-chain-lens doctorはリポジトリ内settingsファイルに対する動くpre-commit/CIゲートになります。壊れたhookパスがmainに乗ることはありません。

関連する開発ツール

プロダクト一覧 →

← プロダクト一覧へ