|
| 1 | +# Requirements: Model-Agnostic Routing |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +Make the spec-driven plugin work correctly on any Claude-compatible backend (direct Anthropic API, Claude Code Router, LiteLLM, opencode, etc.) by removing snapshot-pinned model IDs from agent frontmatter, supporting tier aliases with env-var overrides, and showing a one-time optimization notice when a non-Anthropic backend is detected. |
| 6 | + |
| 7 | +## User Roles |
| 8 | + |
| 9 | +| Role | Description | |
| 10 | +|------|-------------| |
| 11 | +| Plugin User (Direct) | Developer using the plugin with the standard Anthropic API | |
| 12 | +| Plugin User (Router) | Developer using the plugin through a third-party router or proxy (LiteLLM, CCR, opencode, etc.) | |
| 13 | +| Plugin Author | Maintainer of the spec-driven plugin who needs to update model references on new Anthropic releases | |
| 14 | + |
| 15 | +## User Stories |
| 16 | + |
| 17 | +### US-1: Forward-Compatible Model References |
| 18 | + |
| 19 | +**As a** Plugin Author |
| 20 | +**I want** agent model references to use tier aliases instead of snapshot-pinned IDs |
| 21 | +**So that** the plugin works on current and future Anthropic model generations without manual patching each release |
| 22 | + |
| 23 | +#### Acceptance Criteria (EARS) |
| 24 | + |
| 25 | +1. WHEN the plugin is loaded by Claude Code |
| 26 | + THE SYSTEM SHALL resolve agent models from tier alias strings (`opus`, `sonnet`, `haiku`) in the `model:` field of each agent's YAML frontmatter, not from snapshot-pinned identifiers like `claude-opus-4-6` or `claude-haiku-4-5-20251001` |
| 27 | + |
| 28 | + WARNING: `agents/spec-implementer.md` was involved in BUG-1: Anti-stub sweep. Ensure anti-stub enforcement text in the agent's system prompt body remains intact after editing the frontmatter. |
| 29 | + |
| 30 | + WARNING: `agents/spec-tester.md` was involved in BUG-1: Anti-stub sweep. Ensure anti-stub enforcement text in the agent's system prompt body remains intact after editing the frontmatter. |
| 31 | + |
| 32 | + WARNING: `agents/spec-reviewer.md` was involved in BUG-1: Anti-stub sweep. Ensure anti-stub enforcement text in the agent's system prompt body remains intact after editing the frontmatter. |
| 33 | + |
| 34 | +2. WHEN any of the 11 agent files in `agents/*.md` is inspected |
| 35 | + THE SYSTEM SHALL contain exactly one of the following values in the `model:` YAML frontmatter field: `opus`, `sonnet`, or `haiku` -- with no version number, snapshot suffix, or `claude-` prefix |
| 36 | + |
| 37 | +3. WHEN the plugin is used on a newer Anthropic model generation (e.g., Opus 4.7, Sonnet 5.0) |
| 38 | + THE SYSTEM SHALL route agents to the correct model tier without any file edits, because the frontmatter contains only the tier alias |
| 39 | + |
| 40 | +4. THE SYSTEM SHALL preserve the existing tier assignments: `spec-planner` and `spec-reviewer` on `opus`; `spec-tasker`, `spec-validator`, `spec-implementer`, `spec-tester`, `spec-acceptor`, `spec-consultant`, `spec-documenter`, and `spec-scanner` on `sonnet`; `spec-debugger` on `haiku` |
| 41 | + |
| 42 | +--- |
| 43 | + |
| 44 | +### US-2: Non-Anthropic Backend Compatibility |
| 45 | + |
| 46 | +**As a** Plugin User (Router) |
| 47 | +**I want** the plugin to work when I run Claude Code against a non-Anthropic backend |
| 48 | +**So that** I can use the spec-driven workflow with any Claude-compatible router or proxy |
| 49 | + |
| 50 | +#### Acceptance Criteria (EARS) |
| 51 | + |
| 52 | +1. WHEN a user runs a shell script (`spec-exec.sh`, `spec-loop.sh`, `spec-complete.sh`, `spec-accept.sh`, `spec-docs.sh`, `spec-release.sh`, `spec-verify.sh`, `spec-retro.sh`) and the environment variable `ANTHROPIC_BASE_URL` is unset |
| 53 | + THE SYSTEM SHALL treat the backend as Anthropic (direct API) and not display any optimization notice |
| 54 | + |
| 55 | +2. WHEN a user runs a shell script and `ANTHROPIC_BASE_URL` is set to a value containing the substring `anthropic.com` (e.g., `https://api.anthropic.com/v1`) |
| 56 | + THE SYSTEM SHALL treat the backend as Anthropic and not display any optimization notice |
| 57 | + |
| 58 | +3. WHEN a user runs a shell script and `ANTHROPIC_BASE_URL` is set to a value that does NOT contain the substring `anthropic.com` (e.g., `http://localhost:4000`, `https://my-litellm.example.com/v1`) |
| 59 | + THE SYSTEM SHALL treat the backend as non-Anthropic and display the optimization notice (subject to `SPEC_QUIET` suppression per US-3) |
| 60 | + |
| 61 | +4. THE SYSTEM SHALL NOT make any network calls, DNS lookups, or HTTP requests as part of backend detection -- detection is purely string-based on the `ANTHROPIC_BASE_URL` environment variable |
| 62 | + |
| 63 | +5. WHEN the plugin runs on direct Anthropic API (no `ANTHROPIC_BASE_URL` set, or set to an `anthropic.com` URL) |
| 64 | + THE SYSTEM SHALL behave identically to v5.0.3 in all functional aspects (backward compatibility) |
| 65 | + |
| 66 | + WARNING: `scripts/spec-exec.sh` was involved in BUG-1: Anti-stub sweep. Ensure anti-stub enforcement text in the prompt template remains intact after adding backend detection sourcing. |
| 67 | + |
| 68 | + WARNING: `scripts/spec-loop.sh` was involved in BUG-1: Anti-stub sweep. Ensure anti-stub enforcement text in the prompt template remains intact after adding backend detection sourcing. |
| 69 | + |
| 70 | +--- |
| 71 | + |
| 72 | +### US-3: Non-Anthropic Backend Guidance Notice |
| 73 | + |
| 74 | +**As a** Plugin User (Router) |
| 75 | +**I want** to receive guidance about optimizing model routing when I'm on a non-Anthropic backend |
| 76 | +**So that** I know which env vars to set and where to find configuration documentation |
| 77 | + |
| 78 | +#### Acceptance Criteria (EARS) |
| 79 | + |
| 80 | +1. WHEN a non-Anthropic backend is detected (per US-2 AC-3) and `SPEC_QUIET` is not set to `1` |
| 81 | + THE SYSTEM SHALL print an optimization notice to stderr containing ALL of the following: |
| 82 | + - A header line: `[spec-driven] Non-Anthropic backend detected` |
| 83 | + - The detected URL (value of `ANTHROPIC_BASE_URL`) |
| 84 | + - The complete list of 11 per-agent env var names: `SPEC_MODEL_PLANNER`, `SPEC_MODEL_IMPLEMENTER`, `SPEC_MODEL_DEBUGGER`, `SPEC_MODEL_TASKER`, `SPEC_MODEL_VALIDATOR`, `SPEC_MODEL_REVIEWER`, `SPEC_MODEL_TESTER`, `SPEC_MODEL_SCANNER`, `SPEC_MODEL_ACCEPTOR`, `SPEC_MODEL_DOCUMENTER`, `SPEC_MODEL_CONSULTANT` |
| 85 | + - A placeholder example for at least one env var (e.g., `export SPEC_MODEL_PLANNER=deepseek-v3`) |
| 86 | + - A pointer to the documentation file: `docs/advanced/model-routing.md` |
| 87 | + - Instructions to suppress the notice: `export SPEC_QUIET=1` |
| 88 | + |
| 89 | +2. THE SYSTEM SHALL print the optimization notice to stderr (file descriptor 2), not stdout (file descriptor 1), so that it does not pollute output that tooling may parse |
| 90 | + |
| 91 | +3. THE SYSTEM SHALL print the optimization notice at most once per script invocation, even if multiple functions or code paths re-source the detection helper |
| 92 | + |
| 93 | +4. WHEN `SPEC_QUIET` is set to `1` |
| 94 | + THE SYSTEM SHALL NOT print the optimization notice, regardless of backend detection result |
| 95 | + |
| 96 | +5. WHEN `SPEC_QUIET` is set to any value other than `1` (e.g., `0`, `true`, empty string) or is unset |
| 97 | + THE SYSTEM SHALL NOT suppress the notice (only the exact value `1` suppresses) |
| 98 | + |
| 99 | +--- |
| 100 | + |
| 101 | +### US-4: Per-Agent Model Override via Environment Variables |
| 102 | + |
| 103 | +**As a** Plugin User (Router) |
| 104 | +**I want** to override the model used for each agent via environment variables |
| 105 | +**So that** I can map each agent tier to the specific model my router exposes |
| 106 | + |
| 107 | +#### Acceptance Criteria (EARS) |
| 108 | + |
| 109 | +1. WHEN the `/spec` command spawns the `spec-planner` agent via the Task tool and the environment variable `SPEC_MODEL_PLANNER` is set to a non-empty string |
| 110 | + THE SYSTEM SHALL pass the value of `SPEC_MODEL_PLANNER` as the `model:` parameter to the Task tool invocation, overriding the frontmatter default |
| 111 | + |
| 112 | + WARNING: `commands/spec.md` was involved in BUG-2: Validate-fix loop routing. Ensure the validate-fix loop in Step 4.5 still routes vague-requirement issues to `spec-planner` and task-traceability issues to `spec-tasker` after adding env-var override instructions. |
| 113 | + |
| 114 | +2. WHEN any `SPEC_MODEL_*` environment variable is set for a given agent |
| 115 | + THE SYSTEM SHALL use that value as the model identifier passed to the Task tool, regardless of what tier alias is in the agent's frontmatter |
| 116 | + |
| 117 | +3. WHEN no `SPEC_MODEL_*` environment variable is set for a given agent |
| 118 | + THE SYSTEM SHALL use the tier alias from the agent's YAML frontmatter (e.g., `opus`, `sonnet`, `haiku`) as the model |
| 119 | + |
| 120 | +4. THE SYSTEM SHALL support the following env-var-to-agent mapping (one variable per agent, all 11 covered): |
| 121 | + |
| 122 | + | Env Var | Agent | Default Tier | |
| 123 | + |---------|-------|-------------| |
| 124 | + | `SPEC_MODEL_PLANNER` | spec-planner | opus | |
| 125 | + | `SPEC_MODEL_TASKER` | spec-tasker | sonnet | |
| 126 | + | `SPEC_MODEL_VALIDATOR` | spec-validator | sonnet | |
| 127 | + | `SPEC_MODEL_IMPLEMENTER` | spec-implementer | sonnet | |
| 128 | + | `SPEC_MODEL_TESTER` | spec-tester | sonnet | |
| 129 | + | `SPEC_MODEL_REVIEWER` | spec-reviewer | opus | |
| 130 | + | `SPEC_MODEL_DEBUGGER` | spec-debugger | haiku | |
| 131 | + | `SPEC_MODEL_SCANNER` | spec-scanner | sonnet | |
| 132 | + | `SPEC_MODEL_ACCEPTOR` | spec-acceptor | sonnet | |
| 133 | + | `SPEC_MODEL_DOCUMENTER` | spec-documenter | sonnet | |
| 134 | + | `SPEC_MODEL_CONSULTANT` | spec-consultant | sonnet | |
| 135 | + |
| 136 | +5. WHEN a command that spawns agents (at minimum: `commands/spec.md`, `commands/spec-brainstorm.md`, `commands/spec-refine.md`, `commands/spec-tasks.md`, `commands/spec-validate.md`) invokes the Task tool |
| 137 | + THE SYSTEM SHALL include instructions in the command prompt to check the relevant `SPEC_MODEL_*` env var and pass it as the `model:` parameter when set |
| 138 | + |
| 139 | +6. THE SYSTEM SHALL NOT attempt env-var interpolation inside YAML frontmatter -- the override mechanism lives entirely in the spawning command's prompt logic |
| 140 | + |
| 141 | +--- |
| 142 | + |
| 143 | +### US-5: Accurate Model-Agnostic Documentation |
| 144 | + |
| 145 | +**As a** Plugin User (Direct or Router) |
| 146 | +**I want** documentation to describe model routing in terms of tiers rather than pinned version numbers |
| 147 | +**So that** the docs remain accurate regardless of which model generation or backend I'm using |
| 148 | + |
| 149 | +#### Acceptance Criteria (EARS) |
| 150 | + |
| 151 | +1. WHEN a user reads `CLAUDE.md` |
| 152 | + THE SYSTEM SHALL display a "Model Routing" table that uses tier names (`opus` / `sonnet` / `haiku`) and tier descriptions (e.g., "Deep reasoning for edge cases and architecture") instead of version-specific identifiers like "Opus 4.6" or "Sonnet 4.6" |
| 153 | + |
| 154 | +2. WHEN a user reads `commands/spec.md` |
| 155 | + THE SYSTEM SHALL display a "Model Routing" table that uses tier names and descriptions without version-specific identifiers |
| 156 | + |
| 157 | +3. WHEN a user reads any of the 11 agent files in `agents/*.md` |
| 158 | + THE SYSTEM SHALL find `description:` text that references tiers (e.g., "runs on the opus tier for deep reasoning") rather than specific versions (e.g., "runs on Opus 4.6") |
| 159 | + |
| 160 | +4. WHEN a user reads documentation under `docs/agents/`, `docs/commands/index.md`, `docs/commands/spec.md`, `docs/workflow/`, `docs/getting-started/`, or `docs/advanced/extending.md` |
| 161 | + THE SYSTEM SHALL find tier-based language instead of version-pinned references for all model mentions |
| 162 | + |
| 163 | +5. WHEN a user reads `docs/advanced/model-routing.md` |
| 164 | + THE SYSTEM SHALL find a guide containing ALL of: |
| 165 | + - Explanation of the three-tier system (opus/sonnet/haiku) and which agents use which tier |
| 166 | + - Full list of `SPEC_MODEL_*` env vars with descriptions |
| 167 | + - Explanation of override precedence (env var > frontmatter tier alias) |
| 168 | + - Description of backend detection behavior (`ANTHROPIC_BASE_URL` logic) |
| 169 | + - Instructions for suppressing the notice (`SPEC_QUIET=1`) |
| 170 | + - Example router configurations for at least three routers: Claude Code Router (CCR), LiteLLM, and opencode |
| 171 | + - Example model mappings using hypothetical OSS models (e.g., DeepSeek-V3 for opus tier, Qwen3-Coder for sonnet tier, a small 7B-8B model for haiku tier) |
| 172 | + |
| 173 | +6. THE SYSTEM SHALL NOT modify any files under `.claude/specs/spec-intelligence-layer/` or `.claude/specs/spec-plugin-v3-enhancements/` (archived specs are out of scope) |
| 174 | + |
| 175 | +--- |
| 176 | + |
| 177 | +### US-6: Version Bump |
| 178 | + |
| 179 | +**As a** Plugin Author |
| 180 | +**I want** the plugin version to be bumped from `5.0.3` to `5.1.0` |
| 181 | +**So that** the model-agnostic routing change is identifiable as a minor (feature) release |
| 182 | + |
| 183 | +#### Acceptance Criteria (EARS) |
| 184 | + |
| 185 | +1. WHEN `.claude-plugin/plugin.json` is inspected |
| 186 | + THE SYSTEM SHALL show `"version": "5.1.0"` |
| 187 | + |
| 188 | +2. WHEN `skills/spec-workflow/SKILL.md` is inspected |
| 189 | + THE SYSTEM SHALL show `version: 5.1.0` in the YAML frontmatter |
| 190 | + |
| 191 | +--- |
| 192 | + |
| 193 | +## Non-Functional Requirements |
| 194 | + |
| 195 | +### NFR-1: Banner Output Isolation |
| 196 | + |
| 197 | +THE SYSTEM SHALL print the optimization notice exclusively to stderr (file descriptor 2). No banner content shall appear on stdout under any circumstances. |
| 198 | + |
| 199 | +### NFR-2: Banner Idempotency |
| 200 | + |
| 201 | +THE SYSTEM SHALL print the optimization notice at most once per shell script invocation. If `detect-backend.sh` is sourced multiple times within a single script (e.g., sourced by both the main script and a nested library), the notice shall only print on the first sourcing. |
| 202 | + |
| 203 | +### NFR-3: No Network Calls for Detection |
| 204 | + |
| 205 | +THE SYSTEM SHALL NOT make any network calls (HTTP requests, DNS lookups, TCP connections) as part of the backend detection logic. Detection is a pure string comparison on the `ANTHROPIC_BASE_URL` environment variable. |
| 206 | + |
| 207 | +### NFR-4: Backward Compatibility |
| 208 | + |
| 209 | +WHEN no `SPEC_MODEL_*` environment variables are set and `ANTHROPIC_BASE_URL` is unset or points to `anthropic.com` |
| 210 | +THE SYSTEM SHALL behave identically to v5.0.3 for all functional workflows. The only difference is the tier alias string in frontmatter instead of the snapshot ID, which Claude Code resolves equivalently. |
| 211 | + |
| 212 | +### NFR-5: Shell Script Convention Compliance |
| 213 | + |
| 214 | +THE SYSTEM SHALL follow the existing `set -e` convention (PAT-3) in the new `scripts/lib/detect-backend.sh` helper. The helper shall NOT use `set -euo pipefail` or any convention that deviates from the existing scripts. |
| 215 | + |
| 216 | +### NFR-6: Minimal File Scope |
| 217 | + |
| 218 | +THE SYSTEM SHALL limit file modifications to the files enumerated in design.md. In particular, the following files shall NOT be modified: |
| 219 | +- `.claude/specs/spec-intelligence-layer/*` (archived spec) |
| 220 | +- `.claude/specs/spec-plugin-v3-enhancements/*` (archived spec) |
| 221 | +- `commands/spec-team.sync-conflict-20260407-015530-WTRWCNZ.md` (orphaned file) |
| 222 | + |
| 223 | +--- |
| 224 | + |
| 225 | +## Out of Scope |
| 226 | + |
| 227 | +- Runtime model validation (checking if the model string actually resolves on the backend) |
| 228 | +- Automatic model mapping (guessing which OSS model corresponds to which tier) |
| 229 | +- Configuration files beyond env vars (no `.spec-driven.yml` or similar config file) |
| 230 | +- Changes to the Task tool itself or Claude Code's model resolution internals |
| 231 | +- Modifying shell scripts to pass `--model` flags (scripts inherit the session model; only the banner is new behavior for scripts) |
| 232 | +- Auto-detection of router type (LiteLLM vs. CCR vs. opencode) -- the notice is generic |
| 233 | +- Changes to archived spec files under `.claude/specs/` |
| 234 | + |
| 235 | +## Assumptions |
| 236 | + |
| 237 | +1. Claude Code's Task tool accepts `model:` as a parameter that overrides the agent's frontmatter `model:` field. This is confirmed by the existing `commands/spec.md` agent-spawning pattern. |
| 238 | +2. Claude Code resolves tier alias strings (`opus`, `sonnet`, `haiku`) in agent frontmatter to the latest available model in that tier. This is the standard Claude Code plugin behavior. |
| 239 | +3. The `ANTHROPIC_BASE_URL` environment variable is the standard way users configure non-Anthropic backends. Other variables (like `OPENAI_BASE_URL`) are not relevant to this plugin's detection. |
| 240 | +4. Shell scripts inherit the session model from the `claude` CLI invocation and do not need to pass `--model` explicitly. The env-var override mechanism is only needed at the command/Task-tool level, not in scripts. |
| 241 | + |
| 242 | +## Detected Gaps (Informational) |
| 243 | + |
| 244 | +- `spec-scanner` agent: not registered in `plugin.json` or `CLAUDE.md` routing table (confidence: high) |
| 245 | +- `spec-debugger` agent: not registered in `plugin.json` (confidence: high) |
| 246 | +- `spec-complete` command: no docs page at `docs/commands/spec-complete.md` (confidence: high) |
0 commit comments