Skip to content

feat: add cmux and Ghostty terminal support for sessions#53

Merged
grimmerk merged 19 commits intodevelopfrom
feat/terminal-cmux-ghostty
Mar 19, 2026
Merged

feat: add cmux and Ghostty terminal support for sessions#53
grimmerk merged 19 commits intodevelopfrom
feat/terminal-cmux-ghostty

Conversation

@grimmerk
Copy link
Copy Markdown
Owner

@grimmerk grimmerk commented Mar 19, 2026

Summary

Add cmux and Ghostty terminal support for Claude Code session launch/switch, with auto-detection of which terminal each active session is running in.

Features

  • cmux: Full launch via cmux new-workspace --cwd --command + auto select-workspace + activate. Switch via parallel sidebar-state cwd matching + tree surface title fallback. Requires socket mode automation or allowAll.
  • Ghostty: Full AppleScript support — switch via working directory matching + focus, launch via new tab/new window with surface configuration (initial working directory + initial input). No external requirements.
  • Auto-detect terminal: Active sessions automatically detect which terminal they're running in (walks parent process tree). Switch uses detected terminal regardless of settings. Launch uses settings terminal.
  • Terminal badge: Active sessions show small uppercase badge (ITERM2, CMUX, GHOSTTY) next to message count.
  • Settings: Terminal App selector (iTerm2 / cmux / Ghostty). Open Mode (New Tab / New Window) shown for iTerm2 and Ghostty.

Auto-Detection

For active sessions, CodeV walks the parent process tree (ps -o comm= + ps -o ppid=) to find which terminal app the claude process is running in. This means:

  • Clicking an iTerm2 session switches to iTerm2 (even if settings say cmux)
  • Clicking a cmux session switches to cmux (even if settings say iTerm2)
  • Settings terminal only affects launching non-active sessions

cmux Implementation

Launch: cmux new-workspace --cwd <path> --command "claude --resume <id>" + select-workspace + activate

Switch (two-pass):

  1. Pass 1: Parallel sidebar-state queries for all workspaces (~0.5s for 33 workspaces). Match by cwd or focused_cwd.
  2. Pass 2: cmux tree --all to find surface titles matching project name. Handles 2nd-tab and renamed workspaces.

Socket requirement: automation or allowAll mode (tested: both work, default cmuxOnly does not)

Ghostty Implementation

Launch: AppleScript new tab/new window with surface configuration from {initial working directory, initial input}. Uses initial input instead of command parameter (which gets passed to exec directly, not shell).

Switch: AppleScript iterates all windows → tabs → terminals, matches working directory, calls focus.

Same-CWD Limitation (affects ALL terminals)

When multiple sessions share the same projectPath (e.g. two sessions in /Users/grimmer/git/codex-ff):

  • Detection: Only one gets the purple dot (the other's lsof cwd matches the same history.jsonl entry)
  • Switch: AppleScript/CLI working directory match finds the first terminal, not necessarily the correct one
  • Click non-active one: Opens a new window instead of switching (because it wasn't detected as active)

This affects iTerm2, Ghostty, and cmux equally. Root cause: cwd-based matching cannot distinguish multiple terminals with the same working directory. Would need per-terminal PID or tty matching — iTerm2 has tty via AppleScript but our detectActiveSessions deduplicates by cwd before tty matching.

cmux-Specific Limitations

Limitation Cause
AppleScript count windows returns 0 isAppleScriptEnabled always false — Ghostty fork lacks macos-applescript config key. Fix submitted: cmux PR 1826
AppleScript working directory returns empty TerminalPanel.directory never updated — should read panelDirectories. Fix submitted: cmux PR 1826
New workspace appears at bottom of sidebar cmux behavior
Requires socket mode change Default cmuxOnly blocks external processes

cmux PR We Submitted

cmux PR 1826 (fix: AppleScript count windows returns 0 + working directory returns empty):

  • Root cause 1: Ghostty fork missing macos-applescript config key → isAppleScriptEnabled always false
  • Root cause 2: ScriptTerminal.workingDirectory reads TerminalPanel.directory which is never updated → should read Workspace.panelDirectories
  • If merged, cmux can use AppleScript for switch (same code as Ghostty), eliminating need for CLI sidebar-state + tree approach
  • Remaining limitation: same-cwd matching (needs per-terminal PID/tty, not filed as feature request yet)

cmux Upstream Items to Watch

Item Title Impact
cmux PR 1826 fix: AppleScript count windows + working directory Our PR — enables AppleScript for cmux, unblocks per-terminal cwd matching
cmux PR 1287 feat: add cwd to surface list API Per-surface cwd in CLI — alternative to AppleScript for 2nd-tab matching
cmux issue 1472 Background workspaces have dead PTYs May explain --command delay
(not filed yet) Per-terminal PID or tty in AppleScript/API Would fix same-cwd mismatch across all terminals

Terminal Support Matrix

Terminal Detect Switch Launch Open Mode Requirement
iTerm2 ✅ ps + lsof + tty AppleScript tty focus AppleScript new tab/window Tab / Window None
Ghostty ✅ ps + parent tree AppleScript cwd focus AppleScript new tab/window + surface config Tab / Window None
cmux ✅ ps + lsof sidebar-state cwd → tree fallback new-workspace --cwd --command Socket: automation/allowAll

Related Issues

Design Doc

See docs/claude-session-integration-design.md for full research details.

🤖 On behalf of @grimmerk — generated with Claude Code

grimmerk and others added 19 commits March 19, 2026 21:44
cmux: full CLI support (new-workspace --cwd --command, select-
workspace, focus-panel, send), but requires socket mode change
from default cmuxOnly to automation/allowAll.

Ghostty: macOS limited — no +new-window, no AppleScript dict,
no tab-level switching. Fallback to clipboard only.

Also document why git branch --show-current is not viable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cmux: full launch via new-workspace --cwd --command, switch via
select-workspace with project name matching. Falls back to
clipboard if socket access denied.

Ghostty: clipboard + activate (macOS limited, no tab control).

Settings: Terminal App selector (iTerm2/cmux/Ghostty), iTerm2
Open Mode only shown when iTerm2 selected.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
new-workspace creates but doesn't focus. Add select-workspace
with returned workspace ID + activate cmux app.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
list-workspaces output was truncated and titles don't always
contain paths. Now iterate all workspaces and check each one's
cwd via sidebar-state for exact path matching.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pass 1: sidebar-state cwd + focused_cwd match (fast, exact)
Pass 2: tree --all to find surface title matching project name
(handles 2nd tab and renamed workspaces)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sequential sidebar-state for 33 workspaces took ~5s. Now runs
all queries in parallel via Promise.all (~0.5s).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cmux has AppleScript dictionary with terminal.workingDirectory
and focus, but testing shows count windows returns 0. Keep
CLI sidebar-state + tree approach with parallel queries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Walk parent process tree to detect iTerm2/cmux/Ghostty/Terminal.
Active sessions switch using detected terminal (not settings).
Non-active sessions use settings terminal for launch.
Show small uppercase badge (e.g. ITERM2, CMUX) on active items.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Switch: match terminal working directory, focus matching terminal
Launch: new tab with surface configuration (command + cwd)
Fallback to clipboard if AppleScript fails.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use 'from' instead of 'with configuration' for record parameter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
command parameter is passed to exec directly (not shell),
so cd && claude fails. Use initial working directory for cwd
and initial input to type the resume command + newline.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove '(clipboard)' from Ghostty label (now full support).
Show Open Mode (New Tab/Window) for both iTerm2 and Ghostty.
Ghostty launch respects terminalMode setting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ghostty now has full AppleScript support (working directory,
focus, new tab/window with surface configuration). cmux marked
as limited support due to same-cwd matching issue.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Session-related dropdowns (Default Tab, Session Terminal,
Open Mode, Session Preview) now only visible when switcher
is in Sessions mode. Fixes popup closing issue when
interacting with dropdowns in Projects tab.

Closes #54

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clarifies that this setting only affects launching new sessions,
not switching to active ones (which auto-detects terminal).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@grimmerk grimmerk merged commit b4b1d12 into develop Mar 19, 2026
1 check failed
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