cmux-tui: move-tab-to-column takes the new column's pane id from the caller (tab-column-client-pane-v1)
Leo (2026-11-03): "it's so slow to open and close idk if there's some sort of threading issue but it's nigh instant for claude and codex so we nede to be at least as fast".
leo-named-fix. This is the daemon half. The app half follows in a second PR.
What
When a person opens a tab from a lone agent chat (Cmd-T, a New Tab pick, a folder), the chat docks left. Its pane keeps the new tab (ChatColumnPlacement.route .dockChat, which sends move-tab-to-column with dock and respawn). Until the daemon replies, the screen shows nothing new. To show the dock and the new tab's stand-in in the click's frame, the app needs the daemon's new column pane to replace its provisional one by id. split-client-keys-v1 already does this for split.
move-tab-to-column now takes an optional pane_id (pane_ and 32 lowercase hex digits), with or without respawn, behind the new capability tab-column-client-pane-v1:
- The new column's pane takes that public id.
- A malformed id is a bad request.
- An id that a live or deleted resource already has is refused with
pane_id_exists, and nothing moves. - Without
pane_id, nothing changes.
Spec: cmux-tui/spec/commands.md, sdk-schema.json and api-compat.surface.json. SDK bindings were regenerated (bindings/codegen/generate.py --write), and the Rust bindings test names pane_id as missing.
Tests
cmux-tui-core server::split_respawn_tests::a_column_move_takes_the_callers_pane_id covers three cases:
- the capability is advertised;
- a malformed id is refused and moves nothing;
- a keyed dock with respawn gives the column pane the minted id, and a second move with the same id is refused with
pane_id_exists.
Performance
| metric | before | after | delta | harness or run link |
|---|---|---|---|---|
| dock respawn, click to the dock showing | daemon round trip | unchanged in this PR | none | the app half measures it |
There's no user-visible change on its own: this is an additive request field behind a new capability.
Risk
risk:normal. Additive, opt-in field. Clients that don't send pane_id are unaffected.
Changelog
none
Agent session: agent session
🤖 Generated with Claude Code
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Adds an optional pane_id to move-tab-to-column so the daemon's new column pane carries a caller-minted public id, letting the app replace its provisional pane by id when a lone agent chat docks left on a new tab. This is the daemon half; the app half follows, so there's no user-visible change on its own.
Changes
- A malformed id is a bad request and moves nothing; an id a live or deleted resource has is refused with
pane_id_exists. - With
respawn, a used id is refused before the fresh tab is made, so a refusal consumes no terminal id the caller would retry with. - Without
pane_id, behavior is unchanged. - The new field sits behind the
tab-column-client-pane-v1capability, advertised by the daemon. - Spec, SDK schema, api-compat surface, and all language bindings regenerated; tests cover the capability advertisement, malformed ids, a keyed dock with respawn, and used-id refusal.