Model menu: harness rail beside Claude Code's list, with Account
Stacked on #21853 (the compact model menu with Account). Until that lands, this diff also shows its commits. The last two commits are this PR's.
Summary
Leo's direction (2026-10-18): the model picker should look like Claude Code's, keep the harness/model-family rail on the left, and carry an account picker. No warning message.
- Rail: a column of round icon tabs on the left of the compact menu. Starred comes first (only once a model is starred), then Claude, Codex and every other harness that can start here. A tab shows that harness's models in place and keeps the menu open. A signed-out harness's tab says "Signed out" in place of models.
- List, in Claude Code's style: the tab's top models, numbered 1–9 on the right, with a check on the running model. Then a divider, then:
- Effort (its value, then ›): the model's levels and fast mode.
- More models ›: a submenu of the harness's other models, ending in Add harness….
- Account (its value, then ›): the chat's acpmux routes, as in #21853.
- Effort and Account belong to the chat, so they show only on the chat's own harness's tab.
- Type to filter: typing filters every harness's models in place, with no search field. Each match names its harness in secondary text, and the header shows the typed text. 1–9 pick a match, and Backspace removes the last letter.
- No warning: no "Higher effort means…" header and no ⚠ usage badge.
- Cross-harness picks: picking a model of another harness starts a chat there, the same way the full picker does (
onCombo, elseonHarness). - Full picker: it is still on Cmd-Ctrl-M and the Debug Settings
agent.modelMenu= Full choice, which is where models get starred.
Testing
test/model-menu-compact.test.tsx(JSDOM, the real composer and catalog): new tests for the rail and its Codex tab, Starred only when starred, More models as a submenu ending in Add harness…, and type-to-filter with no search field. They were committed red before the change (4 failed), and all 12 pass now.- The 16 test files that touch the pickers or
ui/Menu: 69 pass, 2 skip (browser lane). vp check(format, lint, types), check-layers, check-type-scale, pane-english, ui-rules and gallery coverage are clean.- Gallery:
agent-pane.model-pickergainsquick-menu-railandquick-menu-filter, so the gallery job screenshots them.
Changelog
Changed: The model menu has a harness rail on its left, Claude Code style rows (numbered models, Effort, More models, Account), and filters as you type
🤖 Generated with Claude Code
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Switches the model picker to a Claude Code style compact menu: a harness rail on the left, numbered models 1–9, and Effort, More models, and Account rows beneath. The model chip is now a quiet model-and-effort label, and the separate effort chip is removed.
- The model, effort, and access chips rest as plain text and gain a small rounded background only under the pointer, on keyboard focus, or while their menu is open; the rail's tabs are circles, not capsules.
- Effort and Account show only on the chat's own harness tab; other tabs show that harness's models, or "Signed out" with a Log In row in their place.
- Account lists the acpmux routes serving the chat and switches the chat's route, restarting the harness and resuming the same session; a refused switch is named on the row, a client-less one reports failure, and a late answer from another chat is ignored.
- Typing filters every harness's models in place, with no search field; picking another harness's model starts a chat there, like the full picker does.
- The rail and filter survive streaming re-renders, resetting only when the menu opens, and keyboard focus on a filtered row sticks across them; Up and Down stay in the list, Left and Right move along the rail. Focus returns to the first row only when the filter changes or the focused row is gone.
- Filtered rows show no number keys: digits narrow the filter, Enter picks the highlighted match, and 1–9 pick a model only when nothing is typed.
- The full picker remains on Cmd-Ctrl-M, which also opens it over an open compact menu; the new Debug Settings choice
agent.modelMenu(compact by default, full for the old picker) rides the composer event pane-side.