フックとは何か、PreModelSwitchはどのカテゴリーのフックに属するのか?
フックとは、Claude Codeが特定のタイミングで動作を自動実行できるようにする仕組みだ。シェルコマンドを書いたり、HTTPエンドポイントを呼び出したり、MCPツールを呼び出したり、LLMにプロンプトを与えたり、subagentを呼び出したりして、あるイベントがトリガーされた瞬間に自動実行させることができる。最もよく使われる2つのフックはPreToolUse(ツール実行前)とPostToolUse(ツール実行後)で、それぞれ「ツールがまだ実行されておらず、検知できる」タイミングと、「ツールが既に実行完了しており、事後対応しかできない」タイミングに対応している。
PreModelSwitchは、この同じロジックを「モデルの切り替え」という動作に適用したものだ——切り替えが起きる「前」にトリガーされるため、理論上は検知・拒否できる。それと対になるPostModelSwitchは「切り替えが既に起きた」タイミングに対応しており、論理的にはPostToolUseと同じカテゴリーに属する。記録はできるが、阻止はできない。
なぜモデル切り替えは専用のフックセットを持つ価値があるのか、一般的なPreToolUse/PostToolUseで対応するだけではだめなのか?
最も直接的な理由は、モデル切り替えが「ツール呼び出し」ではないという点にある——それはセッション自体の状態の変化であり、以降のすべてのリクエストがどのモデルで処理されるかに影響するものであって、一回のツール実行の結果ではない。PreToolUse/PostToolUseのような汎用的な仕組みでモデル切り替えを検知しようとしても、モデル切り替えに固有の重要な情報——現在のプロンプトキャッシュがまだ温かい状態かどうか、推定されるキャッシュ再構築コストはいくらか——は得られない。こうした情報は「これがモデル切り替えである」という前提があって初めて意味を持つ。
より深い理由は、モデル切り替えがプロンプトキャッシュの動作ロジックに関わっているという点だ。各モデルはそれぞれ独立したキャッシュを持っており、モデルを切り替えると、次のリクエストは会話全体を、キャッシュヒットがまったくない状態で読み込むことになる。切り替えが起きる前にこのコストを評価できる専用の検知ポイントがなければ、モデル切り替えによるキャッシュ再構築コストは「切り替えてから初めて気づく」ものになってしまい、「切り替える前に天秤にかけられる」ものにはならない——これこそがPreModelSwitchが存在する核心的な理由だ。
実際にこの2つのフックをどう使い始めればよいのか?最小限の実用的な設定方法はあるか?
第一段階は、慌てて検知を始めるのではなく、まず観察することだ——ルールを何も書く前に、意図的にモデルを切り替えず、代表的な長いタスクを一度実行してみて、/usageに新しく追加されたプロンプトキャッシュの行や、(カスタム状態行を使っている場合)prompt_cache.warm、prompt_cache.hit_ratioといったフィールドがどう見えるかを単純に観察する。まず「通常の状態でキャッシュがどう振る舞うか」という基準を確立してから、ルールを書き始める方がより正確になる。
第二段階は、「Opusは高価だ」といった単一の決め打ちルールではなく、まずはシンプルな3つの結果分類から始めることだ。対象モデルが許可リストに入っていなければdeny、現在のキャッシュがまだ温かく、推定されるキャッシュ再構築コストが設定した閾値を超えていればask、キャッシュが既に冷えている、コンテキストが小さい、あるいはこの切り替えがタスクのフローの中で予期されていた一部であればallowとする。トリガーされるたびに、元のモデル、対象モデル、要求の出所(手動か自動か)、コンテキストサイズ、キャッシュが温かかったかどうか、推定コストを記録する——ただし、認証情報や会話内容そのものは決して記録しない。
第三段階として初めて、PostModelSwitch向けの事後記録ロジックを追加する。特にPreModelSwitchを経由しない自動フォールバックとセッション復元の2つのシナリオに注意を払い、これらの切り替えも記録されるようにし、まったく痕跡が残らない状態を避ける。
もし自分が個人開発者で、普段の会話が長くない場合、この2つのフックは設定する時間をかける価値があるのか?
もし普段の利用パターンが短時間・単発の会話で、モデルを頻繁に切り替えず、遠い昔の古いセッションを復元することも稀なら、正直なところこの2つのフックがもたらす実際のメリットは限定的だ——キャッシュの再構築によって明確なレイテンシやコストの差を体感することはあまりなく、検知ルールを書く時間をかけても、投資対効果が見合わないかもしれない。
しかし、以下のいずれかに当てはまるなら、個人開発者であっても時間をかける価値がある。セッションを頻繁に長時間実行しており(1つのタスクが数時間、あるいは日をまたぐこともある)、その途中で手動または高速モード経由でモデルを切り替えている場合。数日前の古いセッションを復元して作業を続ける習慣があり、毎回新しく始めるのではない場合。あるいは自動的にモデルを選んでくれるSDKやRemote Controlクライアントを使っていて、それがいつモデルを切り替えているのか自分では完全には把握できていない場合だ。こうした状況では、まずPostModelSwitchの記録ロジックだけを追加してみる(検知は一切せず、純粋に観察する)だけでも、実際の利用の中で「モデル切り替え」がどれくらいの頻度で起き、どれくらいのコストがかかっているのかを明確に把握する助けになる。この可視性を得たうえで、さらに検知ルールを追加するかどうかを決める方が、最初からルールを書くよりも地に足のついたやり方だ。
Claude Code 2.1.251(2026年8月28日)にはPreModelSwitchとPostModelSwitchという2つの新しいフックイベントが追加された——これにより、これまでセッション内で「静かに起きていた」動作(モデルの切り替え)を、検知し、記録し、さらには阻止することさえできるようになった。もしフックという仕組み自体を聞いたことがない、あるいはPreToolUseやPostToolUseしか知らないという人のために、この記事ではこの2つの新しいイベントが実際に何をするのかを基礎から説明する。
Claude Codeでは、セッションの途中でモデルを切り替えることができる——例えばSonnetからOpusへ、あるいはモデルを自動的に切り替える高速モードを有効にする場合などだ。これまでこの動作には検知ポイントが一切なかった。切り替えはただ起きるだけで、システムはあなたに確認を求めることも、詳細を記録することもなく、「今の会話のキャッシュがまだ温かい状態なら、安易にモデルを切り替えないでほしい」というルールを書く方法もなかった。個人利用では大きな違いを感じないかもしれない。しかし、長時間のセッションを頻繁に実行する場合や、複数人で同じゲートウェイを共有しているチームにとっては、モデルの切り替えは実際にはコストと結果の一貫性に直接影響する意思決定ポイントだ。ただ、この意思決定ポイントがこれまでまったく見えず、制御もできなかったにすぎない。
PreModelSwitchは切り替えが「まさに起きようとしている」瞬間にトリガーされる。確認できる情報には、切り替えを要求している元のモデルと対象モデル、現在のコンテキストサイズ、キャッシュがまだ温かい状態かどうか、キャッシュの有効期限、推定されるキャッシュ再構築コスト、価格の出典などが含まれる——これらの情報を得たうえで、このフックはallow(許可)、deny(拒否)、ask(確認)のいずれかを決定できる。PostModelSwitchは切り替えが「既に完了した」後にトリガーされる。確認できるのは、自動フォールバックやセッション復元によって生じた切り替えを含む、その切り替えの完全な結果だ——ただしこのフックは記録するか文脈を追加することしかできず、既に起きたことを止めることはできない。
公式ドキュメントは、見落としやすい細部を特に指摘している。/model、ピッカー、/configを通じた能動的な切り替え要求は、PreModelSwitchとPostModelSwitchの両方をトリガーする。しかし自動フォールバック(例えばあるモデルが一時的に利用できず、システムが自動的にバックアップモデルに切り替える場合)や、セッション復元時に元々使っていたモデルを復元する場合は、PostModelSwitchのみがトリガーされ、PreModelSwitchを経由してあなたが検知することはできない。言い換えれば、もしPreModelSwitchの検知ルールだけを書いて、それですべてのモデル切り替えを掌握できると思い込んでいると、実際には自動フォールバックとセッション復元という2つのシナリオを見逃すことになる——この2つはPostModelSwitchで事後に記録することしかできず、事前に阻止することはできない。
普段短時間・単発の会話しかしない場合、モデル切り替えの影響は通常限定的で、わざわざこの2つのフックを書く必要はあまりない。しかし、以下のいずれかに当てはまるなら、この2つのフックを設定する時間をかける価値がある。セッションが頻繁に長時間になる、SonnetとOpusの間を頻繁に切り替える、モデルを自動的に切り替える高速モードを使っている、古いセッションを復元する、あるいは背後にSDKやRemote Controlのクライアントがあってモデルを自動選択している場合だ。こうした状況では、モデルの切り替えはしばしば次のリクエストが会話全体を、キャッシュヒットがまったくない状態で読み込むことを意味する。切り替えのタイミングが意識的に制御されていなければ、予期せぬレイテンシとコストを招く可能性がある。