🇰🇷 한국어 버전: README.ko.md
Field-tested tips from running many Claude Code sessions in parallel with cmux, the native macOS terminal for AI coding agents (open source). Verified against cmux 0.64.20 — details may change in later versions.
By Yohan Koo (CMDSPACE) · License: CC BY 4.0
🎨 Companion doc: Appearance & Status Line Catalog — colors, fonts, indicator shapes, sidebar density, and a customizable Claude Code status line.
- Install & basic setup
- The core model — everything has an address
- Operating rule — project = workspace, session = tab
- Session management patterns
- Workspace groups (new in 0.64.20)
- Working with tabs (surfaces) and panes
- Mirroring remote tmux
- Claude Code integration — hooks and remote control
- Philosophy: the bottleneck is attention, not execution
- Appendix: one-liners
# Homebrew
brew tap manaflow-ai/cmux
brew install --cask cmux
# Symlink the CLI so it works outside cmux (plain shells, scripts)
sudo ln -sf "/Applications/cmux.app/Contents/Resources/bin/cmux" /usr/local/bin/cmux- Control happens over a Unix socket CLI:
cmux <command>. The CLI automatically uses the socket password from Settings → Automation — no extra auth code needed. - The app auto-updates via Sparkle.
window > workspace > pane > surface(=tab)
└ workspace_group (new in 0.64.20 — a bundle of workspaces)
The most important design decision in cmux: every entity carries a dual address:
- UUID — persistent identifier
- short ref —
window:1workspace:26pane:3surface:4workspace_group:2
Most CLI commands take these refs as arguments. The starting point of cmux automation is that you stop manipulating "the tab I'm looking at" and start manipulating addressable entities (→ §9).
When running many sessions, I follow a single structural rule:
Project = workspace, Claude Code session = a surface (tab) inside it.
- Give each workspace an identity with color (16 colors) and pin — "DEV is always in that spot, in that color."
cmux workspace-action --action set-color # same pattern for set-pin / rename - Tab titles show what Claude Code is doing right now (
✳ …), so a singlecmux tree --allgives you the whole picture. - When several workspaces temporarily serve one purpose (e.g. a multi-agent research wave), wrap them in a group and dissolve it when done (→ §5).
- Attach supporting material (monitoring dashboards, docs) as split panes next to the agent tab (→ §6).
The real payoff of this layout is not aesthetics but spatial memory. Once you develop the bodily sense of "that task lives in the green workspace, top-left," ten sessions stop being a list and become a map.
| Goal | Command / method |
|---|---|
| Bird's-eye view | cmux tree --all — window→workspace→pane→surface + Claude session titles |
| Resource check | cmux top --processes · cmux memory --groups 5 |
| Workspace identity | cmux workspace-action --action set-color/pin/rename |
| Per-workspace todos | cmux todo add/check · cmux workspace status |
| Sidebar status pills | cmux set-status / read back with cmux list-status --workspace <ref> |
| Hibernate background sessions | cmux agent-hibernation on |
| Restore after reboot | cmux restore-session |
| Subscribe to events (automation) | cmux events --name workspace.selected --reconnect |
Manage workspaces as collapsible bundles in the sidebar. The CLI surface is rpc:
# Create — ⚠️ measured behavior: this creates a new 'anchor workspace' named
# after the group, and your current workspace is added to it
# (you do NOT get an empty group)
cmux rpc workspace.group.create '{"name":"research-pipeline"}'
cmux rpc workspace.group.add '{"group_id":"<uuid>","workspace_id":"<uuid>"}'
cmux rpc workspace.group.remove '{"group_id":"…","workspace_id":"…"}'
cmux rpc workspace.group.list # inspect groups, members, anchors
cmux rpc workspace.group.ungroup '{"group_id":"…"}' # dissolve (workspaces preserved)
⚠️ deleteis destructive. To dissolve a bundle while keeping the workspaces, always useungroup.
- Display/housekeeping verbs:
rename·move·focus·collapse/expand·pin/unpin·set_color·set_icon·set_anchor - Create a new workspace inside a group:
cmux new-workspace --name summarizer --group workspace_group:2 \ --group-placement afterCurrent # top | end | afterCurrent(+--group-reference)
Suggested practice: wrap a multi-agent wave in one group with a color and icon → ungroup
when it ends. Keep permanent project clusters pinned + collapsed to keep the sidebar tidy.
cmux new-split right # split a pane (left|right|up|down)
cmux split-off --surface surface:5 down # detach a tab into a split
cmux drag-surface-to-split --surface surface:5 right
cmux move-surface --surface surface:5 --pane pane:2 # move a tab to another pane
cmux move-tab-to-new-workspace --tab tab:3 --title "long job" # promote a tab
cmux new-pane --type browser --url http://127.0.0.1:8787 # browser pane
cmux new-surface --type agent-session --provider claude # agent session tab
cmux rename-tab "summarizer"There is also a tmux-compatible command set, so tmux muscle memory carries over:
capture-pane (screen capture) · pipe-pane (stream output) · resize-pane ·
swap-pane · break-pane (pane → workspace promotion) · join-pane · last-pane · respawn-pane
cmux ssh-tmux dev-server # mirror via tmux -CC control mode- The remote host's tmux sessions → workspaces, tmux windows → tabs, multi-pane windows → native splits.
- Requires the "Remote tmux" beta setting. Respects
~/.ssh/configaliases, ProxyJump, and IdentityFile; interactive auth (MFA, passwords) runs over inline ssh before mirroring through the shared connection. - Management:
ssh-session-list·ssh-session-attach --session-id <id> [--split right]·ssh-session-cleanup - The result: Claude Code sessions on remote servers join the same address space (workspace refs) as local ones, so your local automation (notifications, jump-to-session) covers them too.
Shells running inside cmux get CMUX_WORKSPACE_ID and CMUX_SURFACE_ID injected.
Read these in Claude Code's Stop/Notification hooks and you can stamp every notification
with "which session this came from" — the key ingredient for notification→session jump automation.
# inside a hook script
echo "origin of this notification: $CMUX_WORKSPACE_ID / tab: $CMUX_SURFACE_ID"If you need the tab number, resolve surface UUID → tab position with cmux rpc surface.list.
cmux read-screen --workspace workspace:22 --lines 40 # remote eyes — read the screen
cmux send --workspace workspace:22 "keep going" # remote hands — inject text
cmux send-key --workspace workspace:22 enter # approve a permission promptWith just these three you can observe and drive any Claude Code session from another session — or from an external daemon or bot.
cmux set-status attaches a status pill (icon + label + color + priority) to a workspace.
I refresh a pill on every Claude Code hook:
- Waiting for input 🟡 — label =
tab N · decision hint("which tab, deciding what") - Error 🔴 — truncated headline
- Done — pill cleared
A glance at the sidebar shows exactly which sessions are waiting on you. Verify with cmux list-status.
Groups (§5) plus pills (§4/§8) turn the sidebar into a classifiable structure: groups hold workspaces, workspaces hold tabs, and every level can carry tags — status pills, colors, icons.
That classification enables the pattern I use most: periodic auto-curation. An external sidecar daemon judges each session from hook signals (needs input / error / long-idle), then moves workspaces between groups and windows automatically so that one "NOW" view always contains only the sessions that actually require my attention. When a session is resolved, it goes back to its original spot.
The result: instead of scanning ten workspaces, I look at one auto-maintained
window that says "these are the sessions waiting on you." The moving parts are
all plain CLI/RPC calls (workspace.group.add/remove, window moves, set-status),
so any script or daemon can implement this loop — mine is a personal sidecar
app (OmniControl) that runs the judgment on a timer.
cmux notify --title "build done" --workspace workspace:18
cmux diff --last-turn # diff viewer for the agent's last turn
cmux markdown open README.md # formatted markdown panelRun ten Claude Code sessions at once and you learn something: the agents don't get tired — you do. More precisely, the cost of tracking "which session needs me right now" overtakes the cost of execution. When finished sessions, sessions paused on permission prompts, and sessions that quietly died on errors all blur together, multi-agent work stops being productivity and becomes surveillance labor.
So the essence of session management is not terminal layout but attention routing:
- Half of it is sending signals (done / needs input / error) to channels (notifications, sounds, messengers).
- The other half is a one-step path back to that exact session when the signal arrives.
This is where cmux's UUID+ref addressing shines. The moment a session has an address, everything above it falls into place. Put the workspace address inside the notification card and the notification stops meaning "something finished" and starts meaning "come here." A pending queue stops being a list and becomes a jump button. A voice command stops being a broadcast and becomes a delivery to one specific session.
I built a sidecar daemon on this principle (a personal project called OmniControl) that issues
system-wide deep links of the form customscheme://focus?workspace=<uuid>&cwd=<path>,
and stamps every Obsidian note with the address of the session that created it.
Add a fallback ladder — reinterpret by name when the UUID dies on restart, and if the workspace
is gone entirely, revive it in the same cwd with claude --resume — and you effectively get
session permalinks.
The generalization: when a tool can't join your linking ecosystem (PKM, automation, hook apps), the reason is usually not missing features but missing addresses. And if the tool exposes a CLI, you don't have to wait for its developer — a sidecar can issue the addresses on its behalf.
One-line summary: the secret of session management in the multi-agent era is not more monitoring — it is giving every session a clickable address and making every signal carry that address with it.
cmux workspace list # workspace inventory
cmux tree --all # full structure + session titles
cmux read-screen --workspace workspace:22 --lines 40 # remote eyes
cmux send --workspace workspace:22 "keep going" # remote hands
cmux send-key --workspace workspace:22 enter # approve permission
cmux notify --title "build done" --workspace workspace:18
cmux events --name workspace.selected --reconnect # event subscription
cmux diff --last-turn # last-turn diff
cmux markdown open README.md # markdown panel
cmux agent-hibernation on # hibernate sessions
cmux restore-session # restore after reboot- Companion doc in this repo: Appearance & Status Line Catalog
- cmux official: https://cmux.com/ · docs: https://cmux.com/docs/getting-started · source: https://github.com/manaflow-ai/cmux
- This is a personal field-notes document, not official cmux documentation. Corrections and additional tips are welcome via PR.