cmux NEXT model picker: every harness its own tab again, Claude Code full model ids (carries #27692) + failed-probe launch tabs
Carries austinywang's #27692 (his three commits, with his authorship) plus the fix its exact-head review asked for. #27692 stays his to close; this lands it without waiting, since it fixes a regression Leo reported.
Leo, 2026-10-30: "honestly we had a pretty good thing going with teh symbols of the harneses at the top :("
Commits
dd777ca95dd,be3e7a42342,ba7e7f57eb3: Austin Wang's #27692, cherry-picked unchanged onto the feat-cmux-next tipb69f04615cd. All three applied cleanly.724707fbf3d: fix: a launch entry whose probe failed keeps its launch tab. The Codex review of #27692 ata327a7cbde3eblocked on this (posted as #27692 issuecomment-6516293952).hasModelschecked only each row's owndisabled, and the harness-levelHarnessChoice.unavailable(its probe failed) was dropped when the rail rows were built. So a launch entry whose probe failed, but whose catalog still listed models, became an ordinary tab that could start a stale model. That contradicts #27692's own body: "An entry with no pickable models (none listed, or its probe failed) still launches from its tab". TheQuickFamilynow carriesunavailable,hasModelsis false for it, and a jsdom test ("a new chat still launches a named harness entry whose probe failed from its tab") covers it.
Evidence
- Picker suites at the head
276eb52(started-chat fork, compact, providers, layout, round rail, search, short list): 111 pass, 0 fail (https://github.com/manaflow-ai/cmux/actions/runs/41013941518). - Red/green for the fix at the same head (https://github.com/manaflow-ai/cmux/actions/runs/41014360351): the new test passes as pushed. It fails once only the fix's guard (
!family.unavailableinhasModels) is removed: the failed-probe entry's tab no longer launches it.
Captures
Gallery state agent-pane.model-picker/quick-menu-many-profiles (step 1, the picker open on Claude Code), rendered at device scale 2 by the gallery workflow at the merge base (before) and at the head (after): the Claude (work) launch entry gets its own harness tab with its mark again instead of a row under Claude Code's models.
| Light | Dark | |
|---|---|---|
| Before | ![]() | ![]() |
| After | ![]() | ![]() |
Viewed after image: yes
Visual verdict: Each harness sits in the left rail as its own tab with its mark, and the menu fits on screen without repeating a control per row, so it holds up next to ChatGPT or Claude.
Takes back #26969: on purpose; Leo asked for every harness to have its own tab again ("we had a pretty good thing going with teh symbols of the harneses at the top"), so this reverts its folding of harnesses into one tab.
The gallery workflow captures the picker's harness tabs before and after, for each state on this line:
Gallery: agent-pane.model-picker/quick-menu-many-profiles, agent-pane.model-picker/started-chat-fork, agent-pane.model-picker/started-chat-quick-menu, agent-pane.model-picker/quick-menu-rail
#27692's description
Summary
The model picker in cmux NEXT nightly (1.0.0-nightly.4093446036501, built from 6c1a5ab) regressed. This PR fixes two problems.
1. Custom harnesses lost their tab and their models. https://github.com/manaflow-ai/cmux/pull/26969 (merged 2026-10-29, 7f7d931) folded every harness that draws the Claude or Codex mark into one rail tab (canonicalHarnesses). A harness like claude-sr2, which is its own profile with icon = "claude", disappeared from the rail. It became a launch-only row inside Claude Code's tab and showed no models. Claude Code (acp), Claude Code (sr), Codex (work) and the other launch configurations went the same way.
This PR reverts https://github.com/manaflow-ai/cmux/pull/26969: the webview side is equivalent to git revert 7f7d9315343c (its two conflicts are context from later commits). It removes canonicalHarnesses, the variants block and the canonical-harnesses-* gallery states, and restores test/model-menu-started-chat-fork.test.tsx to its pre-#26969 version. The density (https://github.com/manaflow-ai/cmux/pull/27320), search grouping (https://github.com/manaflow-ai/cmux/pull/27303), Provider row (https://github.com/manaflow-ai/cmux/pull/27151), checkmark (https://github.com/manaflow-ai/cmux/pull/27232) and empty-search (https://github.com/manaflow-ai/cmux/pull/26962) fixes stay as they are.
The revert alone still left a launch configuration that is not the running harness (claude-sr2 in a Claude Code chat, Claude (work), Codex (work)) as a launch-only tab with no models, as before #26969. Now, when its own catalog entry has a model that can be picked, it is an ordinary tab that lists those models; picking one starts the chat on that harness, as picking a Codex model does. An entry with no pickable models (none listed, or its probe failed) still launches from its tab. In a started chat every other tab still forks; a launch configuration with models now shows "Fork to …" on its tab like any harness, instead of forking on the tab click.
2. GUI chats failed with "There's an issue with the selected model (opus-5-5)". A chat started with a versioned family name (opus-5-5) failed every turn, while the header still read "Claude Code · Opus 5.5". Claude Code accepts opus or claude-opus-5-5, but it sends opus-5-5 to the API exactly as typed. The session's own log shows [claude-code:unrecognized_model] {"model":"opus-5-5"} followed by a 404 model_not_found. The Claude stdio translator (claude_stdio::model_id) now passes Claude Code the full id at spawn (--model), on session/set_model and on the model config option. It does this only for opus-/sonnet-/haiku- followed by a digit. Aliases, full ids and other providers' names pass through unchanged. This applies the rule live_models::claude::launch_id already uses.
Testing
Remote runs only (rbx; this Mac had no agent-identity for cmux-ci and no Freestyle key):
- webviews (bun 1.4.4 on rbx, lane
picker-restore-27692-web, tree of c329f8d7a4):bun test test/model-menu-started-chat-fork.test.tsx test/model-menu-compact.test.tsx test/model-menu-providers.test.tsx test/signed-out-rail.test.tsx test/composer-footer-harness.test.ts: 82 pass, 1 skip (browser lane), 0 fail. New tests: claude-sr2 keeps its tab and lists its models, mounted onclaude-sr2and onclaude(picking its model startsclaude-sr2); a named entry with models starts from one of them; one with no models still launches from its tab; a second launch entry of one family lists its own models and starts itself. - Rust (rbx, lane
picker-restore-27692, 51f9cccd6a):cargo test --locked -p acpmux --lib claude_stdio::tests: 19/19, includingversioned_family_names_reach_claude_code_as_full_ids. Later commits touch only webviews. vp fmt --checkover webviews: clean.
Changelog
- Fixed: the model picker shows every harness, including custom ones such as claude-sr2, as its own tab with its models again.
- Fixed: a chat started with a model like
opus-5-5no longer fails every turn with "There's an issue with the selected model".
🤖 Generated with Claude Code
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes two model-picker regressions in the cmux NEXT nightly: every harness is back to its own rail tab, and versioned model names no longer fail every chat turn.
- Each harness and launch configuration gets its own tab. A launch configuration (like
claude-sr2,Claude (work),Codex (work)) whose catalog entry lists pickable models shows them on its tab, and picking one starts the chat on that harness; one with no models still launches directly from its tab. A harness whose probe failed keeps its launch tab and never shows its stale rows, in the tab, in Starred, or in search, unless the chat runs on it. Removes thecanonicalHarnessesfolding and the variants submenu; the density, search, provider, checkmark, and empty-search fixes from later PRs stay intact. - The Claude stdio translator now hands Claude Code full model ids (
claude-opus-5-5) at spawn, onsession/set_model, and on the model config option. Bare aliases (opus), full ids, and other providers' names pass through unchanged.
Agent session: agent session
🤖 Generated with Claude Code



