Diff v2 → v3

v2: bot legacy · 2026-07-28T06:30:54Z
v3: bot legacy · 2026-08-10T10:28:05Z
  # Model Routing: Haiku, Sonnet, Opus
  
  A feature run can spawn 50 agent invocations. All Opus = 20× cost, 5× latency, no marginal benefit on the easy ones. All Haiku = silent failures on the hard ones. Route each task to the smallest model that's correct.
  
  ## Tiers
  
  ```mermaid
  flowchart LR
      Task --> R{What kind?}
      R -->|lookup, grep, read| H[Haiku]
      R -->|docs, tests, bulk edit, straight impl| S[Sonnet]
      R -->|design, complex impl, review| O[Opus]
+     R -->|security, SEC-*| F[Fable]
  ```
  
  | Tier | Best for | Worst at |
  |------|----------|----------|
  | Haiku | lookups, grep, mechanical reads, listings | judgement, design |
  | Sonnet | well-specified impl, tests, docs, bulk edits | open-ended design |
  | Opus | spec writing, plan/design, complex impl, adversarial review | throughput, cost |
+ | Fable | security review, threat modelling, `SEC-*` tasks | cost; **refuses much of the work it's pointed at — see below** |
  
  Use the next tier up when in doubt.
  
+ ## The Fable tier
+ 
+ `@fable` is the security tier: `SEC-*` tasks, threat modelling, the security dimension
+ of adversarial review. Model ID `claude-fable-5`. It is the top of the capability
+ ladder — the strongest reasoning available, thinking always on, effort dialable
+ `low` → `max`.
+ 
+ Three things to know before you route anything here.
+ 
+ **It refuses a large share of security work by design.** Fable 5 runs classifiers over
+ incoming requests targeting most cybersecurity content, and Anthropic states plainly
+ that the model *is not intended for that domain*. Its documented bug-finding gains
+ **exclude security-focused analysis**, which is precisely where these classifiers apply.
+ Benign security tooling trips them as a false positive. A refusal is **not an error** —
+ you get an HTTP 200 with `stop_reason: "refusal"` and `stop_details.category: "cyber"`,
+ so a harness that reads `content[0]` without checking `stop_reason` first sees an empty
+ result rather than a failure.
+ 
+ **Budget for it.** $10 / $50 per MTok — 2× Opus 5's $5 / $25. A tier that both costs
+ double and rejects part of its own workload is a deliberate trade, not a free upgrade.
+ 
+ **It requires 30-day data retention.** Fable 5 is unavailable under zero data retention:
+ an org configured below 30 days gets `400 invalid_request_error` on *every* Fable request,
+ valid payload or not. Check the org's retention setting before assuming a request is
+ malformed.
+ 
+ ### When a `@fable` task comes back refused
+ 
+ *In the harness* (`@fable` tags dispatched by `/speckit.implement`), there is no per-tag
+ fallback parameter — the tier tag is a routing suggestion the harness reads, nothing more.
+ The recovery is the one this page already prescribes for every tier: **re-run the task at
+ `@opus`.** Treat a `cyber` refusal as a tier mis-route, not a task failure.
+ 
+ *In an API-driven pipeline*, opt into server-side fallbacks so the refusal is re-served
+ in the same call rather than surfacing to you:
+ 
+ ```python
+ client.beta.messages.create(
+     model="claude-fable-5",
+     max_tokens=16000,
+     betas=["server-side-fallback-2026-07-01"],
+     fallbacks="default",          # routes by refusal category; cyber → claude-opus-4-8
+     messages=[...],
+ )
+ ```
+ 
+ `fallbacks: "default"` picks the recommended substitute per refusal category, so you never
+ maintain a model list. Pin one explicitly with the array form
+ (`betas=["server-side-fallback-2026-06-01"]`, `fallbacks=[{"model": "claude-opus-4-8"}]`)
+ — note the *earlier* beta date gates the array form; pairing either header with the other
+ form is a 400. Server-side fallbacks are **Claude API only**; on Bedrock, Vertex, or Foundry
+ register the SDK's client-side refusal-fallback middleware instead.
+ 
+ Either way the destination is Opus. Which is the honest summary of this tier: **Fable is
+ the strongest model in the ladder and the weakest choice for the tasks routed to it**, and
+ Opus catches what it drops.
+ 
  ## Where it's encoded
  
  **Per phase** — frontmatter on each command (`model: opus`). The harness reads it and routes the invocation.
  
- **Per task** — `@haiku / @sonnet / @opus` tag on each line in `tasks.md`. `/speckit.implement` dispatches subagents at the suggested tier.
+ **Per task** — `@haiku / @sonnet / @opus / @fable` tag on each line in `tasks.md`. `/speckit.implement` dispatches subagents at the suggested tier.
  
  The tag is a routing suggestion, not a guarantee. Validate what comes back: if a `@haiku` task returns something that clearly needed judgement, re-run it a tier up rather than accepting it. Trusting tier tags blindly is how subtle semantic failures get through.
  
+ `@fable` needs one extra check the others don't: an empty or non-committal result may be a
+ `cyber` refusal rather than a finding of "nothing to report". On a security task, *no
+ findings* and *declined to look* are indistinguishable downstream — and they mean opposite
+ things. Confirm which one you got before you record a clean pass.
+ 
  ## Worked example
  
  Feature: add `/health` endpoint returning `{status, deps[]}`.
  
  | Task | Tier | Why |
  |------|------|-----|
  | Locate router setup | @haiku | Pure lookup |
  | Find dependency-check helpers | @haiku | grep-style |
  | Design the response shape | @opus | Design decision; affects callers |
  | Write the model struct | @sonnet | Mechanical given the design |
  | Implement the handler | @sonnet | Straight impl |
  | Wire the route | @sonnet | Mechanical |
  | Write the integration test | @sonnet | Behaviour fully specified |
+ | Auth check on the endpoint (`SEC-001`) | @fable | Security task |
  | Adversarial review | @opus | Judgement-heavy |
  
- Two Opus invocations. Six Sonnet/Haiku. ~15% of tokens at Opus tier. ~4× faster wall-clock than all-Opus, same correctness.
+ Two Opus invocations, one Fable, six Sonnet/Haiku. ~15% of tokens at Opus tier. ~4× faster wall-clock than all-Opus, same correctness.
  
+ `SEC-001` is the one to watch. If it comes back refused, re-run it at `@opus` — and note
+ that on a `/health` endpoint the security question ("should this leak dependency names to
+ an unauthenticated caller?") is exactly the kind of benign review that trips the cyber
+ classifiers as a false positive.
+ 
  ## Heuristics
  
  **Output shape.** Listing/extraction → Haiku. Specified function body → Sonnet. New design or cross-file → Opus.
  
  **Judgement required.** None → Haiku. Bounded by the spec → Sonnet. About the spec, or spanning files → Opus.
  
+ **Security-shaped.** `SEC-*`, threat modelling, authz review → Fable, with `@opus` as the
+ standing fallback. Budget for a meaningful refusal rate rather than treating each one as an
+ incident.
+ 
  ## Anti-patterns
  
  - **All Opus**: cheap to do, expensive to run. Wall-clock balloons on trivial subtasks.
  - **All Haiku**: cheap and wrong. Failures look like [[The One-Shot Problem]] — surface passes, semantics off.
  - **Trust the tag blindly**: tags are hypotheses. Flaky @sonnet → bump to @opus. Trivial @opus → demote.
+ - **Reading a `@fable` refusal as a clean bill of health**: the worst failure on this page. A declined security review that gets logged as "no findings" is a silent gap with a green tick on it — check `stop_reason` before you believe the result.
+ - **`@fable` as a general "hardest tasks" tier**: it's scoped to security here. Non-security work that genuinely needs the top of the ladder is a separate routing question — don't let the tag drift into meaning "important".
  
  > Use the smallest model that's correct, not the biggest model you can afford.