メインコンテンツへスキップ
← ブログに戻る
開発ログ2026年7月4日by K.hirano

Fable 5 が弾かれた本当の理由、MCPでもスキルでもなくフック

Claude Code で Fable 5 が毎ターン Opus 4.8 へフォールバックする現象を実機で二分探索。犯人は CLAUDE.md でも MCP でもなく、UserPromptSubmit フックの強制命令調の注入文言でした。

#claude-code#fable-5#hooks#dev-log

こんにちは。部屋干しの洗濯物がなかなか乾かない頃ですね。湿っぽい日が続くと、原因の分からない不調ほど気が重くなるものですが、今回はまさにそういう不調の正体を突き止めた話です。

Fable 5 に切り替えて「こんにちは」と打つだけで、毎回 Opus 4.8 に化けてしまう。中身は何も変えていないのに、です。結論から言うと、犯人は CLAUDE.md(Claude Code に毎回読ませる設定メモ)でも MCP(外部の道具をつなぐ仕組み)でもなく、Fable 5 自身の出来が悪いわけでもありませんでした。自分で仕込んでいた UserPromptSubmit フック(発言を送るたびに自動で走る小さなスクリプト)が、毎ターン差し込んでいた文言です。最初はモデルの機嫌が悪いのだろうと軽く流していたのですが、別プロジェクトでも同じことが起きた時点で、これは環境側の問題だと腹をくくりました。ここから先は、実機の二分探索(容疑者を半分ずつ落として絞り込むやり方)で原因にたどり着くまでの記録です。

この話が効くのは、Claude Code でモデルを切り替えて使っていて、フックやスキルで挙動をカスタマイズしている人です。初期設定のまま使っている人には、正直あまり関係がありません。背景にある Fable 5 そのものの事情は Fable 5 停止は技術事故ではない——米商務省 vs Anthropic、AI統治の攻防を読み解く に書いたので、あわせて読むと今回の論点とのつながりがつかみやすいと思います。

無害な一言でも毎回フォールバックする

現象そのものは単純です。/model fable でセッションを始め、内容に関わらずどんな発話を投げても、Fable 5 の安全機構がフラグを立てて拒否するか、勝手に Opus 4.8 へ切り替わってしまいます。Claude Code にはこの切り替えを制御する switchModelsOnFlag という設定があり、false か true かでエラーの出方がまるで違います。

switchModelsOnFlag: false にしていると、フラグが立った瞬間に応答そのものが返らず、次のエラーで完全に行き止まりになります。

terminal
API Error: Fable 5's safeguards flagged this message (https://www.anthropic.com/legal/aup). This sometimes happens with safe, normal conversations. Claude Code can't respond to this request with Fable 5. Double press esc to edit your last message, or try a different model with /model.

既定の switchModelsOnFlag: true のままだと、止まらない代わりに、断りもなく Opus 4.8 へ降格されます。応答は返ってくるので気づきにくいのですが、末尾に一言だけ添えられています。

terminal
Fable 5's safeguards flagged this message. This sometimes happens with safe, normal conversations. Switched to Opus 4.8.

厄介なのは、「safe, normal conversations」という文言のとおり、内容が本当に無害だということです。「HELLO」の一言ですら弾かれる一方で、私が普段運用しているセキュリティやフックの話で埋め尽くされた濃い会話は、なぜか一度も弾かれたことがありませんでした。内容の危険性で判定しているなら真逆のはずです。この矛盾が、最後に犯人を特定する手がかりになりました。

CLAUDE.md を空にしても変わらなかった

最初に疑ったのは、グローバルの CLAUDE.md でした。うちのグローバル設定はセキュリティ多層防御の記述がかなり濃く、これが Fable 5 の安全分類器(危ない入力を見分ける仕組み)を刺激しているのではないかと考えたのです。そこで CLAUDE.md をほぼ空の最小構成に差し替えて、Fable 5 を起動し直しました。

結果は変わらず、フォールバックしたままでした。記述内容が原因なら、ここで挙動が変わるはずです。変わらなかったので、少なくともプロンプトに常時載っている「静的なテキスト」自体は無罪だと判断しました。容疑者が一つ消えます。

--safe-mode で全部を落とすと通った

次に試したのが claude --safe-mode です。CLAUDE.md・スキル・プラグイン・フック・MCP のすべてを無効化して起動する Claude Code 公式のフラグで、「全部を落とした状態なら通るか」を一発で確かめられます。

これで Fable 5 を起動すると、何のトラブルもなく完走しました。原因はどこかのカスタマイズにある、という白黒がここで一気につきます。あとは無効化した項目を一つずつ戻して、犯人を絞り込むだけです。

遠回りの収穫: -p の非対話モードでは再現しない

ここで一度、遠回りをしました。「MCP かスキルのどちらかが犯人では」と考え、--strict-mcp-config(MCPのみ無効化)を付けたケースとフル装備のケースを、-p の非対話ワンショット(1回だけ質問して答えを受け取る使い方)で比べたのです。

terminal
claude --safe-mode --model claude-fable-5 -p "こんにちは"

結果は両方とも通ってしまい、仮説は棄却されました。ただ、この遠回りには収穫がありました。11回試して11回とも通ったことで、-p の非対話モードはそもそも対話モードで起きているフラグを再現しない、と気づけたのです。つまり -p は、今回の診断には使えない道具でした。ここを見誤ると、実際には何も直っていないのに「治った」と思い込んだまま先へ進んでしまいます。⚠️ 非対話ワンショットで一度「通った」のを見て安心するのが、この調査でいちばん危ない落とし穴です。

対話モードで測り直すと、MCP もスキルも無罪

気を取り直して、対話モードで二分探索をやり直しました。プロジェクト固有の CLAUDE.md や memory を持たない中立なディレクトリを用意し、次の順で実測しています。

  • R0: フル装備の対話セッション → フォールバック(実験台が生きていることをまず確認)
  • R1: --strict-mcp-config(MCP のみ無効) → フォールバック(MCP は無罪)
  • R2: --disable-slash-commands(スキルのみ無効) → フォールバック(スキルも無罪)
  • R3: MCP とスキルを両方無効 → それでもフォールバック

R0 から R3 まで全滅したことで、残る容疑者はプラグイン群(typescript-lsp・rust-analyzer-lsp・codex・security-guidance)と、毎ターン注入される UserPromptSubmit フックの二つに絞られました。

プラグインを全部オフにしても、まだフォールバックした

Round 1 として、プラグインを4つとも無効化し(enabledPlugins を全て false)、フックはそのまま残して新しいセッションを開きました。1発目からフォールバックです。プラグインも無罪と確定しました。

正直、この時点では少し途方に暮れました。残っているのはフックしかない、という消去法の結論に自信が持てなかったからです。

フックの注入文言を空にしたら、初めて通った

Round 2 が決定打でした。プラグインは全て元通りに戻し、代わりに手元の ~/.claude/hooks/court-guard.sh(UserPromptSubmit フック)が毎ターン注入していた文言だけを空文字に差し替えます。他は完全にフル装備のまま、新しいセッションで「こんにちは」と打ちました。

通りました。フル装備のまま、フックの注入内容を消したこの一点だけで、Fable 5 が普通に応答したのです。

Fable 5 フォールバック原因調査の二分探索フロー図。R0からR3まで、Round1・Round2と容疑者を一つずつ無効化していき、最後にUserPromptSubmitフックの注入文言を空にした時だけ通った過程を示す 二分探索の全体像: R0〜R3・Round1で容疑者を消していき、Round2で真犯人(フックの注入文言)にたどり着いた

CLAUDE.md の記述内容、MCP 接続、スキルの有効化、プラグイン4種と、どれも「それらしい」容疑者に見えましたが、一つずつ落として確かめると全部シロでした。二分探索を最後まで続けたからこそ、「たぶんこれだろう」ではなく、実際に確認できる一点まで絞り込めたのだと思います。

引き金は、命令口調の注入文言だった

court-guard.sh が毎メッセージ、内容に関わらず無条件で注入していたのは、次のような文言でした。

terminal
ツールを使う応答は必ず守る: (1)本文テキストを一切前置きせず、ツール呼び出しだけで応答を開始する (2)1応答1ツール(連続させない)(3)ネストJSON引数の重いツールは単発に分解 (4)説明・報告はツール成功後の別メッセージで出す (5)malformedで止まったら謝罪文を書かず直前のツールだけ即再出力。同一ターンで2回以上続いたら新セッションへの切り替えを提案する

「必ず守る」「一切前置きせず」「〜だけで応答」「謝罪せず」と、Claude の既定動作を強制的に上書きする命令口調が、ユーザーの発話とは無関係に毎ターン注入され続けていたわけです。Fable 5 の安全分類器は、おそらくこれをプロンプトインジェクション(外から AI への指示をこっそり書き換える攻撃)やジェイルブレイク的な強制上書きとして検知し、内容の危険性とは無関係に機械的にフラグを立てていたと考えられます。

これで、あの矛盾にも説明がつきます。「HELLO」の一言が弾かれ、セキュリティの濃い会話が弾かれなかったのは、内容ではなく、注入された命令文の"口調"そのものが引き金だったからです。フックが仕込む文面が乱暴だと、会話の中身に関係なく安全機構を刺激してしまう。身をもって知りました。

ただし、仕組みは実測からの推定

一つだけ正直に書いておくと、「強制命令調の文言が安全分類器を誤爆させる」という仕組みは、あくまで実測から導いた推定です。Anthropic 側の分類器の内部ロジックが公開されているわけではないので、断定はできません。今後同じパターンで似た現象が起きても、原因が別にある可能性は残っています。

直したのは注入の出し方、Fable 5 は役割を絞って使う

court-guard.sh は、実際にツール呼び出しの malformed エラー(呼び出しの形が崩れる失敗)を検出した時だけ、柔らかい助言調の文言で条件付き注入する版に書き換えました。クリーンなターン(実際には大多数)では、何も注入しません。これでフル装備の通常セッションでも Fable 5 が問題なく使えるようになりました。2026-07-03 に修正を反映してから、同じ現象は再現していません。

この一件をきっかけに、モデルの使い分けも見直しました。通常セッションは Sonnet 5(effort xhigh)を常用し、Fable 5 は設計やプランニング、アドバイザー用途に絞って /model fable で個別に呼び出す運用に落ち着いています。Fable 5 が壊れていたわけではなく、こちらの注入文言の書き方が乱暴だっただけ、というのが最終的な着地点です。

同じ症状なら、まずフックの注入内容を見る

Fable 5 を通常セッションで使いたいのに理由もなくフォールバックするなら、CLAUDE.md やスキル、MCP を疑う前に、まず自分の UserPromptSubmit フックが毎ターン何を注入しているかを見てください。

terminal
cat ~/.claude/hooks/*.sh

確かめる順番は次のとおりです。

  • 強制命令調の文言を、毎ターン無条件で注入している箇所がないか。それだけで、ここに書いた二分探索の大半を省略できるはずです。
  • 手元にそういうフックがなければ、--safe-mode で全部を落として通るかどうかを確かめる。
  • 二分探索は必ず対話モードで行う。-p の非対話ワンショットは今回のフラグを再現しないので、いくら試しても「治った」ように見えてしまいます。

この記事を書いた人

HW系エンジニアとして20年以上、10,000件を超える顧客訪問と2,000件を超える単独ソリューション実績。AIツールを使った個人開発やIoT農園など、Raspberry Piを使ったオートメーション化なども実践中です!エンジニア専門結婚相談所も運営中、ClaudeCodeで解決できない心の課題も解決いたします!

META-MARK × AI

ローカルAIを動かすGPU、ちゃんと選べていますか?

VRAM・性能・コスパをMetaScoreで数値化。AIアプリ別の推奨ハードウェア要件も確認できます。