Skill v1.0.3
currentAutomated scan100/100~2 modified
version: "1.0.3" 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-downstart from your pane automatically — Muxy exportsMUXY_PANE_IDinto 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-workspaces | <workspace-id> <name> <project-count> <active> | |
muxy list-tabs | <index> <tab-id> <kind> <title> <active> | |
muxy list-sessions | <session-id> <shell-pid> <cwd> <attached> <title> <project-id> <worktree-id> <tab-id> |
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.
Background sessions
If the user has Settings → Terminal → Background sessions on, terminals keep running after Muxy quits. muxy list-sessions shows them, along with the tab, project, and worktree each one belongs to, and muxy kill-session --session <id> stops one plus everything running inside it:
muxy kill-session --session "$SESSION"
Take the ID from the first column: it matches the pane ID only until a tab adopts another session. Closing a session's tab already ends it, so reach for kill-session only for a session that outlived its tab. Never kill a session you did not create — it is someone's running work, and it is gone for good.
Worktrees and projects
muxy switch-project "My App"muxy switch-worktree feature/login --project "My App"muxy create-worktree login --branch feature/login --base mainmuxy 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.
Workspaces
Workspaces are named filters for the sidebar. A project can belong to one workspace at a time.
muxy list-workspaces # <id> <name> <project-count> <active>muxy create-workspace "My Workspace" # creates, returns the workspace IDmuxy switch-workspace "My Workspace" # filter sidebar to that workspacemuxy rename-workspace <id> "New Name"muxy delete-workspace <id>
Workspaces resolve by UUID or exact case-insensitive name.
Projects
create-project attaches an existing directory as a project, or with --create creates a new one:
muxy create-project ~/code/my-app # attach existing directorymuxy create-project ~/code/new-project --create # create directory then attachmuxy create-project ~/code/my-app --workspace "Work" # attach and move to a workspacemuxy create-project ~/code/my-app --name "My App" # set custom name
Move a project between workspaces:
muxy attach-project "My App" --workspace "Work" # move project into workspacemuxy detach-project "My App" # remove from all workspaces
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 # new terminal tabmuxy switch-tab 0 # by index, ID, or titlemuxy switch-tab "Server Logs"muxy next-tab # cycle forwardmuxy previous-tab # cycle backward
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. The list is flat and includes split-child tabs; switching to one activates its owning top-level tab and focuses that pane.
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 # tab created in that worktree, your view stays putmuxy list-tabs --project "My App" --worktree mainmuxy switch-tab 2 --worktree feature/loginmuxy 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" # omit the title to reset to the defaultmuxy tab set-color 0 blue # palette name; omit to resetmuxy tab set-icon 0 "flame.fill" # any SF Symbol name; omit to resetmuxy tab pin 0 # pin / unpin (blocks direct close)muxy tab unpin 0muxy tab move 0 2 # reorder a root tab or a child within its panemuxy tab close "Server" # close by index/id/title
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 a direct tab close / close-pane; tab close is a no-op on a pinned tab, so unpin first. Closing a parent tab still closes every child tab it owns, including pinned children.
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) # returns the browser tab IDmuxy browser open https://example.com --split # open beside the current panemuxy browser navigate "$TAB" https://example.com/docsmuxy browser list # <tab-id> <title> <url> <profile> <active>muxy browser read "$TAB" # title, then URL, then visible page textmuxy browser close "$TAB"
Automate the page once it is open:
muxy browser wait "$TAB" --selector "input[name=q]" # also --text, --url-contains, --function, --timeout-msmuxy browser wait-for "$TAB" "input[name=q]" # selector-only shorthandmuxy browser fill "$TAB" "input[name=q]" "muxy" # set an input's valuemuxy browser press "$TAB" Enter # dispatch a keymuxy browser wait-for-navigation "$TAB" # wait for the load to finishmuxy browser click "$TAB" "a.result"muxy browser select "$TAB" "#region" "us-east"muxy browser check "$TAB" "#terms" # also: uncheck, hover, scroll-into-viewmuxy browser eval "$TAB" "document.title" # run JS, returns the JSON resultmuxy browser snapshot "$TAB" # visible interactive elements (great for agents)muxy browser find "$TAB" text "Sign in" # find by role|text|label|placeholder|testidmuxy browser get-text "$TAB" "h1" # also get-html, get-value, get-attribute, get-countmuxy browser is "$TAB" visible "#checkout" # visible|enabled|checked|disabled|hiddenmuxy browser screenshot "$TAB" | base64 -D > page.png # PNG of the page (works on background tabs)muxy browser reload "$TAB" # also: back, forwardmuxy browser storage set "$TAB" token abc # local storage (add 'session' for sessionStorage)muxy browser storage get "$TAB" tokenmuxy browser cookies get "$TAB" # JSON array of cookies for the tab's profilemuxy browser cookies set "$TAB" session xyz example.commuxy 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/loginmuxy 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.
Backup configuration
muxy config export ~/Backups/muxy.muxymuxy config import ~/Backups/muxy.muxy
config export writes a full Muxy backup (settings, projects, worktrees, workspaces, key bindings, shortcuts, and Ghostty config) with secrets such as SSH keys and paired devices stripped. config import replaces current Muxy data, creates a pre-import backup first, applies the imported settings, and restarts Muxy. Paths resolve relative to the calling shell's working directory. Backup commands wait up to 610 seconds by default; set MUXY_BACKUP_TIMEOUT to override the timeout.
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 thatread-screencan surface sensitive output. See the Security model section of the docs. - Prefer switching to creating.
switch-project/switch-worktreeselect an existing entry; opening a path that is already open selects it rather than duplicating it. Reach forcreate-worktree/new-tabonly 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
- [ ] Confirmed Muxy is running before any socket command (path-open is the only exception).
- [ ] Captured every pane ID from the command that created it; never hardcoded one.
- [ ] Parsed list output by the first (ID) column, not by a possibly-duplicate title.
- [ ] Used
sendfor text andsend-keysfor one supported key; quoted commands with spaces/operators. - [ ] Named panes you create and closed them when finished, so the shared workspace stays legible.
- [ ] Remembered that targeting a worktree (
--project/--worktree) never moves the user's visible workspace; usedswitch-*to actually change focus.