cmux Integration for Pi
Pi runs inside cmux with full access to the cmux CLI via three extension tools: cmux, cmux_status, and cmux_notify. The cmux extension also automatically manages sidebar status (Running/Idle/Needs input) through pi lifecycle hooks.
Naming discipline
When starting meaningful work or pivoting the core workstream, use the cmux-workspace-naming skill. Name the broad workspace theme in short Human Case, optionally with one useful emoji. Do not rename for tiny substeps.
For multi-tab, multi-session, or multi-subagent workspaces:
- Workspace/session name = umbrella theme shared by all lanes.
- Tab/surface/child-session name = stable lane/role, only when helpful.
- Parent/orchestrator owns workspace naming; child agents should not clobber it.
- Use sidebar status/progress/log rows for live state instead of renaming tabs every time something starts/stops.
- Keep the sidebar calm: avoid bouncy
Running,Checking,Fixing,Almost Donetitle churn. - For 4-10 agents, boring is good:
Parent,Research 1,Research 2,Reviewer,Worker,CI Watch. - Split into a new workspace/session when the lane becomes an independent workstream.
Required flow:
cmux action="identify"
cmux action="rename-workspace" args=["--workspace", "workspace:45", "🧭 cmux Naming Rules"]
cmux action="focus-panel" args=["--workspace", "workspace:45", "--panel", "surface:80"]
cmux action="tree" args=["--workspace", "workspace:45"]
Use the discovered refs, not guessed refs. Do not type rename commands into the active Pi terminal with send; that turns into user input instead of an operator command. Use the cmux tool or run the cmux CLI from a shell tool.
Concepts
Refs — cmux uses short refs to identify objects: workspace:1, pane:2, surface:3, window:1. Run cmux identify for the caller/focused refs, or cmux tree for layout discovery, before targeting specific surfaces.
Surfaces — a surface is a single terminal or browser tab inside a pane. Each pane can have multiple surfaces (shown as tabs). Each workspace has one or more panes (splits).
Environment — cmux auto-sets CMUX_WORKSPACE_ID, CMUX_SURFACE_ID, and CMUX_SOCKET_PATH in local terminal surfaces. In cmux ssh remote sessions, Pi subprocesses may not inherit those variables; the extension discovers ~/.cmux/bin/cmux and the relay socket automatically. Commands default to the caller's workspace/surface when flags are omitted where cmux exposes caller context.
Tools
cmux — Workspace, Pane, and Surface Control
The main tool for multiplexer operations. Takes an action and optional args array.
Discover layout
cmux action="tree"
cmux action="tree" args=["--all"]
cmux action="identify"
cmux action="remote-status"
cmux action="diagnose"
cmux action="capabilities"
cmux action="list-workspaces"
cmux action="current-workspace"
cmux action="list-panes"
cmux action="list-panes" args=["--workspace", "workspace:2"]
Read another terminal's screen
cmux action="read-screen" args=["--surface", "surface:1", "--lines", "50"]
cmux action="read-screen" args=["--surface", "surface:3", "--scrollback"]
cmux action="read-screen" args=["--workspace", "workspace:2"]
Use --scrollback to include scrollback buffer. Use --lines N to limit output. Without --surface, reads the focused surface of the specified workspace (or caller's workspace).
Send text or keys to another terminal
cmux action="send" args=["--surface", "surface:1", "npm run build\n"]
cmux action="send-key" args=["--surface", "surface:1", "Enter"]
cmux action="send-key" args=["--surface", "surface:2", "C-c"]
Important: Append \n to text to "press Enter". Use send-key for special keys: Enter, C-c (Ctrl+C), C-d, Up, Down, Left, Right, Tab, Escape, BSpace (backspace).
Create workspaces, panes, splits
cmux action="new-workspace" args=["--cwd", "/path/to/project"]
cmux action="new-split" args=["right"]
cmux action="new-split" args=["down", "--workspace", "workspace:1"]
cmux action="new-pane" args=["--type", "terminal", "--direction", "right"]
cmux action="new-pane" args=["--type", "browser", "--url", "http://localhost:3000"]
Split directions: left, right, up, down.
Navigate and manage
cmux action="select-workspace" args=["--workspace", "workspace:3"]
cmux action="rename-workspace" args=["--workspace", "workspace:3", "🚢 Course Builder Deploys"]
cmux action="focus-pane" args=["--pane", "pane:2"]
cmux action="close-surface" args=["--surface", "surface:5"]
cmux action="close-workspace" args=["--workspace", "workspace:4"]
cmux_status — Sidebar Status, Progress, and Logs
Control the cmux sidebar for the current workspace. In cmux ssh remote relay mode, current stable cmux may support notifications and remote status but not sidebar mutation commands (set-status, set-progress, log). If unsupported, the tool returns a clear error and lifecycle status writes no-op instead of failing the Pi session. Use cmux action="diagnose" first when local/remote behavior looks odd.
Status entries
cmux_status action="set-status" key="build" value="Compiling..." icon="hammer.fill" color="#FF9500" priority=10
cmux_status action="set-status" key="tests" value="14/20 passing" icon="checkmark.circle" color="#34C759" priority=10
cmux_status action="clear-status" key="build"
cmux_status action="sidebar-state"
Icons are SF Symbol names. Common ones:
bolt.fill— running/activepause.circle.fill— idle/pausedcheckmark.circle— successxmark.circle— error/failurehammer.fill— buildingmagnifyingglass— searchingarrow.down.circle— downloadingbell.fill— attention neededcircle.dashed— pending
Colors are hex: #4C8DFF (blue), #34C759 (green), #FF3B30 (red), #FF9500 (orange), #8E8E93 (gray).
priority controls sidebar ordering. Higher appears first; use negative priority for low-priority background rows.
Progress bar
cmux_status action="set-progress" value="0.45" label="Deploying..."
cmux_status action="set-progress" value="1.0" label="Complete"
cmux_status action="clear-progress"
Value is 0.0 to 1.0.
Log entries
cmux_status action="log" value="Build started" level="info"
cmux_status action="log" value="Test failed: auth.test.ts" level="error"
cmux_status action="log" value="Deprecated API usage" level="warn"
cmux_status action="clear-log"
cmux_notify — Native Notifications
Send macOS notifications via cmux. Appears in Notification Center.
cmux_notify title="Build Complete" body="All 47 tests passing" subtitle="my-project"
cmux_notify title="Deploy Failed" body="Error: connection timeout on staging"
cmux_notify title="pi" body="Task finished — ready for review"
Common Patterns
Check what's running in another workspace
# 1. Find the workspace
cmux action="tree"
# 2. Read its screen
cmux action="read-screen" args=["--workspace", "workspace:2", "--lines", "30"]
Run a command in another terminal and check output
# Send the command
cmux action="send" args=["--surface", "surface:1", "npm test 2>&1\n"]
# Wait a moment, then read the result
cmux action="read-screen" args=["--surface", "surface:1", "--lines", "50"]
Multi-workspace orchestration
# Create a new workspace for the task
cmux action="new-workspace" args=["--cwd", "/path/to/project"]
# Split it for parallel work
cmux action="new-split" args=["right"]
# Run frontend in one pane, backend in the other
cmux action="send" args=["--surface", "surface:7", "npm run dev\n"]
cmux action="send" args=["--surface", "surface:8", "npm run api\n"]
# Show progress
cmux_status action="set-progress" value="0.5" label="Starting services..."
# Open browser to preview
cmux action="new-pane" args=["--type", "browser", "--url", "http://localhost:3000"]
Long task with progress tracking
# Set status at start
cmux_status action="set-status" key="task" value="Processing..." icon="bolt.fill" color="#4C8DFF"
cmux_status action="set-progress" value="0.0" label="Step 1/5"
# Update as you go
cmux_status action="set-progress" value="0.4" label="Step 3/5"
cmux_status action="log" value="Completed migration step 3"
# Finish
cmux_status action="set-progress" value="1.0" label="Done"
cmux_status action="set-status" key="task" value="Complete" icon="checkmark.circle" color="#34C759"
cmux_notify title="Task Complete" body="All 5 steps finished successfully"
# Clean up
cmux_status action="clear-progress"
cmux_status action="clear-status" key="task"
Open a browser pane for preview
cmux action="new-pane" args=["--type", "browser", "--url", "http://localhost:3000"]
Automatic Lifecycle Status
The cmux extension automatically manages Pi sidebar metadata:
pi_model— current provider/model/thinking levelpi_usage— context usage, token totals, and cost- pane stack rows — active cmux panes/surfaces, with the running Pi pane annotated
- lifecycle status — Idle/Running/Needs input shown on the active pane row
| Pi Event | Sidebar Status | Icon | Color | Tab Indicator |
|---|---|---|---|---|
| Session start | Idle + session name (if resuming) | pause.circle.fill / text.bubble |
gray | mark-read, clear notifications |
| Agent starts working | Running | bolt.fill |
blue | mark-read, clear notifications |
| Tool execution | Live activity (e.g. "Reading ~/.zshrc") | bolt.fill |
blue | — |
| Agent turn complete | Needs input + turn summary | bell.fill |
blue | mark-unread + notification |
| Session shutdown | all cleared | — | — | mark-read, clear notifications |
Session naming is opt-in via PI_CMUX_SESSION_NAMING=1. When enabled, the session name appears as a sidebar status entry — the workspace label is never modified by the extension and is left to the operator.
Live tool activity: Every tool execution updates the active pane row with what pi is doing (e.g. "Reading ~/.zshrc", "Running grep", "Editing auth.ts"). This is always on and visible from other workspaces — useful for monitoring pi while focused elsewhere.
Attention cycle: When the agent finishes a turn, the workspace tab is marked unread (lights up) and a cmux notification fires. When the user provides input and the agent starts working again, the tab is marked read and notifications are cleared. This gives a clean read/unread signal across workspaces.
Allowed Actions
The cmux tool allows these actions: tree, identify, list-workspaces, current-workspace, read-screen, send, send-key, new-workspace, new-split, new-pane, new-surface, select-workspace, close-surface, close-workspace, list-panes, list-pane-surfaces, focus-pane, rename-workspace, surface-health.
For browser control, use new-pane with --type browser to create browser surfaces. For advanced browser automation, use the agent-browser skill or cmux browser subcommands via bash.
Extension Safety: Fork-Bomb Prevention
The cmux extension spawns helper pi -p subprocesses for session naming and turn summaries. Without proper guards, each child process loads the cmux extension again, fires the same hooks, and spawns another child — exponential process explosion.
Three-layer defense (all required):
--no-extensionsflag on everypi -pspawn — prevents the child from loading any extensions, including cmux itself. This is the critical flag;--no-tools/--no-skillsalone are not enough.--no-sessionflag — prevents the child from creating session files, which would compound the recursion with disk I/O.PI_CMUX_CHILDenv guard — the extension setsPI_CMUX_CHILD=1in the child's environment and bails out at the top ofcmuxExtension()if that var is set. Belt-and-suspenders defense in case--no-extensionsis somehow bypassed.
// Top of extension — bail if we're a helper subprocess
if (process.env[CMUX_CHILD_ENV] === "1") return;
// Every pi subprocess spawn must include:
spawn("pi", [
"-p",
"--model", NAMING_MODEL,
"--no-session", // ← no session files
"--no-extensions", // ← THE critical flag — prevents self-recursion
"--no-tools",
"--no-skills",
"--no-prompt-templates",
"--system-prompt", "...",
], {
env: { ...process.env, [CMUX_CHILD_ENV]: "1" }, // ← env guard
});
State resets on lifecycle events:
session_start: reset_pendingSessionNameand_hasNamedSessionsession_shutdown: reset both to prevent stale state across/continuesessions