SKILL.md
SKILL.mdBrowse 13 files
2,616 tokens
10,963 bytes
Token encoding: o200k_base
Snapshot 6f118af
1---2name: cmux-browser3description: "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."4---5 6# Browser Automation with cmux7 8## Read the CLI contract first9 10Check the binary that will actually run before giving an exact command:11 12```bash13cmux browser --help14cmux --version15```16 17There are two deliberately different command shapes:18 19- **Create a browser surface** with `open`, `open-split`, or `new`. These commands may be workspace-scoped and do not need a surface handle.20- **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.21 22Prefer the flag form in scripts because it makes the target unmissable:23 24```bash25SURFACE="surface:7" # use a ref returned by discovery; do not guess an index26cmux browser --surface "$SURFACE" get url27cmux browser --surface "$SURFACE" get-url # accepted alias28cmux browser --surface "$SURFACE" snapshot --interactive29cmux browser --surface "$SURFACE" snapshot -i # accepted alias30cmux browser --surface "$SURFACE" url # accepted alias31cmux browser --surface "$SURFACE" tab list32cmux browser --surface "$SURFACE" click e1 --snapshot-after33```34 35The positional form is equivalent (`cmux browser "$SURFACE" get url`). `url` and36`get-url` are accepted URL aliases, and the short interactive snapshot flag is37accepted when a surface is already present; use `get url` and38`snapshot --interactive` in new documentation so the target and operation are39clear. Surface-bound operations have no unscoped form. The current CLI's40explicitly global browser verbs (`open`, `open-split`, `new`, `identify`,41`import`, `profile`, `profiles`, `react-grab`, `reactgrab`, `devtools`,42`dev-tools`, `focus-mode`, `design-mode`, `zoom`, and `history`) may omit the43handle and use caller/workspace routing; do not infer a target from visible44focus for any other verb.45 46## Find an existing browser surface without changing focus47 48`identify`, `tree`, and list commands are read-only and do not select a49workspace, pane, or browser. Do not infer that the visually focused surface is50the one the user wants.51 52First inspect the caller context (useful for the default workspace):53 54```bash55cmux identify --json56```57 58To discover browser surfaces in the caller or another workspace/window, use the59all-window tree. It includes parent refs, so a browser in a different workspace60can be targeted directly without selecting that workspace:61 62```bash63cmux tree --all --json \64 | jq -r '65 .windows[]? as $window66 | $window.workspaces[]? as $workspace67 | $workspace.panes[]? as $pane68 | $pane.surfaces[]?69 | select(.type == "browser")70 | [$window.ref, $workspace.ref, $pane.ref, .ref]71 | @tsv'72```73 74The filtered output is `window`, `workspace`, `pane`, and `surface` refs. Keep75the `surface` ref, then target it explicitly:76 77```bash78SURFACE="surface:N" # copied from the filtered tree output79cmux browser --surface "$SURFACE" get url80cmux browser --surface "$SURFACE" snapshot --interactive81```82 83If the user gives a URL or title instead of a workspace/pane, match that84metadata locally and emit only the unique surface ref. This never prints the85matched URL or title:86 87```bash88MATCH_FIELD="url" # use "title" when matching a page title89MATCH_VALUE="${BROWSER_URL_OR_TITLE:?set BROWSER_URL_OR_TITLE without logging it}"90SURFACE="$(91 cmux tree --all --json |92 jq -r --arg field "$MATCH_FIELD" --arg value "$MATCH_VALUE" '93 [94 .windows[]? as $window95 | $window.workspaces[]? as $workspace96 | $workspace.panes[]? as $pane97 | $pane.surfaces[]?98 | select(.type == "browser")99 | select((if $field == "url" then (.url // "") else (.title // "") end) == $value)100 | .ref101 ] as $matches102 | if ($matches | length) == 1 then $matches[0]103 elif ($matches | length) == 0 then error("no matching browser surface")104 else error("multiple matches; use workspace/pane context")105 end'106)"107if [[ -z "$SURFACE" ]]; then108 printf '%s\n' 'no uniquely matching browser surface; provide workspace/pane context' >&2109 exit 1110fi111cmux browser --surface "$SURFACE" get url112```113 114For one known workspace, `cmux --json list-pane-surfaces --workspace115<workspace>` is a smaller read-only query. Raw tree/list payloads can contain116page URLs and titles; filter or redact them before logging or pasting them.117Never use a focus/select command merely to discover a surface.118 119## Core workflow120 121Open (or create) a surface without stealing focus, capture the returned ref,122then use that ref for every existing-surface operation:123 124```bash125OPEN_JSON="$(cmux --json browser open https://example.com --focus false)"126SURFACE="$(printf '%s' "$OPEN_JSON" | jq -r '.surface_ref // .surface_id // empty')"127[ -n "$SURFACE" ] || { printf '%s\n' 'browser open did not return a surface ref' >&2; exit 1; }128cmux browser --surface "$SURFACE" get url129cmux browser --surface "$SURFACE" wait --load-state complete --timeout-ms 15000130cmux browser --surface "$SURFACE" snapshot --interactive131cmux browser --surface "$SURFACE" fill e1 "hello"132cmux browser --surface "$SURFACE" click e2 --snapshot-after133cmux browser --surface "$SURFACE" snapshot --interactive134```135 136After a browser download finishes, inspect the same surface's bounded history137without opening the file or consuming a waiter:138 139```bash140cmux browser --surface "$SURFACE" download list141cmux browser --surface "$SURFACE" download list --limit 5 --json142```143 144The JSON records expose the stable `download_id`, filename, actual saved path145when known, status (`downloading`, `saved`, or `failed`), byte count when146known, and whether a known path still exists. Listing is newest first and147repeatable; it remains scoped to the requested surface. Use `download wait` to148keep the existing event-wait workflow.149 150The `open` response contains the new surface ref; in a script, extract it from151the JSON response instead of printing the full response. If `get url` is empty152or `about:blank`, navigate first instead of waiting on load state. Re-snapshot153after navigation, modal open/close, or any major DOM change because refs go154stale.155 156## Wait157 158```bash159cmux browser --surface "$SURFACE" wait --selector "#ready" --timeout-ms 10000160cmux browser --surface "$SURFACE" wait --text "Success" --timeout-ms 10000161cmux browser --surface "$SURFACE" wait --url-contains "/dashboard" --timeout-ms 10000162cmux browser --surface "$SURFACE" wait --load-state complete --timeout-ms 15000163cmux browser --surface "$SURFACE" wait --function "document.readyState === 'complete'" --timeout-ms 10000164```165 166## Viewport sizing (WKWebView)167 168`cmux browser --surface "$SURFACE" viewport <width> <height>` sets an exact169logical viewport from 1 to 4096 CSS pixels. The page is aspect-fitted inside170its existing pane, so pane layout and focus stay unchanged, and screenshots use171the requested logical dimensions. `viewport reset` returns to native pane172sizing.173 174Close or detach the browser inspector first: its inspector-managed split layout175cannot be combined with viewport emulation, and opening or redocking an176attached inspector resets emulation to native sizing. Large viewport and177page-zoom combinations are bounded; the command returns structured178`maximum_page_zoom` details and leaves the viewport unchanged when the179combination exceeds WKWebView render limits.180 181## Limits (WKWebView)182 183Offline emulation, trace/screencast recording, network route184interception/mocking, and low-level raw input injection return `not_supported`;185they depend on Chrome/CDP-only APIs. Use `click`, `fill`, `press`, `scroll`,186`wait`, and `snapshot` instead.187 188## Troubleshooting `js_error`189 190Some complex pages reject the JavaScript behind `snapshot --interactive` and191`eval`. Recover by checking whether the page actually navigated, then fall192back to raw text or HTML:193 194```bash195cmux browser --surface "$SURFACE" get url196cmux browser --surface "$SURFACE" get text body197cmux browser --surface "$SURFACE" get html body198```199 200If it still fails, navigate to a simpler intermediate page and retry from201there. If the CLI and this skill disagree, refresh help (`cmux browser202--help`) and refresh the installed skill before continuing; do not invent an203implicit target.204 205## Skill distribution and refresh206 207The repository copies are the source of truth: `.claude/skills/cmux-browser`208and `.agents/skills/cmux-browser` point at `skills/cmux-browser`. Do not edit a209mirror by hand. The supported Vercel installer (pinned here to the reviewed210`skills` 1.5.23 release) refreshes both global Claude Code and Codex discovery211roots and copies the complete skill (including references and templates):212 213```bash214# From this checkout while developing the skill:215npx --yes skills@1.5.23 add . --global --yes --skill cmux-browser --agent claude-code codex --copy216 217# From the published repository after the change is merged:218npx --yes skills@1.5.23 add manaflow-ai/cmux --global --yes --skill cmux-browser --agent claude-code codex --copy219```220 221Restart an agent session after a refresh if it cached the previous document.222The repository's `skills.sh` remains available for a Codex-only destination;223pass its `--dest` explicitly when that is the installation path:224 225```bash226./skills.sh --dest "$HOME/.codex/skills" --skill cmux-browser227```228 229Never commit home-directory skill copies, credentials, cookies, or saved browser230state.231 232## Deep-dive references233 234| Reference | When to Use |235|-----------|-------------|236| [references/surface-discovery.md](references/surface-discovery.md) | Find and target an existing browser surface without focus changes |237| [references/commands.md](references/commands.md) | Full command mapping, aliases, `agent-browser` equivalents, viewport error codes |238| [references/snapshot-refs.md](references/snapshot-refs.md) | Ref lifecycle and stale-ref troubleshooting |239| [references/authentication.md](references/authentication.md) | Login/OAuth/2FA patterns and state save/load |240| [references/session-management.md](references/session-management.md) | Multi-surface isolation and state persistence |241| [references/video-recording.md](references/video-recording.md) | Recording status and practical alternatives |242| [references/proxy-support.md](references/proxy-support.md) | Proxy behavior in WKWebView and workarounds |243 244## Ready-to-use templates245 246| Template | Description |247|----------|-------------|248| [templates/form-automation.sh](templates/form-automation.sh) | Snapshot/ref form fill loop (requires an explicit surface) |249| [templates/authenticated-session.sh](templates/authenticated-session.sh) | Login once, save/load state (requires an explicit surface) |250| [templates/capture-workflow.sh](templates/capture-workflow.sh) | Navigate and capture snapshots/screenshots (requires an explicit surface) |251 Discovery context
Discovered by repository scan. No exact path reference found in the snapshot’s root CLAUDE.md.
