From sjh-skills
Orchestrates multi-pane terminal sessions via cmux CLI: splits panes, spawns Claude/Codex sub-agents, sends keys between panes, reads output, updates sidebar, manages browser/markdown panes.
npx claudepluginhub jiahao-shao1/sjh-skills --plugin sjh-skillsThis skill uses the workspace's default tool permissions.
Orchestrate terminal sessions, spawn Claude Code instances, automate the built-in browser, preview markdown — all inside cmux.
Controls cmux macOS terminal app via CLI from Claude Code: manage windows/workspaces/panes/surfaces, open embedded browser splits, send notifications, update sidebar status/progress.
Manages terminal splits for parallel commands, automates headless Chromium browser like Playwright, displays status sidebars, and coordinates AI agent teams via CLI in Claude Code workflows.
Controls cmux macOS terminal multiplexer: manages workspaces/panes/surfaces/panels, sends commands to terminals/browsers, automates browsers, notifications, sidebar metadata. Use on /cmux or cmux requests.
Share bugs, ideas, or general feedback.
Orchestrate terminal sessions, spawn Claude Code instances, automate the built-in browser, preview markdown — all inside cmux.
Check CMUX_WORKSPACE_ID env var. If set → you're in cmux. If unset → skip all cmux commands.
Auto-set env vars: CMUX_WORKSPACE_ID, CMUX_SURFACE_ID, CMUX_SOCKET_PATH.
Window > Workspace (sidebar tab) > Pane (split region) > Surface (terminal tab in pane).
Short refs: workspace:1, pane:1, surface:2.
cmux identify --json # your current context
cmux list-workspaces # all workspaces
cmux list-panes # panes in current workspace
cmux list-pane-surfaces --pane <ref> # surfaces in a pane
cmux tree --all # full hierarchy view
cmux trigger-flash --surface <ref> # flash surface for visual confirmation
cmux surface-health # detect hidden/detached surfaces
cmux new-split <left|right|up|down> # split current pane
cmux new-workspace --cwd <path> # new workspace tab
cmux new-surface # new tab in current pane
Network access requires proxy env vars. Always set them before agent commands.
Important: When sending compound commands (proxy export + agent launch), send them as a single string to cmux send. Do NOT split into separate send calls — the second command would run before the first finishes.
# Claude Code — interactive mode (user can switch to this pane and intervene)
cmux send --surface <ref> 'export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890 HTTPS_PROXY=http://127.0.0.1:7890 HTTP_PROXY=http://127.0.0.1:7890 ALL_PROXY=socks5://127.0.0.1:7890 && claude --dangerously-skip-permissions\n'
# Claude Code — non-interactive mode (run task, capture output, signal completion)
cmux send --surface <ref> 'export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890 HTTPS_PROXY=http://127.0.0.1:7890 HTTP_PROXY=http://127.0.0.1:7890 ALL_PROXY=socks5://127.0.0.1:7890 && claude -p "your prompt" --model haiku 2>&1 | tee /tmp/agent-output.txt; echo "AGENT_DONE"\n'
# Codex — interactive mode (full-auto, user can intervene)
cmux send --surface <ref> 'export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890 HTTPS_PROXY=http://127.0.0.1:7890 HTTP_PROXY=http://127.0.0.1:7890 ALL_PROXY=socks5://127.0.0.1:7890 && codex --dangerously-bypass-approvals-and-sandbox\n'
# Codex — with initial prompt
cmux send --surface <ref> 'export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890 HTTPS_PROXY=http://127.0.0.1:7890 HTTP_PROXY=http://127.0.0.1:7890 ALL_PROXY=socks5://127.0.0.1:7890 && codex --dangerously-bypass-approvals-and-sandbox -p "your prompt"\n'
When the user asks to "split a pane with Codex/Claude/agent", always:
cmux new-split <direction> to create the panecmux send --surface <new-ref> '<export https_proxy=... && agent command>\n' to launchcmux send --surface <new-ref> 'prompt' then cmux send-key --surface <new-ref> entercmux send --surface <ref> 'text\n' # send text + Enter (for shell commands)
cmux send --surface <ref> 'text' # send text only (no Enter)
cmux send-key --surface <ref> <key> # send special key (ctrl-c, enter, etc.)
cmux read-screen --surface <ref> --lines <n> # read last n lines of terminal output
Shell vs interactive programs: \n works as Enter for shell prompts (bash processes it via line discipline). But interactive programs in raw terminal mode (Claude Code, vim, etc.) treat \n as a literal newline character, not a submit action. For those, send text without \n, then use send-key enter:
# Shell command — \n works as Enter
cmux send --surface <ref> 'ls -la\n'
# Interactive program — use send-key enter to submit
cmux send --surface <ref> 'your message here'
cmux send-key --surface <ref> enter
The sidebar is always visible — use it to give the user a glance at what's happening without switching panes.
cmux set-status <key> <value> --icon <name> --color <#hex>
cmux set-progress <0.0-1.0> --label "text"
cmux log --level <info|success|warning|error> --source "agent" -- "message"
cmux notify --title "Title" --body "Body" # desktop notification
cmux clear-status <key> / cmux clear-progress / cmux clear-log
cmux rename-workspace "name"
cmux rename-tab --surface <ref> "name"
cmux close-surface --surface <ref>
cmux close-workspace --workspace <ref>
Open sites in cmux's built-in browser, interact with pages, take screenshots. Read references/browser.md for full command reference, form automation, and troubleshooting.
cmux --json browser open https://example.com # open browser split, returns surface ref
cmux browser <surface> wait --load-state complete --timeout-ms 15000
cmux browser <surface> snapshot --interactive # get clickable element refs
cmux browser <surface> click e1 # click element by ref
cmux browser <surface> fill e2 "text" # fill input field
cmux browser <surface> screenshot --out /tmp/s.png # take screenshot
cmux browser <surface> get url # current URL
cmux browser <surface> get title # page title
cmux browser <surface> navigate <url> # go to URL
Display formatted markdown alongside the terminal with live reload. Read references/markdown.md for routing options and agent integration patterns.
cmux markdown open plan.md # open preview panel (auto-reloads on file change)
cmux markdown open plan.md --workspace workspace:2 # target specific workspace
cmux new-split right
cmux send --surface surface:2 'export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890 HTTPS_PROXY=http://127.0.0.1:7890 HTTP_PROXY=http://127.0.0.1:7890 ALL_PROXY=socks5://127.0.0.1:7890 && claude -p "analyze project structure" --model haiku > /tmp/a1.txt; echo "DONE"\n'
cmux new-split down
cmux send --surface surface:3 'export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890 HTTPS_PROXY=http://127.0.0.1:7890 HTTP_PROXY=http://127.0.0.1:7890 ALL_PROXY=socks5://127.0.0.1:7890 && claude -p "count code lines" --model haiku > /tmp/a2.txt; echo "DONE"\n'
cmux set-status task "Running" --icon hammer --color "#1565C0"
# Poll: cmux read-screen --surface surface:2 --lines 5
# Collect: cat /tmp/a1.txt /tmp/a2.txt
# Clean up: cmux close-surface --surface surface:2 && cmux close-surface --surface surface:3
Launch an agent in a split pane that the user can interact with directly:
# Claude Code in right split
cmux new-split right
cmux send --surface surface:2 'export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890 HTTPS_PROXY=http://127.0.0.1:7890 HTTP_PROXY=http://127.0.0.1:7890 ALL_PROXY=socks5://127.0.0.1:7890 && claude --dangerously-skip-permissions\n'
# Codex in right split (full-auto mode)
cmux new-split right
cmux send --surface surface:2 'export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890 HTTPS_PROXY=http://127.0.0.1:7890 HTTP_PROXY=http://127.0.0.1:7890 ALL_PROXY=socks5://127.0.0.1:7890 && codex --dangerously-bypass-approvals-and-sandbox\n'
To feed context to the agent after it starts (e.g., a handoff prompt):
# Wait for the agent to be ready, then send context
sleep 5
cmux send --surface surface:2 'Here is the task: ...'
cmux send-key --surface surface:2 enter
User can press ⌥⌘→ to switch to the agent pane and talk to it directly.
cmux set-progress 0.0 --label "Starting"
# ... work ...
cmux set-progress 0.5 --label "Testing"
# ... work ...
cmux set-progress 1.0 --label "Complete"
cmux clear-progress
cmux notify --title "Done" --body "All tasks finished"
--surface <ref> from when you created the pane.select-workspace, focus-pane unless the user asked.identify --json — know your context before creating terminals.