| name | muxy-cli |
| description | How to drive the Muxy macOS terminal multiplexer from a shell with the `muxy` command — open projects, switch projects/worktrees/tabs, build split layouts, send input to panes, and read visible terminal output. Use this when you are an agent running inside a Muxy pane (or any script on the same machine) and want to control the workspace instead of asking the user to click. Mechanics and the security model live in the linked docs. |
Muxy CLI Guide
The muxy command lets an agent or script control a running Muxy workspace: open projects, switch projects/worktrees/tabs, create split panes, send keystrokes to a pane, and read back what a pane is showing. You drive the same workspace the user sees — treat it as a shared surface, not a private scratchpad.
This skill is the usage layer — when to reach for the CLI and how to use it safely. For the full command reference, output formats, and security model, read the docs page (append /plain for raw Markdown):
https://muxy.app/docs/features/muxy-cli/plain
The LLM-friendly index lists every Muxy docs page: https://muxy.app/llms.txt.
When to use it
- You are running inside a Muxy pane and want to spawn a sibling pane (a dev server, a test watcher, a logs tail) instead of blocking your own terminal.
muxy split-right/split-down start from your pane automatically — Muxy exports MUXY_PANE_ID into every pane and the CLI reads it.
- You need to orchestrate work across panes — start a process in one pane, then later send it input or read its output by pane ID.
- You are scripting project setup — open a folder, switch to the right worktree, lay out a known split arrangement.
Don't use it to do work a plain shell command can do in your own pane. Splitting, sending keys, and reading screens are for when the work genuinely belongs in another pane the user is watching.
First, confirm Muxy is reachable
Every command talks to the running app over a local Unix socket — except opening a path, which falls back to launching Muxy if it is closed. So the socket commands fail with Error: Muxy is not running when Muxy is not open, while muxy <path> still works. Check once before a sequence of socket commands:
muxy list-panes >/dev/null 2>&1 || { echo "Muxy not running"; exit 1; }
If muxy itself is not found, it has not been installed — the user installs it from Muxy → Install CLI (it lands in /usr/local/bin, or ~/bin / ~/.local/bin as a fallback). You cannot install it for them.
muxy --help lists every command; muxy <command> --help (or -h) prints that command's options.
Capture IDs, never guess them
Pane, tab, project, and worktree commands key off IDs. The split commands print the new pane ID on stdout — capture it; do not invent or hardcode IDs.
WEB=$(muxy split-right npm run dev)
TESTS=$(muxy split-down --from "$WEB" npm test)
muxy rename-pane --pane "$WEB" "Web"
muxy rename-pane --pane "$TESTS" "Tests"
For the other surfaces, list and parse the tab-separated output (the first column is always the ID/index) rather than matching on a title that may not be unique:
| Command | Columns (tab-separated) |
|---|
muxy list-panes | <pane-id> <title> <cwd> <focused> |
muxy list-projects | <project-id> <name> <path> <active> |
muxy list-worktrees [project] | <worktree-id> <name> <path> <branch> <active> |
muxy list-tabs | <index> <tab-id> <kind> <title> <active> |
PANE=$(muxy list-panes | awk -F'\t' '$2=="Tests"{print $1; exit}')
Switch commands resolve a name, ID, path, or branch, so a human-readable argument is fine for switch-project / switch-worktree / switch-tab; capture the ID only when you will address the same pane repeatedly.
Send input deliberately
muxy send types text into a pane without pressing Return; muxy send-keys presses one supported key. Send the text, then the key — this lets you stage a command and run it in two steps, or send a control key on its own:
muxy send --pane "$TESTS" "npm test -- --watch"
muxy send-keys --pane "$TESTS" Enter
Supported keys: Escape/Esc, Enter/Return, Tab, Ctrl+C/Ctrl-C, Ctrl+D/Ctrl-D, Ctrl+Z/Ctrl-Z, Backspace.
You are typing into a live shell another process owns. Read the screen first if you are unsure what is running, and prefer Ctrl+C over assuming a prompt is idle.
Read the screen, don't scrape scrollback
muxy read-screen --pane <id> [--lines N] returns the last N visible lines (default 50) of rendered terminal cells — not the full scrollback. Use it to check on a process you started in another pane:
muxy read-screen --pane "$WEB" --lines 20
If you need more history than is on screen, that is a sign the work should write to a file you can read directly, not be scraped from a terminal.
Worktrees and projects
muxy switch-project "My App"
muxy switch-worktree feature/login --project "My App"
muxy create-worktree login --branch feature/login --base main
muxy refresh-worktrees
create-worktree <name> defaults the branch to <name> and creates it; pass --existing to check out an existing branch, --base <branch> to fork from a specific base, and --path/--project to place or target it. Without --path, Muxy uses the project's worktree path template or folder setting and resolves the required {branch} variable from the requested branch. After Git operations done outside Muxy, refresh-worktrees re-reads worktrees from Git.
Tabs
A tab is a whole surface (terminal, source control, an extension) within the active worktree; panes split inside a tab. Open one, move between them, or jump straight to a known tab:
muxy new-tab
muxy switch-tab 0
muxy switch-tab "Server Logs"
muxy next-tab
muxy previous-tab
Use switch-tab (resolves index/ID/title) when you know the target; reach for next-tab/previous-tab only for relative cycling. List first with muxy list-tabs when you need the index or ID.
new-tab, list-tabs, switch-tab, next-tab, previous-tab, and split-right/split-down accept --project <name|id|path> and --worktree <name|id|branch> to target a specific worktree. Both are optional: with neither they act on the active worktree; --worktree alone resolves in the active project, then searches all projects for a unique match (ambiguous — pass --project); --project alone uses that project's active/preferred worktree; both are explicit. Targeting acts in the target worktree's background workspace — your visible view stays put. Use switch-project/switch-worktree to actually move focus.
muxy new-tab --worktree feature/login
muxy list-tabs --project "My App" --worktree main
muxy switch-tab 2 --worktree feature/login
muxy split-right npm test --worktree feature/login
Customize and manage a tab with muxy tab <op> <index|id|title>. The target resolves the same way as switch-tab — by index or title within the active worktree, or by tab ID anywhere across open workspaces:
muxy tab rename 0 "Server"
muxy tab set-color 0 blue
muxy tab set-icon 0 "flame.fill"
muxy tab pin 0
muxy tab unpin 0
muxy tab move 0 2
muxy tab close "Server"
The color must be one of Muxy's palette names: red, orange, amber, yellow, lime, green, teal, cyan, blue, indigo, violet, pink. set-icon takes an SF Symbol name. Pin a tab to protect it from tab close / close-pane; tab close is a no-op on a pinned tab, so unpin first.
Browser
The built-in browser opens web pages in a tab and can be fully automated for workflows — navigation, DOM interaction, JavaScript, cookies, storage, and screenshots:
TAB=$(muxy browser open http://localhost:3000)
muxy browser open https://example.com --split
muxy browser navigate "$TAB" https://example.com/docs
muxy browser list
muxy browser read "$TAB"
muxy browser close "$TAB"
Automate the page once it is open:
muxy browser wait "$TAB" --selector "input[name=q]"
muxy browser wait-for "$TAB" "input[name=q]"
muxy browser fill "$TAB" "input[name=q]" "muxy"
muxy browser press "$TAB" Enter
muxy browser wait-for-navigation "$TAB"
muxy browser click "$TAB" "a.result"
muxy browser select "$TAB" "#region" "us-east"
muxy browser check "$TAB" "#terms"
muxy browser eval "$TAB" "document.title"
muxy browser snapshot "$TAB"
muxy browser find "$TAB" text "Sign in"
muxy browser get-text "$TAB" "h1"
muxy browser is "$TAB" visible "#checkout"
muxy browser screenshot "$TAB" | base64 -D > page.png
muxy browser reload "$TAB"
muxy browser storage set "$TAB" token abc
muxy browser storage get "$TAB" token
muxy browser cookies get "$TAB"
muxy browser cookies set "$TAB" session xyz example.com
muxy browser cookies delete "$TAB" session
Headless by default. Every browser command — including screenshot, eval, DOM reads, clicks, and navigation — works on any open tab in the active project without that tab being visible or focused. You can drive a browser tab from a terminal tab and never leave your view; there is no need to switch-tab to it first. screenshot renders the page off-screen, so it captures real content even for a backgrounded tab.
browser open and browser list accept --project <name|id|path> and --worktree <name|id|branch> to target a specific worktree (same resolution as Tabs; both optional). The tab opens in the target worktree's background workspace — your visible view stays put. Use switch-project/switch-worktree to actually move focus.
muxy browser open localhost:3000 --worktree feature/login
muxy browser list --worktree feature/login
Run browser open with no URL to open the configured home page (blank by default). Capture the tab ID from browser open (or browser list) and reuse it; never guess it. After navigating, give the page a moment to load (wait-for, wait-for-navigation, or a wait condition) before reading. Cookies are shared by all tabs on the same profile. If the built-in browser is disabled in Settings, browser actions return an error and browser list returns no tabs.
Install the skills into your AI harnesses
muxy install-skills installs the Muxy agent skills (muxy-cli and muxy-extension) into every AI coding harness it detects on the machine — Claude Code, Codex, Cursor, Droid, Grok, OpenCode, and others — using each tool's own skill location. It wraps npx skills add with --global (all your projects) and --yes (non-interactive), and forwards any extra arguments, so you can scope it like muxy install-skills -a codex. Run it once so future sessions of those harnesses pick the skills up automatically; it needs npx (Node.js) on PATH and does not require Muxy to be running.
Behavior
- Quote any command that contains spaces or shell operators so the whole thing reaches the pane intact:
muxy split-right "echo a | wc". An unquoted operator is interpreted by your shell, not the new pane.
- One key per
send-keys. It is not a key sequence parser — chain calls for multiple keys.
- The socket is local to your macOS user. It grants no extra privileges, but any process running as your user can drive the workspace while Muxy is open. Don't pipe untrusted input into
muxy send, and be mindful that read-screen can surface sensitive output. See the Security model section of the docs.
- Prefer switching to creating.
switch-project / switch-worktree select an existing entry; opening a path that is already open selects it rather than duplicating it. Reach for create-worktree / new-tab only when nothing suitable exists.
- Leave the user's focus where they expect it. You share the visible workspace — name panes you create (
rename-pane) so the user can tell what is yours, and close them (close-pane) when the work is done.
- Targeting a worktree (
--project/--worktree) never moves the user's visible workspace — the action runs in the target's background workspace; use switch-* to actually change focus.
Checklist