[#1018] Add Claude Opus 5 as a pinned selectable model#1019
Conversation
Append `claude-opus-5` to MODEL_OPTIONS.claude immediately after
claude-fable-5 and before the 4.x pins (newest pin first, never first),
so modelsForBackend("claude")[0] stays "opus" — the #931 default/heal
target. Pure data addition: buildAgentArgs already forwards any concrete
Claude slug as `--model <slug>`, and the PUT agent-models route stores
the value without an allowlist, so no logic changes.
Coverage: catalog membership, effectiveModel/sanitizeModel pin
preservation, deterministic placement, the #935 normalizeButler mirror
(Butler's only regression guard, since that surface is React-only), and
a launch case asserting `--model claude-opus-5` alongside the permission
and --mcp-config arguments.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: APPROVE
Epic Alignment: PASS
Standalone #1018 is aligned with its contract: one shared Claude-catalog row, opus remains the first concrete default/heal target, and saved valid models remain valid.
Checked (evidence)
- Structural gate: live PR body includes filled
## EPIC Alignmentand## Self-Verification; linked amended ticket #1018 has standalone## EPIC Contextand its deterministic placement/test contracts. - Catalog and placement:
src/lib/agentModels.ts:35-41inserts the pin immediately after Fable 5, before 4.x pins, preservingopusat:29. - Persistence and Butler regression:
server/agentModels.test.js:36,52,59-61,70,89covers catalog exposure, valid display/save, position/default, and Butler preservation. - Riskiest part: Claude launch arguments retain permission and MCP wiring;
server/agentArgs.gemini.test.js:91-99verifies the exact pin plus both arguments. - Kill-list: scanned all items — clean; 3 changed files (+31/-0), no runtime logic change or scope creep.
- CI:
gh pr checks 1019→test pass 1m7s(live).
Findings
- None.
Decision
The live diff fully implements #1018 without altering the default alias, other catalogs, or launch logic. Approval applies to ef8715c2b22793ff6af28965e62c6a97ed4618f8.
|
@re2 APPROVE at 3 files, +31/−0, base @dev asked me to check the no-silent-migration reasoning independently rather than take it on trust. I did — empirically, not just by reading The reasoning holds and is stronger than stated: On Butler: agreed that Checked (evidence)Placement + ordering (the #931 invariant). Ran Launch path. Both selection surfaces are catalog-driven, so no UI work was needed or done. Tests at this SHA, in a clean worktree: All four ticket-phase nits are present: deterministic placement (pinned by an explicit assertion block, No concerns. Head unmoved at |
Closes #1018.
Adds
claude-opus-5to the shared Claude model catalog as an explicit pin, so operators who need a reproducible version can select it instead of relying on the movingopusalias. Pure data addition + tests — no logic, spawn, or UI changes.EPIC Alignment
MODEL_OPTIONS.claudeand its persistence/launch regression coverage.MODEL_OPTIONS.clauderemains the single catalog;opusremains the first concrete Claude option (Settings: agent Model dropdown hardcoded to Claude models — not provider-aware (shows 'sonnet' for Codex/Gemini agents) #931 default/heal target); valid saved model values survive normalization and launch unchanged.Changes (3 files, +31/−0)
src/lib/agentModels.ts— one row,{ value: "claude-opus-5", label: "claude-opus-5" }, placed immediately afterclaude-fable-5and before the 4.x pins per the ticket's deterministic-placement requirement (newest pin first, never first).server/agentModels.test.js— catalog membership;effectiveModel/sanitizeModelpin preservation; a placement block pinning the position and thatopusstays index 0; and anormalizeButler({command:"claude", model:"claude-opus-5"})regression.server/agentArgs.gemini.test.js— aclaude_opus5_agentfixture asserting--model claude-opus-5plus retention of--dangerously-skip-permissionsand--mcp-config <path>.No production logic changed:
buildAgentArgs()'s Claude branch already forwards any non-empty slug as--model <slug>, andPUT /api/project/:projectId/agent-models/:agentIdstoresmodelas a trimmed string with no allowlist (onlyreasoning_effortis validated). Both selection surfaces are catalog-driven —AgentModelsWidget.tsxviaoptionsForBackend,SettingsPage.tsxviamodelsForBackend— so the dashboard modal, the per-agent Settings dropdown, and Butler all pick the row up with no UI work.Self-Verification
npm test→ 64 passed, 0 failed, 2 skipped (the two skips are the pre-existing Jest-style files, out of Unref routes.js module-load pollers + add cross-platform 'npm test' (fix full-suite hang) #836 scope).npm run build→ succeeds (TypeScript clean, 9/9 static pages generated).node server/agentModels.test.js→ 35 passed / 0 failed;node server/agentArgs.gemini.test.js→ 12 passed / 0 failed.optionsForBackend("claude").sanitizeModelonly rewrites values absent from the catalog, so adding a row strictly widens the accepted set and no saved model is rewritten by loading or saving unrelated settings.--model claude-opus-5with permission + MCP args intact.opus (latest)still present and still first concrete option — asserted (and the pre-existing guard atserver/agentModels.test.jsremains).normalizeButlermirror.main@caf94e2(the ticket's corrected baseline).Review notes
Reviewed as a ticket first: @re1, @re2, and @dev all approved #1018's spec at
caf94e2, and @Head amended the ticket with the four review nits (placement, corrected baseline, thenormalizeButlercase, the permission/MCP assertion) — all four are implemented above. Butler deserves a second look: its surface is React-only, so thenormalizeButlermirror inserver/agentModels.test.jsis the sole regression guard for that acceptance criterion.🤖 Generated with Claude Code