Repository navigation
carry of #28175: cmux: add first-class space CLI commands - #28722
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-68ba07270dde07b96ff4
cmux space rename --name Office and the other flag forms must keep the generic catalog route instead of targeting a space named after the flag; options after a positional form must reach the action. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-68ba07270dde07b96ff4
…ds (green) cmux space rename --name Office targeted a space named --name. The positional forms now match only the words before the first option, as the generic <noun> <verb> route reads them, and pass the options after them to the action. The space forms move to cli/app/space.rs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-68ba07270dde07b96ff4
tab.moveToSpace pinned the tab's whole workspace to the space, taking every sibling tab along. A tab alone in its workspace still takes the workspace (a pin, as Move Workspace to Space does); a tab with siblings moves into a new workspace (TabMoves.toNewWorkspace, the path Move Tab to New Workspace uses) that is pinned to the space. Home's own tab is refused as for Move Tab to New Workspace, and a workspace already pinned to the space is refused as Move Workspace to Space refuses it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-68ba07270dde07b96ff4
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-68ba07270dde07b96ff4
tab.moveToSpace had neither a tab-menu placement nor an exemption, so the surface parity check had no decision for it. The tab menu's Move folder keeps Move Tab to Workspace…; this one is palette, CLI and MCP only (pointerMenuTrim). action-surfaces.json, actions.md counts and the web next-docs references (bun web/scripts/export-next-docs.ts) list it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-68ba07270dde07b96ff4
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-68ba07270dde07b96ff4
… the daemon Home's own tab is refused whether or not it is alone (a lone Home tab could pin Home into another space). The action changes nothing locally before the pin answers, so it is a .waiting(.daemonEcho) effect, not .applied. The flag-form tests use real catalog names (space delete, space switch). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-68ba07270dde07b96ff4
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-68ba07270dde07b96ff4
|
Review (codex gpt-6-astra high fast, direct codex exec): SHIP at e8d51c7 Three rounds, all against merge base fc2a87b:
Non-blocking: if the pin fails after a tab with siblings has moved, the new workspace stays unpinned (the failure is reported). |
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Not verified: macOS jobs did not run: compile and app tests were skipped on CI passes on Written by web and size checks: green Default changesThis pull request changes 2 defaults at
Needs a review. It passes with an independent review receipt on this commit: a comment or review whose first line is Merge receipt: merged as Regenerate the snapshot with Shipped in:
|
|
Found 10 test failures on Blacksmith runners: Failures
|
run_action leaves args out when an action takes none, so space switch's
expected {} never matched (the original #28175 test was red at its head for
this). Both space tests now read a missing args as {}.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-68ba07270dde07b96ff4
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
Review (codex gpt-6-astra high fast, direct codex exec): SHIP at 32b3929 Round 4, a delta review of 32b3929 (test-only). Rust (cmux-ci on this PR at 32b3929, run 41161031549):
Reds at this head, compared with base by test name:
|
|
One more base red appeared after the body edit re-ran checks: |
There was a problem hiding this comment.
4 issues found across 19 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="cmux-tui/crates/cmux-tui/src/cli.rs">
<violation number="1" location="cmux-tui/crates/cmux-tui/src/cli.rs:147">
P2: Adding `space` to the cross-platform public scopes leaves non-Unix `cmux-tui space --help` on the generic root-help fallback. Add a `"space" => Cow::Borrowed(scope_help::SPACE_HELP)` arm to `scope_help_for` so the newly advertised scope has consistent help on every target.</violation>
</file>
<file name="Packages/macOS/CmuxNext/Sources/CmuxNextApp/Handlers/TabHandlers+More.swift">
<violation number="1" location="Packages/macOS/CmuxNext/Sources/CmuxNextApp/Handlers/TabHandlers+More.swift:76">
P2: When the source workspace has siblings, this action commits the tab move before pinning the new workspace. If `pinWorkspace` fails, the action reports an error but leaves the tab stranded in an unpinned workspace instead of preserving the requested move-to-space outcome; add rollback or make the move and pin failure-safe.</violation>
</file>
<file name="Packages/macOS/CmuxNext/Sources/CmuxNextActions/LayoutActions.xcstrings">
<violation number="1" location="Packages/macOS/CmuxNext/Sources/CmuxNextActions/LayoutActions.xcstrings:11987">
P2: This new “Space” action reuses the existing “Workspace” translations in every locale except English and Japanese, so localized users will see the wrong destination concept. Add translations matching the app’s existing `Space` terminology, such as those used by `action.browser.link.openInNewSpace`.</violation>
</file>
<file name="cmux-tui/crates/cmux-tui/src/cli/app/space.rs">
<violation number="1" location="cmux-tui/crates/cmux-tui/src/cli/app/space.rs:20">
P2: `cmux space new --name Office` falls through to the nonexistent generic `space new` action, so the flag form cannot create a named space. Add a no-positional `new` arm that routes to `space.new` and lets its optional `name` argument pass through.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
| "attention", | ||
| "agent", | ||
| "room", | ||
| "space", |
There was a problem hiding this comment.
P2: Adding space to the cross-platform public scopes leaves non-Unix cmux-tui space --help on the generic root-help fallback. Add a "space" => Cow::Borrowed(scope_help::SPACE_HELP) arm to scope_help_for so the newly advertised scope has consistent help on every target.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At cmux-tui/crates/cmux-tui/src/cli.rs, line 147:
<comment>Adding `space` to the cross-platform public scopes leaves non-Unix `cmux-tui space --help` on the generic root-help fallback. Add a `"space" => Cow::Borrowed(scope_help::SPACE_HELP)` arm to `scope_help_for` so the newly advertised scope has consistent help on every target.</comment>
<file context>
@@ -144,6 +144,7 @@ const PUBLIC_SCOPES: &[&str] = &[
"attention",
"agent",
"room",
+ "space",
"closed",
"git",
</file context>
| // action-wait-allow: a space pin has no store intent (Move Workspace to Space sends it the same way), so nothing local stands in. | ||
| return .waiting(.daemonEcho) { | ||
| var key: WorkspaceKey? = WorkspaceKey(rawValue: qualified.key) | ||
| if !alone { key = await TabMoves.toNewWorkspace(tab, services: services) } |
There was a problem hiding this comment.
P2: When the source workspace has siblings, this action commits the tab move before pinning the new workspace. If pinWorkspace fails, the action reports an error but leaves the tab stranded in an unpinned workspace instead of preserving the requested move-to-space outcome; add rollback or make the move and pin failure-safe.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At Packages/macOS/CmuxNext/Sources/CmuxNextApp/Handlers/TabHandlers+More.swift, line 76:
<comment>When the source workspace has siblings, this action commits the tab move before pinning the new workspace. If `pinWorkspace` fails, the action reports an error but leaves the tab stranded in an unpinned workspace instead of preserving the requested move-to-space outcome; add rollback or make the move and pin failure-safe.</comment>
<file context>
@@ -51,10 +51,34 @@ extension TabHandlers {
+ // action-wait-allow: a space pin has no store intent (Move Workspace to Space sends it the same way), so nothing local stands in.
+ return .waiting(.daemonEcho) {
+ var key: WorkspaceKey? = WorkspaceKey(rawValue: qualified.key)
+ if !alone { key = await TabMoves.toNewWorkspace(tab, services: services) }
+ guard let key else { return "move-tab-to-new-workspace failed (see the app log)" }
+ return await home.failure("pin-workspace") { try await $0.pinWorkspace(session: session, key: key, to: room) }
</file context>
| "ar": { | ||
| "stringUnit": { | ||
| "state": "needs_review", | ||
| "value": "نقل علامة التبويب إلى مساحة عمل…" |
There was a problem hiding this comment.
P2: This new “Space” action reuses the existing “Workspace” translations in every locale except English and Japanese, so localized users will see the wrong destination concept. Add translations matching the app’s existing Space terminology, such as those used by action.browser.link.openInNewSpace.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At Packages/macOS/CmuxNext/Sources/CmuxNextActions/LayoutActions.xcstrings, line 11987:
<comment>This new “Space” action reuses the existing “Workspace” translations in every locale except English and Japanese, so localized users will see the wrong destination concept. Add translations matching the app’s existing `Space` terminology, such as those used by `action.browser.link.openInNewSpace`.</comment>
<file context>
@@ -11965,7 +11965,138 @@
+ "ar": {
+ "stringUnit": {
+ "state": "needs_review",
+ "value": "نقل علامة التبويب إلى مساحة عمل…"
+ }
+ },
</file context>
| let words = words.iter().map(String::as_str).collect::<Vec<_>>(); | ||
| let room = |name: &str| format!("room:{name}"); | ||
| let (action, mut args, route) = match words.as_slice() { | ||
| ["new", name] => ("space.new", vec!["--name".into(), (*name).into()], ActionName::Any), |
There was a problem hiding this comment.
P2: cmux space new --name Office falls through to the nonexistent generic space new action, so the flag form cannot create a named space. Add a no-positional new arm that routes to space.new and lets its optional name argument pass through.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At cmux-tui/crates/cmux-tui/src/cli/app/space.rs, line 20:
<comment>`cmux space new --name Office` falls through to the nonexistent generic `space new` action, so the flag form cannot create a named space. Add a no-positional `new` arm that routes to `space.new` and lets its optional `name` argument pass through.</comment>
<file context>
@@ -0,0 +1,50 @@
+ let words = words.iter().map(String::as_str).collect::<Vec<_>>();
+ let room = |name: &str| format!("room:{name}");
+ let (action, mut args, route) = match words.as_slice() {
+ ["new", name] => ("space.new", vec!["--name".into(), (*name).into()], ActionName::Any),
+ ["switch", name] => ("space switch", vec!["--target".into(), room(name)], ActionName::Cli),
+ ["rename", old, new] => (
</file context>
actions.md counts: base's 1311 plus this PR's tab.moveToSpace. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-fc739fd2f4e557ae7189
…omMembership.pinned Base keys RoomMembership.pins by session then key now; pins[qualified] no longer compiles (review BLOCK at 7d3f53a). Same read as Move Workspace to Space. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-fc739fd2f4e557ae7189
|
Review (codex, router-review): SHIP at 27ce64c Reviewer: codex gpt-6.1-sol xhigh, fast tier. Follow-ups: 2. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward. SHIP at 27ce64c Visual verdict: no images; Leo tries the build
Follow-ups:
|
|
Review (codex gpt-6-astra high, router-review): BLOCK at 7d3f53a BLOCK at 7d3f53a Visual verdict: no images; Leo tries the build
Static review completed; Rust and Swift toolchains were unavailable in the box. |
Generated next-docs counts: base's regenerated counts plus tab.moveToSpace. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-fc739fd2f4e557ae7189
|
Review (codex, router-review): SHIP at b8d0db6 Reviewer: codex gpt-6.1-sol xhigh, fast tier. Follow-ups: 1. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward. SHIP at b8d0db6 Visual verdict: no images; Leo tries the build
Export consistency checks passed. Rust and Swift tests could not run because their toolchains are absent. Follow-ups:
|
Picks up the trusted glaeda runner hook (#30154) the signing guard test reads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-fc739fd2f4e557ae7189
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Carry of #28175 (its owner's session is gone). It keeps that PR's six commits with their authorship, merges feat-cmux-next in, and fixes the two findings of the review that blocked it at edcac1e.
Leo, 2026-10-30, as quoted on #28175: "oh also spaces warrant good commnds too" / "good intuitive stuff".
Summary
What #28175 adds: first-class
cmux spaceverbs.cmux space listreads the daemon's room listing.cmux space new <name>,switch <name>,rename <old> <new>,close <name>,move workspace <workspace> <space>andmove tab <tab> <space>run the app's catalog actions. The CLI and MCP go through the same registry.tab.moveToSpace(cmux tab move-to-space, palette and MCPapp_tab_move_to_space) is the tab twin of Move Workspace to Space.cmux space --helpand the root help list the scope (English and Japanese).Fixed in this carry:
Packages/macOS/CmuxNext/Sources/CmuxNextApp/Handlers/TabHandlers+More.swift,moveToSpace, lines 63-79):TabMoves.toNewWorkspace, the path Move Tab to New Workspace uses. That new workspace is then pinned to the space, and the siblings stay where they were..waiting(.daemonEcho), since a space pin has no store intent.cmux space rename --name Officetargeted a space named--name. The positional forms now match only the words before the first option, the same way the generic<noun> <verb>route reads them. Options after the positional words reach the action. Flag forms fall through to the catalog route unchanged. The space forms moved tocmux-tui/crates/cmux-tui/src/cli/app/space.rs.tab.moveToSpacehad no tab-menu placement and no exemption. It is now exempt from the tab right-click menu aspointerMenuTrim: that menu's Move folder already has Move Tab to Workspace…, and a list of spaces there would bloat it. It stays in the palette, CLI and MCP.plans/cmux-next/action-surfaces.json; theplans/cmux-next/actions.mdcounts (1282 actions, palette 1229, CLI verbs 757, MCP 675, tab 106, pointerMenuTrim 15); andweb/data/next-docs/*.generated.json, written bybun web/scripts/export-next-docs.ts. The PR autofix regenerates the action exports on the fleet if anything differs.plans/cmux-next/arch-ratchet.json: oneapp_linesexception for this handler's lines. The handler needs App-only types (TabMoves,WindowProfiles,AppServices,AppActionContext), so it can't live in a package. The reviewer judged this justified.Testing
space_flags_are_not_positional_namesandspace_positional_forms_keep_trailing_optionsincmux-tui/crates/cmux-tui/src/cli/app/tests.rs. Commit 9c09857 adds them before the fix.cargo test -p cmux-tui cli::exits 0. With the P2 fix reverted,space_flags_are_not_positional_namesandspace_positional_forms_keep_trailing_optionsfail.space_mutations_use_the_catalog_actions_and_name_targetswas red at its own head:run_actionleaves outargswhen an action takes none. The tests now read a missingargsas{}.Observed / Not run
scripts/cmux-next/check-state-roots.shok;scripts/cmux-next/check-no-godfiles.sh --only rustok;prepush-gate.pypasses with the ratchet exception.cmux space move tabacross two spaces. Only the reviewer's read and the compile cover the Swift handler.Changelog
Added:
cmux space list|new|switch|rename|close|movecommands and a Move Tab to Space actionProof
No capture: CLI verbs and a palette/CLI-only action; no right-click menu or other native UI changes.
Supersedes #28175.
Agent session: agent session
🤖 Generated with Claude Code