Skip to content

Model strategy

Audience: contributors and maintainers deciding or reviewing tier defaults. For day-to-day --use-llm setup, see docs/llm.md.

GPT-6 Astra is available through llm_provider: codex using ChatGPT subscription login, or the explicitly enabled openai Responses provider. Use llm_reasoning_effort: medium initially; work-queue automation uses high. The current harness, including one using a locally served model, can own all model work with llm_provider: harness. See execution in your harness.

Claude tier defaults below remain specific to Claude agents and Anthropic providers. They do not select an Astra model or change a running session.

This document explains why anvil's agents default to specific Claude tiers (Opus / Sonnet / Haiku) and how to override them. Companion to docs/llm.md, which covers how to configure each provider and has the canonical tier/model-id/cost table.


The headline rule

Default everything to Sonnet, escalate to Opus only for reasoning/architecture/synthesis, drop to Haiku for read-only / mechanical / lookup work.

This is the 2026 community consensus, codified in Anthropic's own docs and surfaced via the routing-telemetry issue (anthropics/claude-code#27665) which documented that 93.8% of tokens were being routed to Opus when smarter defaults would cut that to ~30%. Defaulting every agent to Opus is the headline cost anti-pattern in agent setups — it costs roughly 5× more per token than Sonnet without quality wins on most agent work.

anvil's tier defaults follow this rule directly: DEFAULT_TIER = "sonnet" in planning/llm.py, and each agent's frontmatter sets model: to the tier appropriate for the work it does.


Tier ↔ agent mapping

anvil (5 agents)

Agent Tier Why
planner opus PRD-to-tasks synthesis. Requires understanding implicit dependencies, sizing tasks against acceptance criteria, and deciding what to leave for expand. Hard reasoning over structured but ambiguous input.
critic opus Code review against acceptance criteria. Subtle bugs (race conditions, broken invariants, security regressions) are the high-value finds; reasoning depth dominates token efficiency.
docs-scribe sonnet Structured generation of CHANGELOG entries, README updates, cross-reference fixes. The input (a code change) and output shape (a Keep-a-Changelog entry) are both well-defined.
sentinel haiku Evidence validation: run a shell command, parse exit code, compare against acceptance criteria. The classic "read-only investigator" case Anthropic's own Explore subagent uses Haiku for.
state-keeper haiku Cross-source-of-truth scan: glob the filesystem, query SQLite, list git branches, report drift. Pure read-and-classify.

Override precedence

Users always win:

  1. Per-call argument — pass model= or tier= to a provider constructor in code.
  2. Env var — set ANTHROPIC_MODEL (Anthropic-supported) or use Claude Code's CLAUDE_CODE_SUBAGENT_MODEL=inherit to force every subagent to the session model.
  3. Project config — set llm_tier: opus or llm_model: <id> in .anvil/config.yaml to apply project-wide.
  4. Agent frontmatter — the model: field in each agent's .md file sets the tier-default for that agent.
  5. Module defaultDEFAULT_TIER = "sonnet" in planning/llm.py.

Higher numbers override lower ones. If a user explicitly wants Opus everywhere, that choice is respected — the tier defaults are recommendations, not lock-ins.


Automatic escalation (deferred)

Anthropic ships exactly one first-party "escalate on complexity" pattern: the opusplan model alias, which uses Opus in plan mode and auto-switches to Sonnet for execution. This is the only escalation pattern with first-party support as of May 2026.

Third-party community routers exist (tzachbon/claude-model-router-hook, 0xrdan/claude-router, musistudio/claude-code-router) that classify prompt complexity at the PreToolUse hook level and rewrite the model. None of these are first-party, and anvil does not ship its own router because:

  1. Measuring before optimizing — most projects' agent spend is dominated by overuse of Opus on simple turns, not by undertuning of any single turn. Switching defaults to Sonnet (already the anvil default) captures the bulk of the savings without dynamic routing.
  2. Cost predictability — a dynamic router can surprise ops teams when prompt classification flips a critical path to Haiku. The cost win is real, but the failure mode (a planning task accidentally classified as "simple" and run on Haiku) is opaque to debug.
  3. Opt-in over default — users who want dynamic routing today can wire tzachbon/claude-model-router-hook themselves and override per-agent. Bundling it would force a one-size-fits-all policy.

If a future anvil release ships dynamic escalation, it will be via an explicit llm_router: config key, not by default.


Cost reference

See llm.md § Cost-tier defaults for the canonical per-tier model-id and price table (kept in one place to avoid drift). At a glance: Sonnet is roughly 5× cheaper than Opus per token, and Haiku roughly 15× cheaper — the core economics behind the headline rule above.

For a typical anvil planning session (one PRD → tasks generation + 4 expansions + 6 score augmentations + 3 critic reviews), the current tier defaults reduce per-session token spend by ~60% versus the prior "everything inherits Opus" pattern, with no measurable quality regression on the planner and critic paths (which stay on Opus).


Pinning a project to Opus

Some teams genuinely want Opus everywhere — for compliance, audit, or because their work is consistently in the "deep reasoning" bucket. To pin:

# .anvil/config.yaml
llm_tier: opus

This sets the floor: every provider built by resolve_planner_provider(config) uses Opus. Individual agent frontmatter model: values are independent of this (they govern Claude Code subagent dispatch, not the planning-augmentation calls anvil makes), so if you want Opus across the whole agent fleet too, also set CLAUDE_CODE_SUBAGENT_MODEL=claude-opus-4-7 in your environment.


References