Claude CodeのmodelPickerでOpus Plan Modeが出てこない — 「カバー済み」誤判定バグの原因と回避策
settings.jsonのmodelPickerにopusplanを追加しても/modelの選択肢に出ない不具合を、公式ドキュメントとGitHub Issue #89690の検証結果から整理する。
エンジニアのゆとです。
opusplan——Plan Modeの間だけOpusを使い、実装フェーズは自動でSonnetに切り替わるモデルエイリアス——は、MAXプランのトークン消費を抑えたい人にとって地味に強い機能だ。毎回/model opusと/model sonnetを手動で往復させなくていい。
これを毎回タイプするのが面倒で、settings.jsonのmodelPickerに「Opus Plan Mode」という名前の行として登録しようとした人が、日本語圏にも英語圏にも一定数いる。だが試した人の多くが同じ壁にぶつかっている。「行は書いた、Claude Codeも設定を読み込んでいる、でも/modelを開いても一覧にその行が出てこない」。エラーは出ない。警告も出ない。ただ静かに消える。
これは設定ミスではない。GitHub Issue #89690として報告されている既知の不具合で、自分がこの記事を書いている時点(Claude Code 2.1.265、2026年9月8日の再検証コメントが最新)でもまだ再現し続けている。原因を公式ドキュメントの一次情報とIssueの技術的な調査から突き合わせて整理し、実際に効く回避策をまとめる。
結論から: 何が起きていて、どう回避するか
| やりたいこと | 結果 |
|---|---|
settings.jsonのmodelPicker.optionsにopusplanの行を追加(デフォルト設定のまま) | 行が消える。/modelピッカーに出てこない。エラーなし |
代わりに/model opusplanと直接コマンドで打つ | 問題なく動く。ピッカーを経由しないのでバグの影響を受けない |
modelPicker.replaceBuiltInOptionsをtrueにする | 公式ドキュメント上、「カバー済みならスキップする」ロジックはこのオプションがオフの時だけ働く仕様。オンにすれば理屈の上ではこのバグを回避できる(後述) |
ANTHROPIC_DEFAULT_MODEL=opusplanで新規セッションのデフォルトにする | これも動かない。ただしmodelPickerのバグとは別の、公式に明記された仕様上の制限 |
再現手順
Issue報告者が示している再現コードはこうだ。
{
"modelPicker": {
"options": [
{
"model": "opusplan",
"label": "Opus Plan Mode",
"description": "Use Opus in plan mode, Sonnet otherwise"
}
]
}
}
claude --settings /tmp/mp.json
セッション内で/modelを実行すると、ビルトインの5行(Default、Opus、Fable、Sonnet、Haiku)だけが表示され、「Opus Plan Mode」の行は出ない。行が消えたことを示すメッセージも一切出ない。設定ファイルのパスや構文が間違っているのかと疑って何度も書き直しても、症状は変わらない。
原因: 「すでにカバーされている」判定の誤爆
なぜ静かに消えるのか。公式のsettings reference(modelPickerの項目)にその挙動が明記されている。
With it off, Claude Code skips a listed model that the built-in lineup already covers.
replaceBuiltInOptions(デフォルトはfalse)がオフの状態、つまり「ビルトインの一覧に追記する」モードでは、Claude Codeは自分で書いた行がビルトインのどれかと「同じモデル」だと判断すると、その行を黙ってスキップする仕様になっている。重複表示を防ぐための仕組み自体は理にかなっている。
問題は、この「すでにカバーされている」判定がopusplanに対して誤爆することだ。Issue報告者は配布されているネイティブバイナリを直接読んで、このカバレッジチェックがどのビルトイン行と衝突しているのかを追跡している。最初は「Opus行と衝突している」と報告されたが、2.1.257のバンドルを再解析した結果、実際にはSonnet行の方が衝突相手だったと訂正されている。
Correction: the collision partner is the Sonnet row, not the Opus row
opusplanはPlan Mode中はOpus、実行中はSonnetという2つのモデルにまたがる特殊なエイリアスだ。カバレッジチェックが「解決後のモデル」を単純比較する実装になっているせいで、opusplanが実行フェーズで使う「Sonnet」という結果だけを見て、「これはもうSonnet行でカバーされている」と誤判定している、というのがIssue上で最も裏付けの強い仮説になっている。
自分の手元でも同じ症状を確認した。opus単体やsonnet単体、外部ゲートウェイのモデルIDを行に追加した場合は問題なく一覧に出る。opusplanだけがこの罠にはまる。
継続して再現している(直っていない)
厄介なのは、これが一時的な不具合ではなく2026年8月下旬から9月上旬にかけて出た複数バージョンで一貫して再現し続けていることだ。Issue上の再検証コメントを時系列で並べるとこうなる。
- 2.1.250(8/28再検証): 再現。関連する変更なし
- 2.1.257(8/28再検証): 再現。カバレッジチェックの衝突相手をSonnet行と訂正
- 2.1.260(9/3再検証): 再現。このバージョンのチェンジログは
/modelピッカーについて「Fable 5.1が表示されない不具合の修正」のみに言及、カバレッジチェック自体には触れていない - 2.1.265(9/8再検証、記事執筆時点で最新): 再現。このバージョンのチェンジログは
/model opusplan[1m]が「Model not found」で弾かれる別バグの修正に言及しているが、これもピッカー側のカバレッジチェックとは別の話
つまり、opusplanまわりの/model関連バグは複数同時に存在していて、そのうちの1つ(タイプ入力での拒否)は直ったが、今回扱っているピッカー表示のバグは未修正のまま残っている。バージョンを上げれば直るだろうと様子見している人は、しばらくその状態が続くと考えたほうがいい。
回避策1: ピッカーを経由せず直接コマンドで打つ
一番確実な回避策は、そもそもmodelPickerのカスタム行に頼らないことだ。opusplanはビルトインのエイリアスとして最初から使えるので、セッション中に直接タイプすればいい。
/model opusplan
これはmodelPickerのカバレッジチェックを一切通らない経路なので、バグの影響を受けない。唯一の欠点は、セッションを開始するたびに手打ちが必要なこと。modelPickerで「一覧から選ぶ体験」を作りたかった人にとっては、その部分の利便性だけは失われる。
回避策2: replaceBuiltInOptionsをtrueにする
modelPickerのフィールド仕様を読むと、もう一段踏み込んだ回避策が見えてくる。公式ドキュメントにはreplaceBuiltInOptionsについて次のように書かれている。
Set it to true to show only these rows, Default, and a row for the model the session is already using. Leave it unset to add these rows after the built-in lineup.
そして、さきほど引用した「カバー済みならスキップする」という挙動は、このオプションがオフのときの説明として書かれている。つまり理屈の上では、replaceBuiltInOptions: trueにしてビルトイン一覧を完全に置き換えるモードに切り替えれば、「すでにカバーされている」判定自体が働かなくなり、opusplanの行も表示されるはずだ。
{
"modelPicker": {
"options": [
{ "model": "opus", "label": "Opus" },
{ "model": "sonnet", "label": "Sonnet" },
{
"model": "opusplan",
"label": "Opus Plan Mode",
"description": "計画はOpus、実装はSonnetに自動切替"
}
],
"replaceBuiltInOptions": true
}
}
この方法にはトレードオフがある。replaceBuiltInOptions: trueはビルトインの一覧・availableModels由来の行・ゲートウェイが検出したモデル・ANTHROPIC_CUSTOM_MODEL_OPTIONをすべて隠す仕様なので、ここで挙げた行以外は一切ピッカーに出なくなる。Opus単体やSonnet単体も普段から使うなら、上の例のように自分で明示的に書き足しておく必要がある。書き忘れたモデルは「Default」経由でしか呼べなくなる。
Issue上ではこのreplaceBuiltInOptionsルートは検証されていない(投稿者はカバレッジチェックのコード追跡に専念していて、この回避策には触れていない)。ドキュメントの仕様どおりに動くはずという一次情報ベースの推測であり、実運用で試す場合は一度/modelで一覧を確認してから本番の設定に反映することをすすめる。
ついでに踏む地雷: ANTHROPIC_DEFAULT_MODELもopusplanを無視する
modelPickerとは別の話として、もう1つ知っておいたほうがいい仕様がある。「新しいセッションのデフォルトモデルをopusplanにしたい」と思って環境変数で指定しても、これも動かない。
export ANTHROPIC_DEFAULT_MODEL=opusplan
公式ドキュメントに、この変数が無視されるケースが明記されている。
Claude Code ignores the variable in these cases: You set it to default, inherit, opusplan, or haiku.
これはバグではなく仕様だ。opusplanはセッションの状態(Plan Modeかどうか)に依存して動作を変えるモード的なエイリアスなので、「新規セッション開始時の固定デフォルト」という概念とかみ合わない、という整理なのだろう。opusplanを毎回のデフォルトにしたいなら、環境変数ではなくsettings.jsonのmodelフィールドに"opusplan"と直接書く方法を使う。こちらはANTHROPIC_DEFAULT_MODELより優先順位が高く、正常に機能する。
{
"model": "opusplan"
}
FAQ
opusplanは廃止されたのか
一時期そう見えた時期がある。Issue #8358(「Bring back “opusplan”, why did you remove it in v2.0.0?」)によれば、opusplanはv1.0.x系では/modelから選べていたが、v2.0.0のタイミングで一度姿を消し、ユーザーからの要望を受けて後のバージョンで復活した経緯がある。「opus plan mode removed」で検索している人が一定数いるのは、この時期の混乱が尾を引いていると考えられる。現行バージョンではopusplanエイリアス自体は健在で、今回扱っているのはあくまでmodelPicker経由での表示不具合だ。
Plan Modeを使わないセッションでopusplanを指定するとどうなるか
opusplanは名前のとおりPlan Modeとセットで意味を持つエイリアスで、Plan Mode中でなければ自動切替のロジックは働かない。Plan Modeに入っていない通常のセッションで/model opusplanを指定すると、実質的にSonnetで動き続けることになる。Plan Modeへの切り替え(Shift+Tab)と組み合わせて使うのが前提の機能だと理解しておくといい。
1Mコンテキストと組み合わせたい場合は
opusplan[1m]という書き方でPlan Mode・実行モードの両方を1Mコンテキストで強制できる。ただし/model経由でこの指定を使うにはClaude Code 2.1.265以降が必要で、--modelフラグやsettings.jsonのmodelフィールド経由ならそれより前のバージョンでも機能する。ピッカー表示の不具合とは別軸の話なので、両方のバージョン要件を混同しないよう注意したい。
この不具合が直ったかどうかはどこで確認できるか
Issue #89690のページを見るのが一番早い。修正された場合は公式のチェンジログにもmodelPickerまたはopusplanという単語が入るはずなので、アップデート時のチェンジログでその2語を検索する習慣をつけておくと見逃しにくい。
まとめ
modelPickerでopusplanの行だけが理由もなく消える現象は、設定ミスではなくカバレッジチェックの実装バグだ。急いで直したいなら/model opusplanを直接打つのが最も確実で、ピッカーからの選択体験にこだわるならreplaceBuiltInOptions: trueを試す価値がある。どちらもコスト最適化のための機能が使いにくいというだけの話で、Opus Plan Mode自体の効果(計画はOpus品質、実装はSonnetの速度とコスト)は変わらない。普段のトークン消費最適化に興味があれば、こちらの記事もあわせて読んでみてほしい。

