SKILL.md
2,616 tokens · o200k_base · 10,963 bytes
Source excerpt starting at line 1.---name: cmux-browserdescription: "End-user browser automation with cmux. Use when you need to open sites, inspect or interact with browser surfaces, wait for page state, and extract data without stealing focus."--- # Browser Automation with cmux ## Read the CLI contract first Check the binary that will actually run before giving an exact command: ```bashcmux browser --helpcmux --version``` There are two deliberately different command shapes: - **Create a browser surface** with `open`, `open-split`, or `new`. These commands may be workspace-scoped and do not need a surface handle.- **Use an existing surface** with every surface-bound navigation, inspection, interaction, tab, state, or diagnostic command. Pass the handle explicitly with `--surface <handle>` or as the first positional token. Prefer the flag form in scripts because it makes the target unmissable: ```bashSURFACE="surface:7" # use a ref returned by discovery; do not guess an indexcmux browser --surface "$SURFACE" get urlcmux browser --surface "$SURFACE" get-url # accepted aliascmux browser --surface "$SURFACE" snapshot --interactivecmux browser --surface "$SURFACE" snapshot -i # accepted aliascmux browser --surface "$SURFACE" url # accepted aliascmux browser --surface "$SURFACE" tab listcmux browser --surface "$SURFACE" click e1 --snapshot-after``` The positional form is equivalent (`cmux browser "$SURFACE" get url`). `url` and`get-url` are accepted URL aliases, and the short interactive snapshot flag isaccepted when a surface is already present; use `get url` and`snapshot --interactive` in new documentation so the target and operation areclear. Surface-bound operations have no unscoped form. The current CLI'sexplicitly global browser verbs (`open`, `open-split`, `new`, `identify`,`import`, `profile`, `profiles`, `react-grab`, `reactgrab`, `devtools`,`dev-tools`, `focus-mode`, `design-mode`, `zoom`, and `history`) may omit thehandle and use caller/workspace routing; do not infer a target from visiblefocus for any other verb. ## Find an existing browser surface without changing focus `identify`, `tree`, and list commands are read-only and do not select aworkspace, pane, or browser. Do not infer that the visually focused surface isthe one the user wants. First inspect the caller context (useful for the default workspace): ```bashcmux identify --json``` To discover browser surfaces in the caller or another workspace/window, use theall-window tree. It includes parent refs, so a browser in a different workspacecan be targeted directly without selecting that workspace: ```bashcmux tree --all --json \ | jq -r ' .windows[]? as $window | $window.workspaces[]? as $workspace | $workspace.panes[]? as $pane | $pane.surfaces[]? | select(.type == "browser") | [$window.ref, $workspace.ref, $pane.ref, .ref] | @tsv'``` The filtered output is `window`, `workspace`, `pane`, and `surface` refs. Keepthe `surface` ref, then target it explicitly: ```bashSURFACE="surface:N" # copied from the filtered tree outputcmux browser --surface "$SURFACE" get urlcmux browser --surface "$SURFACE" snapshot --interactive``` If the user gives a URL or title instead of a workspace/pane, match thatmetadata locally and emit only the unique surface ref. This never prints thematched URL or title: ```bashMATCH_FIELD="url" # use "title" when matching a page titleMATCH_VALUE="${BROWSER_URL_OR_TITLE:?set BROWSER_URL_OR_TITLE without logging it}"SURFACE="$( cmux tree --all --json | jq -r --arg field "$MATCH_FIELD" --arg value "$MATCH_VALUE" ' [ .windows[]? as $window | $window.workspaces[]? as $workspace | $workspace.panes[]? as $pane | $pane.surfaces[]? | select(.type == "browser") | select((if $field == "url" then (.url // "") else (.title // "") end) == $value) | .ref ] as $matches | if ($matches | length) == 1 then $matches[0] elif ($matches | length) == 0 then error("no matching browser surface") else error("multiple matches; use workspace/pane context") end')"if [[ -z "$SURFACE" ]]; then printf '%s\n' 'no uniquely matching browser surface; provide workspace/pane context' >&2 exit 1ficmux browser --surface "$SURFACE" get url``` For one known workspace, `cmux --json list-pane-surfaces --workspace<workspace>` is a smaller read-only query. Raw tree/list payloads can containpage URLs and titles; filter or redact them before logging or pasting them.Never use a focus/select command merely to discover a surface. ## Core workflow Open (or create) a surface without stealing focus, capture the returned ref,then use that ref for every existing-surface operation: ```bashOPEN_JSON="$(cmux --json browser open https://example.com --focus false)"SURFACE="$(printf '%s' "$OPEN_JSON" | jq -r '.surface_ref // .surface_id // empty')"[ -n "$SURFACE" ] || { printf '%s\n' 'browser open did not return a surface ref' >&2; exit 1; }cmux browser --surface "$SURFACE" get urlcmux browser --surface "$SURFACE" wait --load-state complete --timeout-ms 15000cmux browser --surface "$SURFACE" snapshot --interactivecmux browser --surface "$SURFACE" fill e1 "hello"cmux browser --surface "$SURFACE" click e2 --snapshot-aftercmux browser --surface "$SURFACE" snapshot --interactive``` After a browser download finishes, inspect the same surface's bounded historywithout opening the file or consuming a waiter: ```bashcmux browser --surface "$SURFACE" download listcmux browser --surface "$SURFACE" download list --limit 5 --json``` The JSON records expose the stable `download_id`, filename, actual saved pathwhen known, status (`downloading`, `saved`, or `failed`), byte count whenknown, and whether a known path still exists. Listing is newest first andrepeatable; it remains scoped to the requested surface. Use `download wait` tokeep the existing event-wait workflow. The `open` response contains the new surface ref; in a script, extract it fromthe JSON response instead of printing the full response. If `get url` is emptyor `about:blank`, navigate first instead of waiting on load state. Re-snapshotafter navigation, modal open/close, or any major DOM change because refs gostale. ## Wait ```bashcmux browser --surface "$SURFACE" wait --selector "#ready" --timeout-ms 10000cmux browser --surface "$SURFACE" wait --text "Success" --timeout-ms 10000cmux browser --surface "$SURFACE" wait --url-contains "/dashboard" --timeout-ms 10000cmux browser --surface "$SURFACE" wait --load-state complete --timeout-ms 15000cmux browser --surface "$SURFACE" wait --function "document.readyState === 'complete'" --timeout-ms 10000``` ## Viewport sizing (WKWebView) `cmux browser --surface "$SURFACE" viewport <width> <height>` sets an exactlogical viewport from 1 to 4096 CSS pixels. The page is aspect-fitted insideits existing pane, so pane layout and focus stay unchanged, and screenshots usethe requested logical dimensions. `viewport reset` returns to native panesizing. Close or detach the browser inspector first: its inspector-managed split layoutcannot be combined with viewport emulation, and opening or redocking anattached inspector resets emulation to native sizing. Large viewport andpage-zoom combinations are bounded; the command returns structured`maximum_page_zoom` details and leaves the viewport unchanged when thecombination exceeds WKWebView render limits. ## Limits (WKWebView) Offline emulation, trace/screencast recording, network routeinterception/mocking, and low-level raw input injection return `not_supported`;they depend on Chrome/CDP-only APIs. Use `click`, `fill`, `press`, `scroll`,`wait`, and `snapshot` instead. ## Troubleshooting `js_error` Some complex pages reject the JavaScript behind `snapshot --interactive` and`eval`. Recover by checking whether the page actually navigated, then fallback to raw text or HTML: ```bashcmux browser --surface "$SURFACE" get urlcmux browser --surface "$SURFACE" get text bodycmux browser --surface "$SURFACE" get html body``` If it still fails, navigate to a simpler intermediate page and retry fromthere. If the CLI and this skill disagree, refresh help (`cmux browser--help`) and refresh the installed skill before continuing; do not invent animplicit target. ## Skill distribution and refresh The repository copies are the source of truth: `.claude/skills/cmux-browser`and `.agents/skills/cmux-browser` point at `skills/cmux-browser`. Do not edit amirror by hand. The supported Vercel installer (pinned here to the reviewed`skills` 1.5.23 release) refreshes both global Claude Code and Codex discoveryroots and copies the complete skill (including references and templates): ```bash# From this checkout while developing the skill:npx --yes skills@1.5.23 add . --global --yes --skill cmux-browser --agent claude-code codex --copy # From the published repository after the change is merged:npx --yes skills@1.5.23 add manaflow-ai/cmux --global --yes --skill cmux-browser --agent claude-code codex --copy``` Restart an agent session after a refresh if it cached the previous document.The repository's `skills.sh` remains available for a Codex-only destination;pass its `--dest` explicitly when that is the installation path: ```bash./skills.sh --dest "$HOME/.codex/skills" --skill cmux-browser``` Never commit home-directory skill copies, credentials, cookies, or saved browserstate. ## Deep-dive references | Reference | When to Use ||-----------|-------------|| [references/surface-discovery.md](references/surface-discovery.md) | Find and target an existing browser surface without focus changes || [references/commands.md](references/commands.md) | Full command mapping, aliases, `agent-browser` equivalents, viewport error codes || [references/snapshot-refs.md](references/snapshot-refs.md) | Ref lifecycle and stale-ref troubleshooting || [references/authentication.md](references/authentication.md) | Login/OAuth/2FA patterns and state save/load || [references/session-management.md](references/session-management.md) | Multi-surface isolation and state persistence || [references/video-recording.md](references/video-recording.md) | Recording status and practical alternatives || [references/proxy-support.md](references/proxy-support.md) | Proxy behavior in WKWebView and workarounds | ## Ready-to-use templates | Template | Description ||----------|-------------|| [templates/form-automation.sh](templates/form-automation.sh) | Snapshot/ref form fill loop (requires an explicit surface) || [templates/authenticated-session.sh](templates/authenticated-session.sh) | Login once, save/load state (requires an explicit surface) || [templates/capture-workflow.sh](templates/capture-workflow.sh) | Navigate and capture snapshots/screenshots (requires an explicit surface) |
Discovery context
Discovered by repository scan. No exact path reference found in the snapshot’s root CLAUDE.md.