Add cmux skills (browser, debug-windows, markdown, core)

Skills for cmux terminal integration: browser automation for visual
verification, debug windows, markdown viewer, and core topology control.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-03-22 12:25:54 +01:00
parent 30d40de7cf
commit b4c0ee954d
No known key found for this signature in database
GPG key ID: A32FF691A0F752D9
24 changed files with 1368 additions and 0 deletions

View file

@ -0,0 +1,141 @@
---
name: cmux-browser
description: End-user browser automation with cmux. Use when you need to open sites, interact with pages, wait for state changes, and extract data from cmux browser surfaces.
---
# Browser Automation with cmux
Use this skill for browser tasks inside cmux webviews.
## Core Workflow
1. Open or target a browser surface.
2. Verify navigation with `get url` before waiting or snapshotting.
3. Snapshot (`--interactive`) to get fresh element refs.
4. Act with refs (`click`, `fill`, `type`, `select`, `press`).
5. Wait for state changes.
6. Re-snapshot after DOM/navigation changes.
```bash
cmux --json browser open https://example.com
# use returned surface ref, for example: surface:7
cmux browser surface:7 get url
cmux browser surface:7 wait --load-state complete --timeout-ms 15000
cmux browser surface:7 snapshot --interactive
cmux browser surface:7 fill e1 "hello"
cmux --json browser surface:7 click e2 --snapshot-after
cmux browser surface:7 snapshot --interactive
```
## Surface Targeting
```bash
# identify current context
cmux identify --json
# open routed to a specific topology target
cmux browser open https://example.com --workspace workspace:2 --window window:1 --json
```
Notes:
- CLI output defaults to short refs (`surface:N`, `pane:N`, `workspace:N`, `window:N`).
- UUIDs are still accepted on input; only request UUID output when needed (`--id-format uuids|both`).
- Keep using one `surface:N` per task unless you intentionally switch.
## Wait Support
cmux supports wait patterns similar to agent-browser:
```bash
cmux browser <surface> wait --selector "#ready" --timeout-ms 10000
cmux browser <surface> wait --text "Success" --timeout-ms 10000
cmux browser <surface> wait --url-contains "/dashboard" --timeout-ms 10000
cmux browser <surface> wait --load-state complete --timeout-ms 15000
cmux browser <surface> wait --function "document.readyState === 'complete'" --timeout-ms 10000
```
## Common Flows
### Form Submit
```bash
cmux --json browser open https://example.com/signup
cmux browser surface:7 get url
cmux browser surface:7 wait --load-state complete --timeout-ms 15000
cmux browser surface:7 snapshot --interactive
cmux browser surface:7 fill e1 "Jane Doe"
cmux browser surface:7 fill e2 "jane@example.com"
cmux --json browser surface:7 click e3 --snapshot-after
cmux browser surface:7 wait --url-contains "/welcome" --timeout-ms 15000
cmux browser surface:7 snapshot --interactive
```
### Clear an Input
```bash
cmux browser surface:7 fill e11 "" --snapshot-after --json
cmux browser surface:7 get value e11 --json
```
### Stable Agent Loop (Recommended)
```bash
# navigate -> verify -> wait -> snapshot -> action -> snapshot
cmux browser surface:7 get url
cmux browser surface:7 wait --load-state complete --timeout-ms 15000
cmux browser surface:7 snapshot --interactive
cmux --json browser surface:7 click e5 --snapshot-after
cmux browser surface:7 snapshot --interactive
```
If `get url` is empty or `about:blank`, navigate first instead of waiting on load state.
## Deep-Dive References
| Reference | When to Use |
|-----------|-------------|
| [references/commands.md](references/commands.md) | Full browser command mapping and quick syntax |
| [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/authentication.md#saving-authentication-state](references/authentication.md#saving-authentication-state) | Save authenticated state right after login |
| [references/session-management.md](references/session-management.md) | Multi-surface isolation and state persistence patterns |
| [references/video-recording.md](references/video-recording.md) | Current 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 |
| [templates/authenticated-session.sh](templates/authenticated-session.sh) | Login once, save/load state |
| [templates/capture-workflow.sh](templates/capture-workflow.sh) | Navigate + capture snapshots/screenshots |
## Limits (WKWebView)
These commands currently return `not_supported` because they rely on Chrome/CDP-only APIs not exposed by WKWebView:
- viewport emulation
- offline emulation
- trace/screencast recording
- network route interception/mocking
- low-level raw input injection
Use supported high-level commands (`click`, `fill`, `press`, `scroll`, `wait`, `snapshot`) instead.
## Troubleshooting
### `js_error` on `snapshot --interactive` or `eval`
Some complex pages can reject or break the JavaScript used for rich snapshots and ad-hoc evaluation.
Recovery steps:
```bash
cmux browser surface:7 get url
cmux browser surface:7 get text body
cmux browser surface:7 get html body
```
- Use `get url` first so you know whether the page actually navigated.
- Fall back to `get text body` or `get html body` when `snapshot --interactive` or `eval` returns `js_error`.
- If the page is still failing, navigate to a simpler intermediate page, then retry the task from there.

View file

@ -0,0 +1,4 @@
interface:
display_name: "cmux Browser"
short_description: "Automate cmux webview surfaces with snapshot/ref workflows."
default_prompt: "Use this skill for browser automation via cmux CLI: identify target surface, snapshot interactive refs, perform actions, wait for state changes, and re-snapshot to avoid stale refs."

View file

@ -0,0 +1,122 @@
# Authentication Patterns
Login flows, session persistence, OAuth, and 2FA patterns for cmux browser surfaces.
**Related**: [session-management.md](session-management.md), [SKILL.md](../SKILL.md)
## Contents
- [Basic Login Flow](#basic-login-flow)
- [Saving Authentication State](#saving-authentication-state)
- [Restoring Authentication](#restoring-authentication)
- [OAuth / SSO Flows](#oauth--sso-flows)
- [Two-Factor Authentication](#two-factor-authentication)
- [Cookie-Based Auth](#cookie-based-auth)
- [Token Refresh Handling](#token-refresh-handling)
- [Security Best Practices](#security-best-practices)
## Basic Login Flow
```bash
cmux browser open https://app.example.com/login --json
cmux browser surface:7 wait --load-state complete --timeout-ms 15000
cmux browser surface:7 snapshot --interactive
# [ref=e1] email, [ref=e2] password, [ref=e3] submit
cmux browser surface:7 fill e1 "user@example.com"
cmux browser surface:7 fill e2 "$APP_PASSWORD"
cmux browser surface:7 click e3 --snapshot-after --json
cmux browser surface:7 wait --url-contains "/dashboard" --timeout-ms 20000
```
## Saving Authentication State
After logging in, save state for reuse:
```bash
cmux browser surface:7 state save ./auth-state.json
```
State includes cookies, localStorage, sessionStorage, and open tab metadata for that surface.
## Restoring Authentication
```bash
cmux browser open https://app.example.com --json
cmux browser surface:8 state load ./auth-state.json
cmux browser surface:8 goto https://app.example.com/dashboard
cmux browser surface:8 snapshot --interactive
```
## OAuth / SSO Flows
```bash
cmux browser open https://app.example.com/auth/google --json
cmux browser surface:7 wait --url-contains "accounts.google.com" --timeout-ms 30000
cmux browser surface:7 snapshot --interactive
cmux browser surface:7 fill e1 "user@gmail.com"
cmux browser surface:7 click e2 --snapshot-after --json
cmux browser surface:7 wait --url-contains "app.example.com" --timeout-ms 45000
cmux browser surface:7 state save ./oauth-state.json
```
## Two-Factor Authentication
```bash
cmux browser open https://app.example.com/login --json
cmux browser surface:7 snapshot --interactive
cmux browser surface:7 fill e1 "user@example.com"
cmux browser surface:7 fill e2 "$APP_PASSWORD"
cmux browser surface:7 click e3
# complete 2FA manually in the webview, then:
cmux browser surface:7 wait --url-contains "/dashboard" --timeout-ms 120000
cmux browser surface:7 state save ./2fa-state.json
```
## Cookie-Based Auth
```bash
cmux browser surface:7 cookies set session_token "abc123xyz"
cmux browser surface:7 goto https://app.example.com/dashboard
```
## Token Refresh Handling
```bash
#!/usr/bin/env bash
set -euo pipefail
STATE_FILE="./auth-state.json"
SURFACE="surface:7"
if [ -f "$STATE_FILE" ]; then
cmux browser "$SURFACE" state load "$STATE_FILE"
fi
cmux browser "$SURFACE" goto https://app.example.com/dashboard
URL=$(cmux browser "$SURFACE" get url)
if printf '%s' "$URL" | grep -q '/login'; then
cmux browser "$SURFACE" snapshot --interactive
cmux browser "$SURFACE" fill e1 "$APP_USERNAME"
cmux browser "$SURFACE" fill e2 "$APP_PASSWORD"
cmux browser "$SURFACE" click e3
cmux browser "$SURFACE" wait --url-contains "/dashboard" --timeout-ms 20000
cmux browser "$SURFACE" state save "$STATE_FILE"
fi
```
## Security Best Practices
1. Never commit state files (they include auth tokens).
2. Use environment variables for credentials.
3. Clear state/cookies after sensitive tasks:
```bash
cmux browser surface:7 cookies clear
rm -f ./auth-state.json
```

View file

@ -0,0 +1,108 @@
# Command Reference (cmux Browser)
This maps common `agent-browser` usage to `cmux browser` usage.
## Direct Equivalents
- `agent-browser open <url>` -> `cmux browser open <url>`
- `agent-browser goto|navigate <url>` -> `cmux browser <surface> goto|navigate <url>`
- `agent-browser snapshot -i` -> `cmux browser <surface> snapshot --interactive`
- `agent-browser click <ref>` -> `cmux browser <surface> click <ref>`
- `agent-browser fill <ref> <text>` -> `cmux browser <surface> fill <ref> <text>`
- `agent-browser type <ref> <text>` -> `cmux browser <surface> type <ref> <text>`
- `agent-browser select <ref> <value>` -> `cmux browser <surface> select <ref> <value>`
- `agent-browser get text <ref>` -> `cmux browser <surface> get text <ref-or-selector>`
- `agent-browser get url` -> `cmux browser <surface> get url`
- `agent-browser get title` -> `cmux browser <surface> get title`
## Core Command Groups
### Navigation
```bash
cmux browser open <url> # opens in caller's workspace (uses CMUX_WORKSPACE_ID)
cmux browser open <url> --workspace <id|ref> # opens in a specific workspace
cmux browser <surface> goto <url>
cmux browser <surface> back|forward|reload
cmux browser <surface> get url|title
```
> **Workspace context:** `browser open` targets the workspace of the terminal where the command is run (via `CMUX_WORKSPACE_ID`), even if a different workspace is currently focused. Use `--workspace` to override.
### Snapshot and Inspection
```bash
cmux browser <surface> snapshot --interactive
cmux browser <surface> snapshot --interactive --compact --max-depth 3
cmux browser <surface> get text body
cmux browser <surface> get html body
cmux browser <surface> get value "#email"
cmux browser <surface> get attr "#email" --attr placeholder
cmux browser <surface> get count ".row"
cmux browser <surface> get box "#submit"
cmux browser <surface> get styles "#submit" --property color
cmux browser <surface> eval '<js>'
```
### Interaction
```bash
cmux browser <surface> click|dblclick|hover|focus <selector-or-ref>
cmux browser <surface> fill <selector-or-ref> [text] # empty text clears
cmux browser <surface> type <selector-or-ref> <text>
cmux browser <surface> press|keydown|keyup <key>
cmux browser <surface> select <selector-or-ref> <value>
cmux browser <surface> check|uncheck <selector-or-ref>
cmux browser <surface> scroll [--selector <css>] [--dx <n>] [--dy <n>]
```
### Wait
```bash
cmux browser <surface> wait --selector "#ready" --timeout-ms 10000
cmux browser <surface> wait --text "Done" --timeout-ms 10000
cmux browser <surface> wait --url-contains "/dashboard" --timeout-ms 10000
cmux browser <surface> wait --load-state complete --timeout-ms 15000
cmux browser <surface> wait --function "document.readyState === 'complete'" --timeout-ms 10000
```
### Session/State
```bash
cmux browser <surface> cookies get|set|clear ...
cmux browser <surface> storage local|session get|set|clear ...
cmux browser <surface> tab list|new|switch|close ...
cmux browser <surface> state save|load <path>
```
### Diagnostics
```bash
cmux browser <surface> console list|clear
cmux browser <surface> errors list|clear
cmux browser <surface> highlight <selector>
cmux browser <surface> screenshot
cmux browser <surface> download wait --timeout-ms 10000
```
## Agent Reliability Tips
- Use `--snapshot-after` on mutating actions to return a fresh post-action snapshot.
- Re-snapshot after navigation, modal open/close, or major DOM changes.
- Prefer short handles in outputs by default (`surface:N`, `pane:N`, `workspace:N`, `window:N`).
- Use `--id-format both` only when a UUID must be logged/exported.
## Known WKWebView Gaps (`not_supported`)
- `browser.viewport.set`
- `browser.geolocation.set`
- `browser.offline.set`
- `browser.trace.start|stop`
- `browser.network.route|unroute|requests`
- `browser.screencast.start|stop`
- `browser.input_mouse|input_keyboard|input_touch`
See also:
- [snapshot-refs.md](snapshot-refs.md)
- [authentication.md](authentication.md)
- [session-management.md](session-management.md)

View file

@ -0,0 +1,37 @@
# Proxy Support
How proxy behavior works for cmux browser automation.
**Related**: [commands.md](commands.md), [SKILL.md](../SKILL.md)
## Contents
- [Current Behavior](#current-behavior)
- [What Is Not Exposed via CLI](#what-is-not-exposed-via-cli)
- [Workarounds](#workarounds)
- [Verification](#verification)
## Current Behavior
cmux browser uses WKWebView networking. Proxy behavior follows macOS/system networking and app process environment.
## What Is Not Exposed via CLI
There is currently no first-class `cmux browser proxy ...` command for per-surface proxy routing.
Why: WKWebView does not provide CDP-style per-context proxy controls equivalent to Chrome automation stacks.
## Workarounds
1. Configure system/network-level proxy for the environment where cmux runs.
2. Route traffic through an upstream gateway you control.
3. Validate behavior with explicit IP checks.
## Verification
```bash
cmux browser open https://httpbin.org/ip --json
cmux browser surface:7 get text body
```
Compare returned IP against expected proxy egress.

View file

@ -0,0 +1,94 @@
# Session Management
cmux uses isolated browser contexts per surface. Treat each browser surface as its own session.
**Related**: [authentication.md](authentication.md), [SKILL.md](../SKILL.md)
## Contents
- [Surface-Based Sessions](#surface-based-sessions)
- [Isolation Properties](#isolation-properties)
- [State Persistence](#state-persistence)
- [Common Patterns](#common-patterns)
- [Cleanup](#cleanup)
- [Best Practices](#best-practices)
## Surface-Based Sessions
```bash
# session A
cmux browser open https://app.example.com/login --json
# -> surface:7
# session B
cmux browser open https://example.com --json
# -> surface:8
cmux browser surface:7 get url
cmux browser surface:8 get url
```
## Isolation Properties
Each surface has independent:
- cookies
- localStorage/sessionStorage
- tab list and active tab
- navigation history
## State Persistence
### Save State
```bash
cmux browser surface:7 state save /tmp/auth-state.json
```
### Load State
```bash
cmux browser surface:8 state load /tmp/auth-state.json
cmux browser surface:8 goto https://app.example.com/dashboard
```
## Common Patterns
### Reuse Auth Across New Surface
```bash
cmux browser open https://app.example.com/login --json
# login on surface:7 ...
cmux browser surface:7 state save /tmp/auth.json
cmux browser open https://app.example.com --json
# assume surface:8
cmux browser surface:8 state load /tmp/auth.json
cmux browser surface:8 goto https://app.example.com/dashboard
```
### Parallel Multi-Site Tasks
```bash
cmux browser open https://site-a.example --json
cmux browser open https://site-b.example --json
cmux browser open https://site-c.example --json
cmux browser surface:11 get text body > /tmp/a.txt
cmux browser surface:12 get text body > /tmp/b.txt
cmux browser surface:13 get text body > /tmp/c.txt
```
## Cleanup
```bash
cmux close-surface --surface surface:7
cmux close-surface --surface surface:8
rm -f /tmp/auth-state.json
```
## Best Practices
1. Name/log surfaces in your script output so actions stay attributable.
2. Keep one task per surface to avoid ref churn.
3. Save state after successful auth milestones.
4. Re-snapshot after switching tabs/pages inside a surface.

View file

@ -0,0 +1,88 @@
# Snapshot and Refs
Element refs from snapshots make browser automation compact and reliable.
**Related**: [commands.md](commands.md), [SKILL.md](../SKILL.md)
## Contents
- [How Refs Work](#how-refs-work)
- [The Snapshot Command](#the-snapshot-command)
- [Using Refs](#using-refs)
- [Ref Lifecycle](#ref-lifecycle)
- [Best Practices](#best-practices)
- [Troubleshooting](#troubleshooting)
## How Refs Work
Classic flow:
```text
full DOM/HTML -> selector guessing -> action
```
cmux flow:
```text
snapshot -> refs (e1/e2/...) -> direct action
```
## The Snapshot Command
```bash
cmux browser surface:7 snapshot
cmux browser surface:7 snapshot --interactive
cmux browser surface:7 snapshot --interactive --compact --max-depth 3
```
## Using Refs
```bash
cmux browser surface:7 click e6
cmux browser surface:7 fill e10 "user@example.com"
cmux browser surface:7 fill e11 "password123"
cmux browser surface:7 click e12
```
## Ref Lifecycle
Refs are invalidated when page structure changes.
```bash
cmux browser surface:7 snapshot --interactive
# e1 is "Next"
cmux browser surface:7 click e1
# page changed, take a fresh snapshot
cmux browser surface:7 snapshot --interactive
```
## Best Practices
1. Snapshot before interacting.
2. Re-snapshot after navigation/modal/open-close flows.
3. Use `--snapshot-after` on mutating actions.
4. Scope snapshots with `--selector` for very large pages.
## Troubleshooting
### not_found / stale ref
```bash
cmux browser surface:7 snapshot --interactive
```
### Element missing due visibility/timing
```bash
cmux browser surface:7 wait --selector "#target" --timeout-ms 10000
cmux browser surface:7 scroll --dy 400
cmux browser surface:7 snapshot --interactive
```
### Too many elements
```bash
cmux browser surface:7 snapshot --selector "form#checkout" --interactive
```

View file

@ -0,0 +1,52 @@
# Video Recording
Status and alternatives for capturing browser automation evidence in cmux.
**Related**: [commands.md](commands.md), [SKILL.md](../SKILL.md)
## Contents
- [Current Status](#current-status)
- [Recommended Alternatives](#recommended-alternatives)
- [Use Cases](#use-cases)
- [Best Practices](#best-practices)
## Current Status
`cmux browser` currently does not expose a built-in video recording command.
Why: cmux browser automation runs on WKWebView, and the agent-browser style recording pipeline is Chrome/CDP-specific.
## Recommended Alternatives
### 1. Step Screenshots
```bash
cmux browser surface:7 screenshot > /tmp/step1.b64
cmux browser surface:7 click e3 --snapshot-after --json
cmux browser surface:7 screenshot > /tmp/step2.b64
```
### 2. Snapshot Timeline
```bash
cmux browser surface:7 snapshot --interactive > /tmp/snap-1.txt
cmux browser surface:7 click e3 --snapshot-after --json > /tmp/action-1.json
cmux browser surface:7 snapshot --interactive > /tmp/snap-2.txt
```
### 3. macOS Window Capture (external)
Use an external screen recorder if full-motion capture is required.
## Use Cases
- Debug flaky browser automation.
- Produce artifacts for CI logs.
- Document flow changes between releases.
## Best Practices
1. Capture snapshot before and after each mutating action.
2. Add `--snapshot-after` on clicks/fills/types that change state.
3. Keep artifacts grouped by timestamp/run id.

View file

@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -euo pipefail
SURFACE="${1:-surface:1}"
STATE_FILE="${2:-./auth-state.json}"
DASHBOARD_URL="${3:-https://app.example.com/dashboard}"
if [ -f "$STATE_FILE" ]; then
cmux browser "$SURFACE" state load "$STATE_FILE"
fi
cmux browser "$SURFACE" goto "$DASHBOARD_URL"
cmux browser "$SURFACE" get url
cmux browser "$SURFACE" wait --load-state complete --timeout-ms 15000
cmux browser "$SURFACE" snapshot --interactive
echo "If redirected to login, complete login flow then run:"
echo " cmux browser $SURFACE state save $STATE_FILE"

View file

@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -euo pipefail
SURFACE="${1:-surface:1}"
OUT_DIR="${2:-./browser-artifacts}"
mkdir -p "$OUT_DIR"
TS="$(date +%Y%m%d-%H%M%S)"
cmux browser "$SURFACE" snapshot --interactive > "$OUT_DIR/snapshot-$TS.txt"
cmux browser "$SURFACE" screenshot > "$OUT_DIR/screenshot-$TS.b64"
echo "Wrote: $OUT_DIR/snapshot-$TS.txt"
echo "Wrote: $OUT_DIR/screenshot-$TS.b64"

View file

@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
URL="${1:-https://example.com/form}"
SURFACE="${2:-surface:1}"
cmux browser "$SURFACE" goto "$URL"
cmux browser "$SURFACE" get url
cmux browser "$SURFACE" wait --load-state complete --timeout-ms 15000
cmux browser "$SURFACE" snapshot --interactive
echo "Now run fill/click commands using refs from the snapshot above."

View file

@ -0,0 +1,51 @@
---
name: cmux-debug-windows
description: Manage cmux debug windows and related debug menu wiring for Sidebar Debug, Background Debug, and Menu Bar Extra Debug. Use this when the user asks to open/tune these debug controls, add or adjust Debug menu entries, or capture/copy a combined debug config snapshot.
---
# cmux Debug Windows
Keep this workflow focused on existing debug windows and menu entries. Do not add a new utility/debug control window unless the user asks explicitly.
## Workflow
1. Verify debug menu wiring in `Sources/cmuxApp.swift` under `CommandMenu("Debug")`.
- Menu path in app: `Debug``Debug Windows` → window entry.
- The `Debug` menu only exists in DEBUG builds (`./scripts/reload.sh --tag ...`).
- Release builds (`reloadp.sh`, `reloads.sh`) do not show this menu.
2. Keep these actions available in `Menu("Debug Windows")`:
- `Sidebar Debug…`
- `Background Debug…`
- `Menu Bar Extra Debug…`
- `Open All Debug Windows`
3. Reuse existing per-window copy buttons (`Copy Config`) in each debug window before adding new UI.
4. For one combined payload, run:
```bash
skills/cmux-debug-windows/scripts/debug_windows_snapshot.sh --copy
```
5. After code edits, run build + tagged reload:
```bash
xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug -destination 'platform=macOS' build
./scripts/reload.sh --tag <tag>
```
## Key Files
- `Sources/cmuxApp.swift`: Debug menu entries and debug window controllers/views.
- `Sources/AppDelegate.swift`: Menu bar extra debug settings payload and defaults keys.
## Script
- `scripts/debug_windows_snapshot.sh`
Purpose:
- Reads current debug-related defaults values.
- Prints one combined snapshot for sidebar/background/menu bar extra.
- Optionally copies it to clipboard.
Examples:
```bash
skills/cmux-debug-windows/scripts/debug_windows_snapshot.sh
skills/cmux-debug-windows/scripts/debug_windows_snapshot.sh --copy
skills/cmux-debug-windows/scripts/debug_windows_snapshot.sh --domain <bundle-id> --copy
```

View file

@ -0,0 +1,4 @@
interface:
display_name: "cmux Debug Windows"
short_description: "Tune cmux debug windows and copy snapshots."
default_prompt: "Use this skill to manage cmux sidebar/background/menu-bar debug windows, keep Debug menu wiring clean, and capture copyable debug snapshots."

View file

@ -0,0 +1,190 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'USAGE'
Usage: debug_windows_snapshot.sh [--domain <defaults-domain>] [--copy]
Collect Sidebar Debug, Background Debug, Menu Bar Extra, and Browser DevTools debug values
from macOS defaults and print a combined payload. Use --copy to also copy the payload.
Examples:
debug_windows_snapshot.sh
debug_windows_snapshot.sh --copy
debug_windows_snapshot.sh --domain dev.manaflow.cmux --copy
USAGE
}
domain=""
copy_flag=0
while [[ $# -gt 0 ]]; do
case "$1" in
--domain)
shift
[[ $# -gt 0 ]] || { echo "Missing value for --domain" >&2; exit 1; }
domain="$1"
;;
--copy)
copy_flag=1
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 1
;;
esac
shift
done
discover_domain() {
defaults domains 2>/dev/null \
| tr ',' '\n' \
| tr -d ' ' \
| grep -E 'cmux' \
| head -n1 || true
}
read_value() {
local key="$1"
local fallback="$2"
local value
value=$(defaults read "$domain" "$key" 2>/dev/null || true)
if [[ -z "$value" ]]; then
printf '%s' "$fallback"
else
printf '%s' "$value"
fi
}
format_number() {
local raw="$1"
local precision="$2"
if [[ "$raw" =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then
printf "%.*f" "$precision" "$raw"
else
printf "%.*f" "$precision" 0
fi
}
if [[ -z "$domain" ]]; then
domain="$(discover_domain)"
fi
if [[ -z "$domain" ]]; then
echo "Could not auto-detect a cmux defaults domain. Pass --domain <bundle-id>." >&2
exit 1
fi
if ! defaults domains 2>/dev/null | tr ',' '\n' | tr -d ' ' | grep -Fxq "$domain"; then
echo "Defaults domain '$domain' was not found on this machine." >&2
exit 1
fi
sidebarPreset="$(read_value sidebarPreset nativeSidebar)"
sidebarMaterial="$(read_value sidebarMaterial sidebar)"
sidebarBlendMode="$(read_value sidebarBlendMode behindWindow)"
sidebarState="$(read_value sidebarState followWindow)"
sidebarBlurOpacity="$(format_number "$(read_value sidebarBlurOpacity 0.79)" 2)"
sidebarTintHex="$(read_value sidebarTintHex '#101010')"
sidebarTintOpacity="$(format_number "$(read_value sidebarTintOpacity 0.54)" 2)"
sidebarCornerRadius="$(format_number "$(read_value sidebarCornerRadius 0.0)" 1)"
sidebarActiveTabIndicatorStyle="$(read_value sidebarActiveTabIndicatorStyle solidFill)"
shortcutHintSidebarXOffset="$(format_number "$(read_value shortcutHintSidebarXOffset 0.0)" 1)"
shortcutHintSidebarYOffset="$(format_number "$(read_value shortcutHintSidebarYOffset 0.0)" 1)"
shortcutHintTitlebarXOffset="$(format_number "$(read_value shortcutHintTitlebarXOffset 4.0)" 1)"
shortcutHintTitlebarYOffset="$(format_number "$(read_value shortcutHintTitlebarYOffset 0.0)" 1)"
shortcutHintPaneTabXOffset="$(format_number "$(read_value shortcutHintPaneTabXOffset 0.0)" 1)"
shortcutHintPaneTabYOffset="$(format_number "$(read_value shortcutHintPaneTabYOffset 0.0)" 1)"
shortcutHintAlwaysShow="$(read_value shortcutHintAlwaysShow 0)"
bgGlassEnabled="$(read_value bgGlassEnabled 1)"
bgGlassMaterial="$(read_value bgGlassMaterial hudWindow)"
bgGlassTintHex="$(read_value bgGlassTintHex '#000000')"
bgGlassTintOpacity="$(format_number "$(read_value bgGlassTintOpacity 0.05)" 2)"
menubarDebugPreviewEnabled="$(read_value menubarDebugPreviewEnabled 0)"
menubarDebugPreviewCount="$(read_value menubarDebugPreviewCount 1)"
menubarDebugBadgeRectX="$(format_number "$(read_value menubarDebugBadgeRectX 5.38)" 2)"
menubarDebugBadgeRectY="$(format_number "$(read_value menubarDebugBadgeRectY 6.43)" 2)"
menubarDebugBadgeRectWidth="$(format_number "$(read_value menubarDebugBadgeRectWidth 10.75)" 2)"
menubarDebugBadgeRectHeight="$(format_number "$(read_value menubarDebugBadgeRectHeight 11.58)" 2)"
menubarDebugSingleDigitFontSize="$(format_number "$(read_value menubarDebugSingleDigitFontSize 6.70)" 2)"
menubarDebugMultiDigitFontSize="$(format_number "$(read_value menubarDebugMultiDigitFontSize 6.70)" 2)"
menubarDebugSingleDigitYOffset="$(format_number "$(read_value menubarDebugSingleDigitYOffset 0.60)" 2)"
menubarDebugMultiDigitYOffset="$(format_number "$(read_value menubarDebugMultiDigitYOffset 0.60)" 2)"
legacySingleDigitX="$(read_value menubarDebugTextRectXAdjust '')"
if [[ -n "$legacySingleDigitX" ]]; then
menubarDebugSingleDigitXAdjust="$(format_number "$legacySingleDigitX" 2)"
else
menubarDebugSingleDigitXAdjust="$(format_number "$(read_value menubarDebugSingleDigitXAdjust -1.10)" 2)"
fi
menubarDebugMultiDigitXAdjust="$(format_number "$(read_value menubarDebugMultiDigitXAdjust 2.42)" 2)"
menubarDebugTextRectWidthAdjust="$(format_number "$(read_value menubarDebugTextRectWidthAdjust 1.80)" 2)"
browserDevToolsIconName="$(read_value browserDevToolsIconName 'wrench.and.screwdriver')"
browserDevToolsIconColor="$(read_value browserDevToolsIconColor bonsplitInactive)"
payload="$(cat <<PAYLOAD
# Defaults domain
$domain
# Sidebar Debug
sidebarPreset=$sidebarPreset
sidebarMaterial=$sidebarMaterial
sidebarBlendMode=$sidebarBlendMode
sidebarState=$sidebarState
sidebarBlurOpacity=$sidebarBlurOpacity
sidebarTintHex=$sidebarTintHex
sidebarTintOpacity=$sidebarTintOpacity
sidebarCornerRadius=$sidebarCornerRadius
sidebarActiveTabIndicatorStyle=$sidebarActiveTabIndicatorStyle
shortcutHintSidebarXOffset=$shortcutHintSidebarXOffset
shortcutHintSidebarYOffset=$shortcutHintSidebarYOffset
shortcutHintTitlebarXOffset=$shortcutHintTitlebarXOffset
shortcutHintTitlebarYOffset=$shortcutHintTitlebarYOffset
shortcutHintPaneTabXOffset=$shortcutHintPaneTabXOffset
shortcutHintPaneTabYOffset=$shortcutHintPaneTabYOffset
shortcutHintAlwaysShow=$shortcutHintAlwaysShow
# Background Debug
bgGlassEnabled=$bgGlassEnabled
bgGlassMaterial=$bgGlassMaterial
bgGlassTintHex=$bgGlassTintHex
bgGlassTintOpacity=$bgGlassTintOpacity
# Menu Bar Extra Debug
menubarDebugPreviewEnabled=$menubarDebugPreviewEnabled
menubarDebugPreviewCount=$menubarDebugPreviewCount
menubarDebugBadgeRectX=$menubarDebugBadgeRectX
menubarDebugBadgeRectY=$menubarDebugBadgeRectY
menubarDebugBadgeRectWidth=$menubarDebugBadgeRectWidth
menubarDebugBadgeRectHeight=$menubarDebugBadgeRectHeight
menubarDebugSingleDigitFontSize=$menubarDebugSingleDigitFontSize
menubarDebugMultiDigitFontSize=$menubarDebugMultiDigitFontSize
menubarDebugSingleDigitYOffset=$menubarDebugSingleDigitYOffset
menubarDebugMultiDigitYOffset=$menubarDebugMultiDigitYOffset
menubarDebugSingleDigitXAdjust=$menubarDebugSingleDigitXAdjust
menubarDebugMultiDigitXAdjust=$menubarDebugMultiDigitXAdjust
menubarDebugTextRectWidthAdjust=$menubarDebugTextRectWidthAdjust
# Browser DevTools Button
browserDevToolsIconName=$browserDevToolsIconName
browserDevToolsIconColor=$browserDevToolsIconColor
PAYLOAD
)"
printf '%s\n' "$payload"
if [[ "$copy_flag" -eq 1 ]]; then
if command -v pbcopy >/dev/null 2>&1; then
printf '%s' "$payload" | pbcopy
echo "Copied debug snapshot to clipboard."
else
echo "pbcopy not available; skipped clipboard copy." >&2
fi
fi

View file

@ -0,0 +1,125 @@
---
name: cmux-markdown
description: Open markdown files in a formatted viewer panel with live reload. Use when you need to display plans, documentation, or notes alongside the terminal with rich rendering (headings, code blocks, tables, lists).
---
# Markdown Viewer with cmux
Use this skill to display markdown files in a dedicated panel with rich formatting and live file watching.
## Core Workflow
1. Write your plan or notes to a `.md` file.
2. Open it in a markdown panel.
3. The panel auto-updates when the file changes on disk.
```bash
# Open a markdown file as a split panel next to the current terminal
cmux markdown open plan.md
# Absolute path
cmux markdown open /path/to/PLAN.md
# Target a specific workspace
cmux markdown open design.md --workspace workspace:2
```
## When to Use
- Displaying an agent plan or task list alongside the terminal
- Showing documentation, changelogs, or READMEs while working
- Reviewing notes that update in real-time (e.g., a plan file being written by another process)
## Live File Watching
The panel automatically re-renders when the file changes on disk. This works with:
- Direct writes (`echo "..." >> plan.md`)
- Editor saves (vim, nano, VS Code)
- Atomic file replacement (write to temp, rename over original)
- Agent-generated plan files that are updated progressively
If the file is deleted, the panel shows a "file unavailable" state. During atomic replace, the panel attempts automatic reconnection within its short retry window. If the file returns later, close and reopen the panel.
## Agent Integration
### Opening a plan file
Write your plan to a file, then open it:
```bash
cat > plan.md << 'EOF'
# Task Plan
## Steps
1. Analyze the codebase
2. Implement the feature
3. Write tests
4. Verify the build
EOF
cmux markdown open plan.md
```
### Updating a plan in real-time
The panel live-reloads, so simply overwrite the file as work progresses:
```bash
# The markdown panel updates automatically when the file changes
echo "## Step 1: Complete" >> plan.md
```
### Recommended AGENTS.md instruction
Add this to your project's `AGENTS.md` to instruct coding agents to use the markdown viewer:
```markdown
## Plan Display
When creating a plan or task list, write it to a `.md` file and open it in cmux:
cmux markdown open plan.md
The panel renders markdown with rich formatting and auto-updates when the file changes.
```
## Routing
```bash
# Open in the caller's workspace (default -- uses CMUX_WORKSPACE_ID)
cmux markdown open plan.md
# Open in a specific workspace
cmux markdown open plan.md --workspace workspace:2
# Open splitting from a specific surface
cmux markdown open plan.md --surface surface:5
# Open in a specific window
cmux markdown open plan.md --window window:1
```
## Deep-Dive References
| Reference | When to Use |
|-----------|-------------|
| [references/commands.md](references/commands.md) | Full command syntax and options |
| [references/live-reload.md](references/live-reload.md) | File watching behavior, atomic writes, edge cases |
## Rendering Support
The markdown panel renders:
- Headings (h1-h6) with dividers on h1/h2
- Fenced code blocks with monospaced font
- Inline code with highlighted background
- Tables with alternating row colors
- Ordered and unordered lists (nested)
- Blockquotes with left border
- Bold, italic, strikethrough
- Links (clickable)
- Horizontal rules
- Images (inline)
Supports both light and dark mode.

View file

@ -0,0 +1,4 @@
interface:
display_name: "cmux Markdown Viewer"
short_description: "Open markdown files in a formatted panel with live reload alongside the terminal."
default_prompt: "Use this skill to display markdown plans, docs, or notes in a cmux panel: write to a .md file, run 'cmux markdown open <path>', and the panel auto-updates when the file changes."

View file

@ -0,0 +1,69 @@
# Command Reference (cmux Markdown)
## Opening a Markdown Panel
```bash
cmux markdown open <path>
cmux markdown <path> # shorthand (implicit "open")
```
### Options
| Flag | Description | Default |
|------|-------------|---------|
| `--workspace <id\|ref\|index>` | Target workspace | `$CMUX_WORKSPACE_ID` |
| `--surface <id\|ref\|index>` | Source surface to split from | Focused surface |
| `--window <id\|ref>` | Target window | Current window |
### Output
```
OK surface=surface:8 pane=pane:3 path=/absolute/path/to/file.md
```
With `--json`:
```json
{
"window_id": "...",
"workspace_id": "...",
"pane_id": "...",
"surface_id": "...",
"path": "/absolute/path/to/file.md"
}
```
## Path Resolution
- Relative paths are resolved against the caller's current working directory.
- `~` is expanded to the home directory.
- The resolved absolute path is returned in the output.
```bash
# These are equivalent when run from /Users/me/project
cmux markdown open plan.md
cmux markdown open ./plan.md
cmux markdown open /Users/me/project/plan.md
```
## Panel Behavior
- The panel opens as a **horizontal split** to the right of the source surface.
- The tab title shows the filename (e.g., `plan.md`).
- The tab icon is a document icon.
- Content is **read-only** with text selection enabled.
- The file path is displayed as a breadcrumb at the top of the panel.
## Session Persistence
Markdown panels are saved and restored across sessions. On restore, the panel re-reads the file from disk. If the file no longer exists at restore time, the panel is not recreated.
## Help
```bash
cmux markdown --help
cmux markdown -h
```
See also:
- [live-reload.md](live-reload.md)

View file

@ -0,0 +1,53 @@
# Live Reload Behavior
The markdown panel watches the file on disk and automatically re-renders when it changes. This enables real-time plan tracking as agents or editors update the file.
## How It Works
The panel uses a kernel-level file system watcher (`DispatchSource` with `O_EVTONLY`) that monitors the file for:
- **Write events** -- content was modified in place
- **Extend events** -- content was appended
- **Delete events** -- file was removed (atomic replace step 1)
- **Rename events** -- file was moved or renamed
## Supported Write Patterns
| Pattern | Supported | Notes |
|---------|-----------|-------|
| Direct write (`echo >>`) | Yes | Triggers write/extend event |
| Editor save (vim, nano) | Yes | Most editors use atomic write (see below) |
| Atomic replace (write tmp + rename) | Yes | Handled via delete/rename recovery |
| `sed -i` | Yes | Uses atomic replace internally |
| VS Code / IDE save | Yes | Uses atomic replace |
| Agent progressive writes | Yes | Each write triggers a re-render |
## Atomic File Replacement
Many editors and tools write files atomically: write to a temporary file, then rename it over the original. This shows up as a **delete** event followed by a new file appearing at the same path.
The panel handles this by:
1. Detecting the delete/rename event
2. Attempting to re-read the file immediately (in case the rename already happened)
3. If the file is missing, wait 500 ms and check again (the new file may not yet be in place)
4. Reconnecting the file watcher to the new inode
## File Unavailable State
If the file is deleted and does not reappear within the retry window, the panel shows a "file unavailable" state with the original path. The panel does not close automatically -- the user must close it manually.
If the file later reappears at the same path (e.g., the user recreates it), the panel does NOT automatically reconnect. Close and reopen the panel to pick up the new file.
## Performance
- Re-reads are dispatched to the main thread and run synchronously.
- Large files (100KB+) may cause brief UI hitches during re-render. For extremely large markdown files, consider splitting into smaller documents.
- The file watcher runs on a low-priority background queue and has negligible CPU impact.
## Tips for Agents
- **Write the full plan file first, then open it.** This avoids the panel showing a partially written file.
- **Append-style updates work well.** Adding sections to the end of a file triggers a smooth re-render.
- **Overwriting the entire file is fine.** The atomic replace handling ensures no data is lost.
- **Don't delete and recreate rapidly.** If writing a new version, prefer overwriting in place or using atomic replacement.

View file

@ -0,0 +1,54 @@
---
name: cmux
description: End-user control of cmux topology and routing (windows, workspaces, panes/surfaces, focus, moves, reorder, identify, trigger flash). Use when automation needs deterministic placement and navigation in a multi-pane cmux layout.
---
# cmux Core Control
Use this skill to control non-browser cmux topology and routing.
## Core Concepts
- Window: top-level macOS cmux window.
- Workspace: tab-like group within a window.
- Pane: split container in a workspace.
- Surface: a tab within a pane (terminal or browser panel).
## Fast Start
```bash
# identify current caller context
cmux identify --json
# list topology
cmux list-windows
cmux list-workspaces
cmux list-panes
cmux list-pane-surfaces --pane pane:1
# create/focus/move
cmux new-workspace
cmux new-split right --panel pane:1
cmux move-surface --surface surface:7 --pane pane:2 --focus true
cmux reorder-surface --surface surface:7 --before surface:3
# attention cue
cmux trigger-flash --surface surface:7
```
## Handle Model
- Default output uses short refs: `window:N`, `workspace:N`, `pane:N`, `surface:N`.
- UUIDs are still accepted as inputs.
- Request UUID output only when needed: `--id-format uuids|both`.
## Deep-Dive References
| Reference | When to Use |
|-----------|-------------|
| [references/handles-and-identify.md](references/handles-and-identify.md) | Handle syntax, self-identify, caller targeting |
| [references/windows-workspaces.md](references/windows-workspaces.md) | Window/workspace lifecycle and reorder/move |
| [references/panes-surfaces.md](references/panes-surfaces.md) | Splits, surfaces, move/reorder, focus routing |
| [references/trigger-flash-and-health.md](references/trigger-flash-and-health.md) | Flash cue and surface health checks |
| [../cmux-browser/SKILL.md](../cmux-browser/SKILL.md) | Browser automation on surface-backed webviews |
| [../cmux-markdown/SKILL.md](../cmux-markdown/SKILL.md) | Markdown viewer panel with live file watching |

View file

@ -0,0 +1,4 @@
interface:
display_name: "cmux Core"
short_description: "Control windows/workspaces/panes/surfaces and routing with cmux CLI."
default_prompt: "Use this skill to inspect and manipulate cmux topology: identify context, target handles, create/focus/move/reorder windows/workspaces/panes/surfaces, and use trigger-flash for visual confirmation."

View file

@ -0,0 +1,35 @@
# Handles and Identify
Use `identify` and short handles for deterministic automation targeting.
## Handle Inputs
Most v2-backed commands accept:
- UUID
- short ref (`window:N`, `workspace:N`, `pane:N`, `surface:N`)
- index (where legacy/index-based commands still allow it)
## Self Identify
```bash
cmux identify --json
```
Returns current focused topology plus optional caller resolution.
## Caller Override
```bash
cmux identify --workspace workspace:2
cmux identify --workspace workspace:2 --surface surface:8
```
Useful for agents that need to route relative actions from a known caller anchor.
## Output Shaping
```bash
cmux --json identify # refs-first output
cmux --json --id-format both identify
cmux --json --id-format uuids identify
```

View file

@ -0,0 +1,36 @@
# Panes and Surfaces
Split layout, surface creation, focus, move, and reorder.
## Inspect
```bash
cmux list-panes
cmux list-pane-surfaces --pane pane:1
```
## Create Splits/Surfaces
```bash
cmux new-split right --panel pane:1
cmux new-surface --type terminal --pane pane:1
cmux new-surface --type browser --pane pane:1 --url https://example.com
```
## Focus and Close
```bash
cmux focus-pane --pane pane:2
cmux focus-panel --panel surface:7
cmux close-surface --surface surface:7
```
## Move/Reorder Surfaces
```bash
cmux move-surface --surface surface:7 --pane pane:2 --focus true
cmux move-surface --surface surface:7 --workspace workspace:2 --window window:1 --after surface:4
cmux reorder-surface --surface surface:7 --before surface:3
```
Surface identity is stable across move/reorder operations.

View file

@ -0,0 +1,23 @@
# Trigger Flash and Surface Health
Operational checks useful in automation loops.
## Trigger Flash
Flash a surface or workspace to provide visual confirmation in UI:
```bash
cmux trigger-flash --surface surface:7
cmux trigger-flash --workspace workspace:2
```
## Surface Health
Use health output to detect hidden/detached/non-windowed surfaces:
```bash
cmux surface-health
cmux surface-health --workspace workspace:2
```
Use this before routing focused input if UI state may be stale.

View file

@ -0,0 +1,31 @@
# Windows and Workspaces
Window/workspace lifecycle and ordering operations.
## Inspect
```bash
cmux list-windows
cmux current-window
cmux list-workspaces
cmux current-workspace
```
## Create/Focus/Close
```bash
cmux new-window
cmux focus-window --window window:2
cmux close-window --window window:2
cmux new-workspace
cmux select-workspace --workspace workspace:4
cmux close-workspace --workspace workspace:4
```
## Reorder and Move
```bash
cmux reorder-workspace --workspace workspace:4 --before workspace:2
cmux move-workspace-to-window --workspace workspace:4 --window window:1
```