cmux NEXT composer: Claude Code's split (+, prompt, mic, Send in the box; mode, model, effort and context ring in a quiet row under it)

Merged
TE
16d ago
+987-200

Leo (2026-10-19): "just follow how Claude Code does these." This follows #22216 and lays out the chat composer and the New Tab composer the way Claude Code does. Both use one layout component, ComposerFoot.tsx, so neither is a fork.

Layout (Claude Code's split)

  • Inside the box: +, the prompt, Stop, the mic and Send. New Tab has no + yet. It takes pastes and drops (#22231), and a + button for it is a follow-up.
  • Under the box, a quiet row:
    • the permission mode as plain text on the left;
    • the model ("Opus 5.5", primary ink) and effort ("Medium", secondary ink) on the right;
    • then the fast bolt and the context ring.
  • Full access shows its shield in the model chip's color, per Leo's quiet permission chip (2026-10-18, #21744). The shield's "!" names the risk, and the menu keeps the warning color where the mode is chosen (quiet-access-chip).
  • New Tab dots. Leo: "put the claude code style composer on the first dot in the new tab page and put the existing composer on the second one". Cards, the first dot and the page an unset template shows, draws the split: the project strip heads the card, the box holds the prompt, the mic and Send, and the quiet row sits under it. Default, the second dot, keeps the existing composer with its chips in the box. Composer, Threads and Console draw the split too. With the plain footer off, Cards' pill and toolbar come back. Nothing hides the mic in Search.
  • On New Tab the quiet row sits under the box, inside .nt-composer, so #22119 can arrange the page around the composer without touching its internals. While the split draws, the suggestions anchor under the whole composer, so they never cover the quiet row's chips (greptile P1).
  • This builds on the plain footer (composerSettings.ts plainFooter, on by default). With the plain footer turned off, the old single row comes back unchanged.

Spacing (measured against Claude Code at 1x)

Claude Codehere
quiet row under the box~4 px4 px (margin-top)
quiet row height28 px28 px
mode text from the box's left edge16 px16 px (12 px padding + the chip's 4 px hover inset), on the prompt's text edge
model chip to effort chip~8 px between labelsthe chips touch; each has a 4 px inset, so 8 px between pills (the model's chevron sits between the labels)
last control from the box's right edge~12 px12 px
box row (+, mic, Send)48 px48 px min-height, with the prompt above it unchanged

Each control's states

These states hold in both composers.

  • + (chat): icon only, with the shared "Add" tooltip.
    • Rest: glyph only.
    • Hover: soft pill.
    • Pressed: scales to 0.975 at 0.96 opacity, then springs back.
    • Open: keeps the pill.
    • Keyboard focus: pill plus the bar's outline at offset 0.
  • Mic: never hidden. No width breakpoint removes it; the prompt shrinks instead (composerRowFit.ts no longer has a mic step). Rest, hover, pressed and focus work like +. While listening it shows its pressed state.
  • Send / Stop: follow the theme's ink (--agent-text fill on the surface color), never system or iMessage blue. Off, ready, stop, rest and hover are all covered by no-system-blue.test.ts.
  • Permission mode (quiet row, left): plain text at rest, with no pill. Hover gives a soft pill, and the pill stays while the menu is open. Keyboard focus adds the outline. Press works like +. Full access shows its shield in the chip's own color.
  • Mode menu rows: each row has its shield, its name and description, and a trailing column. The trailing column holds the row's number, or the check on the chosen row, which replaces the number (Claude Code's layout).
  • Model and effort (quiet row, right): labels at rest, the model in primary ink and effort in secondary. Hover, open, press and focus work like the mode.
  • Fast bolt: same states as the mode. It leaves at the 370 px step, as before.
  • Context ring (back, in this row): it holds its place from the first frame. Before the chat reports usage it stays inert, so the first report moves nothing (hq#1957's still-composer rule; composer-turn-cycle holds the boxes). It follows showContextUsage. Hover and open give the soft pill; keyboard focus gives the outline at offset 0. The New Tab page has no chat yet, so it shows no ring.
  • + menu and @ file picker rows: the row under the pointer lights, one at a time, in sync with the keyboard highlight.

Tests (Chromium + WebKit on the gallery stage, Huge Blue)

  • test/composer-claude-split.test.ts (new) checks:
    • the box holds no chips;
    • the quiet row sits under the box, with the mode on the 16 px edge, model and effort on the right touching each other, the row ending 12 px from the box's right edge, and the ring after effort;
    • the mic stays at 760 and 300 px;
      • is glyph-only with the "Add" tooltip;
    • the mode menu's check sits at the trailing edge in place of the number;
    • the + menu and @ rows highlight one at a time on hover.
  • test/no-system-blue.test.ts adds Send in every state in both rows.
  • Updated for the split: composer-row-rhythm (each row keeps its own rhythm), composer-footer-plain (Tab reaches the model from the quiet row), composer-caret-focus (the New Tab row is now the quiet row), composer-row-fit and composer-row-steps (the mic never leaves; steps are measured across both rows).

Huge Blue results at the head are posted in a comment below.

Gallery

agent-pane.new-tab adds composer-mic (stage width) and composer-mic-narrow (page squeezed to 300 px), and each fails if the mic or Send leaves the box. #22216's composer-* state variants on both entries now show the split.

šŸ¤– Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Implements Claude Code's composer split in the chat and New Tab composers: the box keeps +, the prompt, the mic and Send or Stop, while the permission mode, model, effort, speed bolt and context ring sit in a quiet row under it. Both composers draw that row from one shared ComposerFoot component behind the plainFooter look, which stays the default; toggling it off returns the previous single row.

Layout

  • The mic never leaves at any width; the prompt shrinks instead.
  • The speed bolt moves with the chips into the quiet row, before the context ring.
  • The context ring holds its place from the first frame, drawing only its track until the chat reports usage, so the first report moves nothing.
  • The mode menu's check sits at the trailing edge in the chosen row's number's place.
  • Send and Stop use the theme's ink, never system or iMessage blue.
  • On New Tab, Default keeps its chips in the box; Cards draws the split without a + (which lands with attachment staging, #22231) and no create row.
  • Suggestions open under the whole composer so they never cover the quiet row's chips; the full-access shield takes the model chip's color.
  • The quiet row makes the composer 32 px taller. In a short pane the composer form packs its queue, box and quiet row at the bottom, so what doesn't fit spills upward over the transcript and Stop keeps Send's place.

Tests

  • composer-claude-split.test.ts covers the split layout, persistent mic, + tooltip, mode menu check and hover highlighting in Chromium and WebKit.
  • Rhythm, fit, steps, caret-focus, location-strip, turn-cycle, scroll, menu-over-suggestions and fast-toggle tests were updated for the two rows; Tab from the prompt reaches the model in the quiet row.
  • no-system-blue.test.ts covers Send in every state on both composers, and narrow-layouts keeps the single-row case measured with the plain footer off.