cmux-terminal-multiplexer

AI-native terminal multiplexer with programmable socket API, full Playwright-equivalent browser automation, and agent team coordination — built for Claude Code…

INSTALLATION
npx skills add https://github.com/aradotso/trending-skills --skill cmux-terminal-multiplexer
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

$27

cmux identify --json          # current window/workspace/pane/surface context

cmux list-panes               # all panes in current workspace

cmux list-pane-surfaces --pane pane:1  # surfaces within a pane

cmux list-workspaces          # all workspaces (tabs) in current window

Environment variables set automatically:

  • $CMUX_SURFACE_ID — your current surface ref
  • $CMUX_WORKSPACE_ID — your current workspace ref

Handles use short refs: surface:N, pane:N, workspace:N, window:N.

Terminal Splits

Create splits

cmux --json new-split right   # side-by-side (preferred for parallel work)

cmux --json new-split down    # stacked (good for logs)

Always capture the returned surface_ref:

WORKER=$(cmux --json new-split right | python3 -c "import sys,json; print(json.load(sys.stdin)['surface_ref'])")

Send commands and read output

cmux send-surface --surface surface:22 "npm run build\n"

cmux capture-pane --surface surface:22              # current screen

cmux capture-pane --surface surface:22 --scrollback  # with full history

cmux send-key-surface --surface surface:22 ctrl-c  # send key

cmux send-key-surface --surface surface:22 enter

Golden rule: never steal focus. Always use --surface targeting.

Worker split pattern

WORKER=$(cmux --json new-split right | python3 -c "import sys,json; print(json.load(sys.stdin)['surface_ref'])")

cmux send-surface --surface "$WORKER" "make test 2>&1; echo EXIT_CODE=\$?\n"

sleep 3

cmux capture-pane --surface "$WORKER"

cmux close-surface --surface "$WORKER"   # clean up when done

Pane management

cmux focus-pane --pane pane:2

cmux close-surface --surface surface:22

cmux swap-pane --pane pane:1 --target-pane pane:2

cmux move-surface --surface surface:7 --pane pane:2 --focus true

cmux reorder-surface --surface surface:7 --before surface:3

Browser Automation

cmux embeds a full headless Chromium engine with a Playwright-style API. No external Chrome required. Every command targets a browser surface by ref.

Workflow pattern

navigate → wait for load → snapshot --interactive → act with refs → re-snapshot

Open and navigate

cmux --json browser open https://example.com        # opens browser split, returns surface ref

cmux browser surface:23 goto https://other.com

cmux browser surface:23 back

cmux browser surface:23 forward

cmux browser surface:23 reload

cmux browser surface:23 get url

cmux browser surface:23 get title

Capture the surface ref:

BROWSER=$(cmux --json browser open https://docs.example.com | python3 -c "import sys,json; print(json.load(sys.stdin)['surface_ref'])")

Snapshot and element refs

Instead of CSS selectors, snapshot to get stable element refs (e1, e2, ...):

cmux browser surface:23 snapshot --interactive              # full interactive snapshot

cmux browser surface:23 snapshot --interactive --compact     # compact output

cmux browser surface:23 snapshot --selector "form#login" --interactive  # scoped

Refs are invalidated after DOM mutations — always re-snapshot after navigation or clicks. Use --snapshot-after to auto-get a fresh snapshot:

cmux --json browser surface:23 click e1 --snapshot-after

Interact with elements

# Click and hover

cmux browser surface:23 click e1

cmux browser surface:23 dblclick e2

cmux browser surface:23 hover e3

cmux browser surface:23 focus e4

# Text input

cmux browser surface:23 fill e5 "hello@example.com"   # clear + type

cmux browser surface:23 fill e5 ""                      # clear input

cmux browser surface:23 type e6 "search query"          # type without clearing

# Keys

cmux browser surface:23 press Enter

cmux browser surface:23 press Tab

cmux browser surface:23 keydown Shift

# Forms

cmux browser surface:23 check e7          # checkbox

cmux browser surface:23 uncheck e7

cmux browser surface:23 select e8 "option-value"

# Scroll

cmux browser surface:23 scroll --dy 500

cmux browser surface:23 scroll --selector ".container" --dy 300

cmux browser surface:23 scroll-into-view e9

Wait for state

cmux browser surface:23 wait --load-state complete --timeout-ms 15000

cmux browser surface:23 wait --selector "#ready" --timeout-ms 10000

cmux browser surface:23 wait --text "Success" --timeout-ms 10000

cmux browser surface:23 wait --url-contains "/dashboard" --timeout-ms 10000

cmux browser surface:23 wait --function "document.readyState === 'complete'" --timeout-ms 10000

Read page content

cmux browser surface:23 get text body        # visible text

cmux browser surface:23 get html body        # raw HTML

cmux browser surface:23 get value "#email"   # input value

cmux browser surface:23 get attr "#link" --attr href

cmux browser surface:23 get count ".items"   # element count

cmux browser surface:23 get box "#button"    # bounding box

cmux browser surface:23 get styles "#el" --property color

# State checks

cmux browser surface:23 is visible "#modal"

cmux browser surface:23 is enabled "#submit"

cmux browser surface:23 is checked "#agree"

Locators (Playwright-style)

cmux browser surface:23 find role button

cmux browser surface:23 find text "Sign In"

cmux browser surface:23 find label "Email"

cmux browser surface:23 find placeholder "Enter email"

cmux browser surface:23 find testid "submit-btn"

cmux browser surface:23 find first ".item"

cmux browser surface:23 find last ".item"

cmux browser surface:23 find nth ".item" 3

JavaScript evaluation

cmux browser surface:23 eval "document.title"

cmux browser surface:23 eval "document.querySelectorAll('.item').length"

cmux browser surface:23 eval "window.scrollTo(0, document.body.scrollHeight)"

Frames and dialogs

cmux browser surface:23 frame "#iframe-selector"   # switch to iframe

cmux browser surface:23 frame main                  # back to main frame

cmux browser surface:23 dialog accept

cmux browser surface:23 dialog dismiss

cmux browser surface:23 dialog accept "prompt text"

Cookies, storage, and state

# Cookies

cmux browser surface:23 cookies get

cmux browser surface:23 cookies set session_token "abc123"

cmux browser surface:23 cookies clear

# Local/session storage

cmux browser surface:23 storage local get

cmux browser surface:23 storage local set myKey "myValue"

cmux browser surface:23 storage session clear

# Save/restore full browser state (cookies + storage + tabs)

cmux browser surface:23 state save ./auth-state.json

cmux browser surface:23 state load ./auth-state.json

Authentication flow

BROWSER=$(cmux --json browser open https://app.example.com/login | python3 -c "import sys,json; print(json.load(sys.stdin)['surface_ref'])")

cmux browser $BROWSER wait --load-state complete --timeout-ms 15000

cmux browser $BROWSER snapshot --interactive

cmux browser $BROWSER fill e1 "user@example.com"

cmux browser $BROWSER fill e2 "my-password"

cmux browser $BROWSER click e3

cmux browser $BROWSER wait --url-contains "/dashboard" --timeout-ms 20000

# Save auth for reuse

cmux browser $BROWSER state save ./auth-state.json

# Reuse in a new surface

BROWSER2=$(cmux --json browser open https://app.example.com | python3 -c "import sys,json; print(json.load(sys.stdin)['surface_ref'])")

cmux browser $BROWSER2 state load ./auth-state.json

cmux browser $BROWSER2 goto https://app.example.com/dashboard

Diagnostics

cmux browser surface:23 console list     # JS console output

cmux browser surface:23 console clear

cmux browser surface:23 errors list      # JS errors

cmux browser surface:23 errors clear

cmux browser surface:23 highlight "#el"  # visual highlight

cmux browser surface:23 screenshot       # capture screenshot

Script and style injection

cmux browser surface:23 addscript "console.log('injected')"

cmux browser surface:23 addstyle "body { background: red; }"

cmux browser surface:23 addinitscript "window.__injected = true"  # runs on every nav

Sidebar Status and Progress

Show live status to the user without interrupting their flow:

cmux set-status agent "working" --icon hammer --color "#ff9500"

cmux set-status agent "done" --icon checkmark --color "#34c759"

cmux clear-status agent

cmux set-progress 0.3 --label "Running tests..."

cmux set-progress 1.0 --label "Complete"

cmux clear-progress

cmux log "Starting build"

cmux log --level success "All tests passed"

cmux log --level error --source build "Compilation failed"

Notifications

cmux notify --title "Task Complete" --body "All tests passing"

cmux notify --title "Need Input" --subtitle "Permission" --body "Approve deployment?"

Agent Teams with cmux

Use cmux splits to give each agent teammate a visible workspace. Coordinate via SendMessage and task lists — never via reading each other's terminal output.

The pattern

  • Create splits for each teammate
  • Spawn teammates via Agent tool — pass each their cmux surface ref
  • Teammates run commands in their split via cmux send-surface
  • Teammates report status via cmux set-status and cmux log
  • User sees all work side-by-side

Example: 3-agent team

# Create visible splits for each teammate

SPLIT_1=$(cmux --json new-split right | python3 -c "import sys,json; print(json.load(sys.stdin)['surface_ref'])")

SPLIT_2=$(cmux --json new-split down | python3 -c "import sys,json; print(json.load(sys.stdin)['surface_ref'])")

SPLIT_3=$(cmux --json new-split down | python3 -c "import sys,json; print(json.load(sys.stdin)['surface_ref'])")

Then in each teammate's prompt:

You have a cmux terminal split at surface:42.

Run commands:  cmux send-surface --surface surface:42 "command\n"

Read output:   cmux capture-pane --surface surface:42

Set status:    cmux set-status myagent "working" --icon hammer

Log progress:  cmux log "message"

Never steal focus — always use --surface targeting.

Mixed layout: terminals + browsers

BUILD=$(cmux --json new-split right | python3 -c "import sys,json; print(json.load(sys.stdin)['surface_ref'])")

DOCS=$(cmux --json browser open https://docs.example.com | python3 -c "import sys,json; print(json.load(sys.stdin)['surface_ref'])")

TEST=$(cmux --json new-split down | python3 -c "import sys,json; print(json.load(sys.stdin)['surface_ref'])")

Key rules

  • **Never spawn claude -p in splits** — use the Agent tool with team_name instead
  • Create splits before spawning teammates — pass refs in their prompts
  • One split per teammate — each owns their visible workspace
  • Coordinate via SendMessage, not by reading each other's terminal output
  • Clean up: cmux close-surface --surface <ref> when done

Quick Reference

Task

Command

Where am I?

cmux identify --json

Split right

cmux --json new-split right

Split down

cmux --json new-split down

Send command

cmux send-surface --surface <ref> "cmd\n"

Read output

cmux capture-pane --surface <ref>

Open browser

cmux --json browser open <url>

Page snapshot

cmux browser <ref> snapshot --interactive

Click element

cmux browser <ref> click e1

Fill input

cmux browser <ref> fill e1 "text"

Wait for load

cmux browser <ref> wait --load-state complete --timeout-ms 15000

Read page text

cmux browser <ref> get text body

Evaluate JS

cmux browser <ref> eval "expression"

Find by role

cmux browser <ref> find role button

Save auth

cmux browser <ref> state save ./auth.json

Load auth

cmux browser <ref> state load ./auth.json

Set status

cmux set-status <key> "text" --icon <name>

Progress bar

cmux set-progress 0.5 --label "Working..."

Log message

cmux log "message"

Notify

cmux notify --title "T" --body "B"

Close split

cmux close-surface --surface <ref>

Screenshot

cmux browser <ref> screenshot

Common Patterns

Run build in background split, tail logs

LOG=$(cmux --json new-split down | python3 -c "import sys,json; print(json.load(sys.stdin)['surface_ref'])")

cmux send-surface --surface "$LOG" "cargo build --release 2>&#x26;1 | tee /tmp/build.log\n"

# ... do other work ...

cmux capture-pane --surface "$LOG" --scrollback | tail -20

QA test flow

BROWSER=$(cmux --json browser open https://myapp.vercel.app | python3 -c "import sys,json; print(json.load(sys.stdin)['surface_ref'])")

cmux browser $BROWSER wait --load-state complete --timeout-ms 15000

cmux browser $BROWSER snapshot --interactive

# Interact using e1, e2, e3 refs...

cmux browser $BROWSER screenshot

cmux browser $BROWSER errors list

cmux close-surface --surface $BROWSER

Status-driven long task

cmux set-status task "starting" --icon clock --color "#ff9500"

cmux set-progress 0.0 --label "Initializing..."

# ... step 1 ...

cmux set-progress 0.33 --label "Building..."

# ... step 2 ...

cmux set-progress 0.66 --label "Testing..."

# ... step 3 ...

cmux set-progress 1.0 --label "Done"

cmux set-status task "complete" --icon checkmark --color "#34c759"

cmux clear-progress

cmux notify --title "Task complete" --body "All steps passed"
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card