Skip to content

Add cmux support to agent-cli dev#589

Merged
basnijholt merged 4 commits into
mainfrom
cmux-dev-support
Jun 10, 2026
Merged

Add cmux support to agent-cli dev#589
basnijholt merged 4 commits into
mainfrom
cmux-dev-support

Conversation

@basnijholt

@basnijholt basnijholt commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Summary

Adds cmux (Ghostty-based macOS terminal for AI coding agents, controlled via a Unix socket through its bundled CLI) as a supported terminal for agent-cli dev.

The repo↔cmux mapping: one workspace per repository name, one tab per worktree.

  • First launch for a repo: cmux workspace create --name <repo> --cwd <worktree> --command <agent-cmd> creates the workspace with the agent running in its first tab.
  • Subsequent launches: cmux new-surface --workspace <ref> opens a tab in the existing workspace (matched by title via cmux workspace list --json), rename-tab names it after the branch, and cmux send types cd <worktree> && <agent-cmd> plus Enter. New surfaces don't accept cwd/command flags, so typing into the shell is the supported route; the terminal buffers the input until the shell is ready (verified live).

Changes

  • New Cmux terminal adapter (agent_cli/dev/terminals/cmux.py), detected via the CMUX_WORKSPACE_ID/CMUX_SURFACE_ID env vars that cmux auto-sets in its terminals
  • Registered in the terminal registry after tmux/zellij, so multiplexers running inside a cmux tab still win detection
  • Detection-only, like other GUI terminals — no --multiplexer involvement
  • Success summary shows cmux Workspace: <repo>; the tmux Attach: hint is no longer printed for non-tmux handles
  • Tests with evidence-based docstrings (cmux CLI help contracts + live verification against cmux 0.64.14), docs table

Testing

  • pytest: 1411 passed, 4 skipped
  • pre-commit run --all-files: passes (jscpd fails locally on a clean tree due to a missing platform binary, unrelated)
  • Live-tested against a running cmux app: first dev new in a scratch repo created the repo-named workspace with a branch-named tab running Claude in the worktree; second dev new reused the workspace and added a second tab whose agent started in the second worktree's directory

cmux (https://cmux.dev) is a Ghostty-based macOS terminal organized as
workspaces with tabs, controlled via a Unix socket through its bundled CLI.

agent-cli dev maps repos to cmux workspaces: each repo gets a workspace
named after it (created on demand), and each worktree launch opens a new
tab inside that workspace, named after the branch, running the agent in
the worktree directory.

- New Cmux terminal adapter (detect via CMUX_WORKSPACE_ID/CMUX_SURFACE_ID)
- Auto-detected when running inside cmux; tmux/zellij still win as innermost
- --multiplexer cmux supported on dev new and dev agent (socket-based, works
  from any terminal)
- Success summary shows the cmux workspace; tmux attach hint no longer
  printed for non-tmux handles
- Tests document the cmux CLI evidence (help text + live verification
  against cmux 0.64.14)
@greptile-apps

greptile-apps Bot commented Jun 10, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds cmux (a Ghostty-based macOS terminal) as a supported terminal adapter for agent-cli dev. The design maps one cmux workspace per repository name and one tab per worktree launch, with full error recovery (e.g., closing idle tabs when send fails).

  • New Cmux terminal adapter in agent_cli/dev/terminals/cmux.py with workspace create/reuse logic, deterministic per-workspace colors, and robust error handling via a shared _run helper.
  • _launch_in_cmux added to launch.py (mirroring the existing _launch_in_tmux pattern); cmux detection registers after tmux/zellij so inner multiplexers win.
  • Summary output in cli.py is narrowed with explicit terminal_name guards so the tmux attach hint is not printed for non-tmux handles.

Confidence Score: 5/5

Safe to merge — the adapter is well-isolated, all three previously-raised blocking issues have been addressed, and the test suite passes with 1411 tests.

All previously-raised issues (silent send failure masking a dead tab, indistinguishable CLI failure from workspace-not-found, and workspace-name divergence in open_new_tab) are resolved in this iteration. Error recovery is explicit: failed send closes the idle surface and returns None. The workspace listing abort-on-nil guard prevents spurious create attempts. The open_new_tab path now calls get_main_repo_root matching _launch_in_cmux. No new defects found in the changed paths.

No files require special attention.

Important Files Changed

Filename Overview
agent_cli/dev/terminals/cmux.py New terminal adapter; workspace create/reuse logic, per-workspace color hashing, and proper cleanup when send fails. All previously-noted blocking issues have been addressed.
agent_cli/dev/launch.py Adds _launch_in_cmux following the same pattern as _launch_in_tmux; correctly short-circuits _launch_in_terminal before the generic open_new_tab path.
agent_cli/dev/cli.py Summary panel now guards session_name display with explicit terminal_name checks for tmux and cmux; the tmux attach hint is no longer shown for non-tmux handles.
agent_cli/dev/terminals/registry.py Cmux registered after Zellij, before GUI terminals — correct priority so tmux/zellij inside a cmux tab still win detection.
tests/dev/test_terminals.py Comprehensive tests covering detection, workspace create/reuse, color determinism, send-failure cleanup, and priority ordering; evidence-backed docstrings cite live verification.
tests/dev/test_launch.py New test verifies that launch_agent with a detected cmux terminal uses open_in_workspace with the repo-root name, confirming the workspace naming invariant through the launch path.
docs/commands/dev.md Documentation table updated to include cmux with its detection env var and behavior summary.

Sequence Diagram

sequenceDiagram
    participant LC as launch_agent()
    participant LT as _launch_in_terminal()
    participant LC2 as _launch_in_cmux()
    participant CX as Cmux adapter
    participant CLI as cmux CLI

    LC->>LT: "terminal.name == "cmux""
    LT->>LC2: path, agent, terminal, full_cmd, tab_name, repo_root
    LC2->>CX: "open_in_workspace(path, cmd, tab_name, workspace_name=repo_root.name)"
    CX->>CLI: workspace list --json
    CLI-->>CX: "{"workspaces": [...]}"

    alt workspace already exists
        CX->>CLI: new-surface --workspace workspace:N
        CLI-->>CX: OK surface:M pane:P workspace:N
        CX->>CLI: rename-tab --workspace workspace:N --surface surface:M --title tab_name
        CX->>CLI: "send --workspace workspace:N --surface surface:M -- "cd /path && cmd\n""
        alt send succeeds
            CLI-->>CX: OK surface:M workspace:N
            CX-->>LC2: "TerminalHandle(handle=surface:M, session_name=workspace_name)"
        else send fails
            CLI-->>CX: CalledProcessError
            CX->>CLI: close-surface --workspace workspace:N --surface surface:M
            CX-->>LC2: None
        end
    else workspace not found
        CX->>CLI: workspace create --name repo --cwd /path --command cmd
        CLI-->>CX: OK workspace:N
        CX->>CLI: workspace-action --action set-color --workspace workspace:N --color Color
        CX->>CLI: rename-tab --workspace workspace:N --title tab_name
        CX-->>LC2: "TerminalHandle(handle=workspace:N, session_name=workspace_name)"
    end

    LC2-->>LT: TerminalHandle or None
    LT-->>LC: (success, handle)
Loading

Reviews (4): Last reviewed commit: "Fix cmux tests on Windows by computing e..." | Re-trigger Greptile

Comment thread agent_cli/dev/terminals/cmux.py Outdated
Comment thread agent_cli/dev/terminals/cmux.py Outdated
Comment thread agent_cli/dev/terminals/cmux.py
cmux is a terminal, not a multiplexer: it is used when auto-detected
(via CMUX_WORKSPACE_ID/CMUX_SURFACE_ID), like other GUI terminals.
Review fixes:
- A failed `send` now closes the idle tab and reports failure instead of
  returning a handle for a tab where the agent never started
- A failed `workspace list` aborts immediately instead of falling through
  to a doomed (or duplicating) `workspace create`
- open_new_tab resolves the main repo root so the generic Terminal
  interface keeps the one-workspace-per-repo invariant for worktrees

New: workspaces get a deterministic color on creation (sha256 of the
workspace name mapped onto cmux's 16 named colors), so each repo always
gets the same color. Existing workspaces are left untouched.
Path('/some/path') stringifies with backslashes on Windows, so the
hardcoded POSIX argv strings did not match.
@basnijholt basnijholt merged commit 7f7afd3 into main Jun 10, 2026
12 checks passed
@basnijholt basnijholt deleted the cmux-dev-support branch June 10, 2026 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant