DEV Community

Creeta
Creeta

Posted on • Originally published at news.creeta.com

The env var that silently routes Fable agents to Haiku

You pinned model: fable in every subagent's YAML, yet your fleet keeps answering like Haiku. The culprit is almost always one stale environment variable that sits above your pin in a strict resolution order — and it fails silently.

The Precedence Ladder: Why CLAUDE_CODE_SUBAGENT_MODEL Overrides Your Fable Pin

In Claude Code, a subagent's model is resolved by a strict, one-directional precedence chain: (1) the CLAUDE_CODE_SUBAGENT_MODEL environment variable, (2) a per-invocation parameter, (3) the YAML frontmatter model field, and (4) the session model . The env var always wins, with no exception. That means a leftover export CLAUDE_CODE_SUBAGENT_MODEL=haiku in your shell or CI environment quietly downgrades every subagent to Haiku 4.5, regardless of the model: fable you declared in frontmatter .

Rank Resolver Beats everything below it
1 CLAUDE_CODE_SUBAGENT_MODEL env var Overrides all — including a pinned model: fable
2 Per-invocation parameter Beats frontmatter and session
3 YAML frontmatter model Beats session only
4 Session model The final fallback

Worked example: your agent file declares model: fable, but your environment still holds CLAUDE_CODE_SUBAGENT_MODEL=haiku from an earlier test run. Resolution stops at rank 1 — the agent runs on Haiku 4.5, and nothing warns you.

The second silent trap is availability. If the pinned model cannot be served — Fable 5 is gated behind your plan, or blocked by a ZDR conflict, or your Claude Code predates v2.1.170 where it first appears in the /model picker — Claude Code falls back to the session model with no error and no log entry . So there are two ways your Fable pin evaporates without a trace: an env var above it, or an unavailable model beneath it. Both look identical from the outside — an agent that simply behaves like a smaller model than you asked for.

Before Running a Fable Agent Fleet: Prerequisites

Before you pin model: fable anywhere, confirm four things — because the silent fallbacks above only bite when a prerequisite is missing. Fable 5 requires a paid Anthropic plan (Pro, Max, Team, or Enterprise) and is not available on Free . Through the API the model ID is claude-fable-5, reachable directly or via Amazon Bedrock, Google Cloud, and Microsoft Foundry .

Check these before you build:

  • Client build: Claude Code v2.1.170+ is the minimum for Fable 5 to appear in the /model picker — earlier builds won't surface it even on a qualifying plan .
  • Data retention: Fable 5 requires 30-day data retention, which is mutually exclusive with Zero Data Retention (ZDR). If your org enforces ZDR, Fable is disqualified — confirm before pinning .
  • Concurrency: Each parallel agent session needs its own valid Claude Code access. There is no shared-seat multiplexing — ten concurrent agents draw ten concurrent usage slots against your plan .

Metering follows your sign-in mode: subscription and Enterprise seats draw from plan usage windows, while API-key sign-in is pay-as-you-go per token . Miss any of these and your pinned Fable model resolves to nothing — the exact evaporation described above.

How to Declare Subagent Model in YAML

You set a subagent's model in its definition file's YAML frontmatter, in the model: field. Claude Code accepts six values there: sonnet, opus, haiku, fable, a full model ID such as claude-fable-5, or inherit — the default, which reuses the session model . Each agent gets its own file, so pin the model per role rather than globally.

Before you trust any pin, audit the environment. Run echo $CLAUDE_CODE_SUBAGENT_MODEL in the shell where the fleet launches, and in CI print it as an explicit job step. If it returns a stale value, unset or blank it — that env var sits at the top of the resolution order and will silently override every model: fable line you wrote .

For an orchestrator-plus-parallel-agents layout, the frontmatter is minimal:

# orchestrator.md
---
name: orchestrator
model: fable
---

# developer.md
---
name: developer
model: sonnet
---

# chore.md
---
name: chore-runner
model: haiku
---
Enter fullscreen mode Exit fullscreen mode

With no conflicting env var set, the commander runs on Fable 5 for planning and final checks, each parallel developer runs on Sonnet 5, and chore agents run on Haiku 4.5 . As Anthropic's model-config docs put it, resolution follows a strict precedence where "the env var, then the per-invocation parameter, then frontmatter, then the session model" decide the winner — so the YAML only holds if nothing higher intercepts it (source: Claude Code model config, 2026-06).

Finally, confirm the effective model with Claude Code's agent view, added in v2.1.139 in May 2026 . Read the model reported on each agent's first tool call — not just the string in the file. What the runtime shows, not what the YAML declares, is the model you are actually paying for.

Foot-Guns: When Fable Model Routing Goes Wrong

Four failure modes turn silent model swaps into wrong bills and false "success" signals. Each one passes the checks a naive fleet trusts — a clean YAML file, an HTTP 200, a returned response — while the effective model, cost, or completion state is not what you think. The common thread: the runtime, not your configuration, decides what actually ran.

  • CI pipeline drift. A CLAUDE_CODE_SUBAGENT_MODEL=haiku exported by an earlier job step persists into every downstream agent invocation in that job. Because env sits at the top of the precedence ladder , each subagent quietly runs Haiku 4.5 at Haiku cost. Cost monitoring then looks healthy — spend drops — so it never alerts you that your Fable orchestrator was demoted mid-pipeline.
  • Classifier re-route. Requests flagged by Anthropic's cybersecurity or biology classifiers auto-route to Opus 4.8 at the API layer, with no Fable-price charge . The agent still receives HTTP 200, so status code alone cannot confirm the effective model — a run you believe is Fable 5 may have executed on Opus.
  • Refusals arrive as 200. Fable can return stop_reason: "refusal" inside an HTTP 200 response, not a 4xx . Wire an explicit stop_reason check into your verify-loop exit criteria; a loop keyed only on HTTP status will treat a refusal as a completed task and merge nothing.
  • Geography. Fable 5 carries a 1.1x US-only inference multiplier . Parallel agents with mixed regional routing produce inconsistent latency and cost you cannot debug from YAML alone.

"In multi-agent setups the orchestrator, not the workers, is the failure point — fan out ten agents and the slices are usually fine, but the results fail to fit together" — model-routing guidance for Fable 5 fleets (source: mcp.directory, 2026).

The defense is the same in all four cases: assert the effective model and stop_reason from the response, not from your config or the HTTP layer, and route flagged or failed runs to a deliberate Opus 4.8 fallback .

Recommended Fable Fleet Arrangement: Orchestrator, Parallel Agents, Haiku Chores

The arrangement that survives long runs layers models by role rather than running Fable 5 everywhere. Fable 5 sits at the commander layer because its 1M-token context window can hold the full repository, spec, task ledger, and every parallel agent's output at once . That matters because multi-agent runs collapse at the orchestrator, not at individual tasks — the manager runs out of context or loses the plan while the workers' slices are fine .

  • Commander — Fable 5: planning, delegation, and final checks; anchored by file-based memory that Anthropic reports tripled long-task gains versus Opus 4.8 on internal evaluations .
  • Parallel developers — Sonnet 5: research, implementation, and verification across fan-out, pipeline, and verify-loop delegation patterns .
  • Chores — Haiku 4.5: low-stakes formatting, summarization, and notifications at the lowest cost, so no Fable quota is spent on deterministic sub-tasks .

One wiring rule ties it together: for any agent that could hit the cybersecurity or biology classifier re-route, add a deliberate Opus 4.8 fallback and never assume Fable is the effective model . Fable can return stop_reason: "refusal" inside an HTTP 200, so make verify-loop exit criteria checkable against the response body — not inferred from the transport layer . Put the biggest context at the top, the cheapest model at the bottom, and assert every effective model — that is the fleet that holds together.

Frequently asked questions

What is CLAUDE_CODE_SUBAGENT_MODEL and where do I set it?

CLAUDE_CODE_SUBAGENT_MODEL is the environment variable that overrides the model for every Claude Code subagent, and it sits at the top of the resolution precedence — ahead of a per-invocation parameter, the YAML frontmatter model field, and the session model . You set it wherever your environment loads: a shell profile, a .env file, or CI environment variables. Because it wins over a pinned model: fable, a leftover CLAUDE_CODE_SUBAGENT_MODEL=haiku will silently route your agents to Haiku. Unset it to let the YAML declarations take effect.

Does Fable 5 work with Zero Data Retention orgs?

No. Fable 5 requires 30-day data retention, which is mutually exclusive with Zero Data Retention (ZDR) . Enterprise orgs configured for ZDR cannot use Fable 5. To run it, either disable ZDR for the relevant workspace or route those agents to a model that operates under your retention policy. Fable 5 also needs Claude Code v2.1.170 or later to appear in the /model picker .

Can two Claude Code agents share one seat or subscription?

No. Each parallel agent session requires its own valid Claude Code access, and concurrent agents consume concurrent usage slots against your Anthropic account . Fleet-style orchestration does not bundle model access or bypass Anthropic limits — parallel agents mean parallel spend . Check your plan's concurrency limits before fanning out ten workers, and note that subscription seats draw from plan usage windows while API-key sign-in is billed pay-as-you-go per token .

What happens if I pin model: fable but Fable 5 is not available on my account?

Claude Code silently falls back to the session model — there is no error and no log warning . Since Fable 5 is not the default on any account and requires the retention and version conditions above, an unavailable pin resolves down the ladder without telling you. Verify the effective model through the agent view or the first tool-call response body rather than trusting the YAML declaration alone.

Why did a Fable agent call cost Opus 4.8 pricing instead of Fable pricing?

Requests flagged by Anthropic's cybersecurity or biology classifiers are auto-routed to Opus 4.8 at the API layer, and Fable pricing (\$10 per million input tokens, \$50 per million output) is not applied to those re-routed calls . Fable is a product surface, not a fixed model, so the same endpoint can serve a different model per request. Read the model field in the response body to confirm which model actually ran — and remember Fable can return stop_reason: "refusal" inside an HTTP 200, so never infer the outcome from transport status alone .

Top comments (0)