Skip to content

Latest commit

 

History

History
1670 lines (1309 loc) · 73.2 KB

File metadata and controls

1670 lines (1309 loc) · 73.2 KB

OpenDevBrowser CLI

Command-line interface for installing and managing the OpenDevBrowser plugin, plus automation commands for agents. Status: active
Last updated: 2026-04-06

OpenDevBrowser exposes 57 opendevbrowser_* tools; see README.md and docs/SURFACE_REFERENCE.md for the full inventories. Generated help is the primary first-contact inventory and onboarding surface. Agent runs should start with opendevbrowser_prompting_guide or opendevbrowser_skill_load opendevbrowser-best-practices "quick start" before low-level browser commands, then load opendevbrowser_skill_load opendevbrowser-best-practices "validated capability lanes" when they need the currently proven transcript, research, and shopping workflows. Load opendevbrowser-design-agent immediately after that baseline for frontend, screenshot-to-code, or /canvas design work. Use continuity guidance only for long-running handoff or compaction. Tool-only commands opendevbrowser_prompting_guide, opendevbrowser_skill_list, and opendevbrowser_skill_load run locally via the skill loader. They are onboarding helpers, not browser-runtime commands, and they do not require relay or daemon bootstrap. CLI-only power command rpc intentionally has no tool equivalent; it is an internal daemon escape hatch behind an explicit safety flag and should be used with extreme caution. Public-surface metadata now flows from src/public-surface/source.ts through scripts/generate-public-surface-manifest.mjs into src/public-surface/generated-manifest.ts, which is consumed by src/cli/help.ts, src/cli/args.ts, and re-exported by src/tools/index.ts. Onboarding literals still live in src/cli/onboarding-metadata.json, and runtime execution authority remains src/cli/args.ts plus src/tools/index.ts.

Dependency inventory: docs/DEPENDENCIES.md First-run pre-release onboarding: docs/FIRST_RUN_ONBOARDING.md

Parity and skill-pack gates:

npm run test -- tests/cli-help-parity.test.ts
npm run test -- tests/parity-matrix.test.ts
./skills/opendevbrowser-best-practices/scripts/validate-skill-assets.sh
./skills/opendevbrowser-design-agent/scripts/validate-skill-assets.sh
./skills/opendevbrowser-design-agent/scripts/design-workflow.sh research-harvest
./skills/opendevbrowser-design-agent/scripts/design-workflow.sh release-gate

Treat those checks as contract and documentation guards. Live release proof comes from the direct-run harnesses documented later in this guide and in docs/RELEASE_RUNBOOK.md.

Installation

Requires Node.js >=18.

# Interactive installation (prompts for location)
npx opendevbrowser

# Non-interactive with flags
npx opendevbrowser --global   # Install to ~/.config/opencode/opencode.json
npx opendevbrowser --local    # Install to ./opencode.json

# Optional: persistent global CLI
npm install -g opendevbrowser
opendevbrowser --version

Pre-release local package onboarding (no npm publish)

cd <public-repo-root>
npm pack

WORKDIR=$(mktemp -d /tmp/opendevbrowser-first-run-XXXXXX)
cd "$WORKDIR"
npm init -y
npm install <public-repo-root>/opendevbrowser-0.0.17.tgz
npx --no-install opendevbrowser --help
npx --no-install opendevbrowser help

Load extension unpacked from:

  • $WORKDIR/node_modules/opendevbrowser/extension

For isolated daemon tests on machines that already run OpenDevBrowser, set:

export OPENCODE_CONFIG_DIR=/tmp/opendevbrowser-first-run-isolated/config
export OPENCODE_CACHE_DIR=/tmp/opendevbrowser-first-run-isolated/cache

By default (--skills-global), the CLI installs bundled skills to global OpenCode/Codex/ClaudeCode/AmpCLI locations (legacy claude/amp labels are still synchronized for compatibility). Use --skills-local for project-local locations or --no-skills to skip skill installation. Use --full to always create opendevbrowser.jsonc and pre-extract extension assets.

Installer inventory:

  • --skills-global and --skills-local sync the 9 canonical opendevbrowser-* packs under skills/ into managed global or project-local agent directories.
  • Reinstall and update refresh drifted managed copies and leave matching packs unchanged.
  • Uninstall removes managed canonical packs and only prunes legacy research or shopping leftovers when those directories are empty and clearly obsolete.

OPENCODE_CONFIG_DIR changes config lookup, but the extracted unpacked-extension copy created by --full still lives at ~/.config/opencode/opendevbrowser/extension.

Skill discovery order

The skill loader discovers skills in this order (first match wins):

  1. Project-local: ./.opencode/skill
  2. Global: ~/.config/opencode/skill (or $OPENCODE_CONFIG_DIR/skill)
  3. Compatibility (project): ./.codex/skills
  4. Compatibility (global): $CODEX_HOME/skills (fallback ~/.codex/skills)
  5. Compatibility (project): ./.claude/skills
  6. Compatibility (global): $CLAUDECODE_HOME/skills or $CLAUDE_HOME/skills (fallback ~/.claude/skills)
  7. Compatibility (project): ./.amp/skills
  8. Compatibility (global): $AMPCLI_HOME/skills or $AMP_CLI_HOME/skills or $AMP_HOME/skills (fallback ~/.amp/skills)
  9. Extra paths from skillPaths (advanced)
  10. Bundled package fallback: packaged skills/ directory after skillPaths when no installed copy matches

Output formats

Use --output-format to switch output formats for automation.

  • text (default): human-friendly output
  • json: single JSON object
  • stream-json: emit one JSON object per line for arrays; otherwise emits a single JSON object

Use --quiet to suppress output. Use --no-interactive (alias of --no-prompt) to disable prompts.


Exit codes

  • 0: success
  • 1: usage error (invalid args, missing flags)
  • 2: execution error (runtime/daemon failures)
  • 10: disconnected (daemon not running or unreachable)

Fatal errors are emitted even when --quiet is set. For JSON output, fatal errors are emitted as:

{ "success": false, "error": "message", "exitCode": 2 }

Argument validation

The CLI validates common flags early and returns a usage error (exitCode: 1) when inputs are invalid.

  • Conflicting flags are rejected (examples: --global + --local, --skills-global + --skills-local).
  • Numeric flags must be positive integers:
    • --port, --cdp-port
    • --wait-timeout-ms, --timeout-ms

Surface inventory (source-accurate)

Canonical inventory document: docs/SURFACE_REFERENCE.md.

CLI command surface

  • Total commands: 64.
  • Categories: install/runtime management, session/connection, navigation, interaction plus low-level pointer control, targets/pages, DOM inspection, design canvas, export plus session-centric diagnostics, macro/annotation, and internal power (rpc).

Tool surface

  • Total tools: 57 (opendevbrowser_*).
  • CLI-tool pairs: 54.
  • Tool-only surface (no CLI equivalent): opendevbrowser_prompting_guide, opendevbrowser_skill_list, opendevbrowser_skill_load.
  • CLI-only surface (no tool equivalent): install, update, uninstall, help, version, serve, daemon, native, artifacts, rpc.

Relay channel surface

  • /ops (default extension channel): high-level command protocol; see docs/SURFACE_REFERENCE.md for all 59 command names.
  • /canvas (design-canvas channel): typed design-canvas protocol; see docs/SURFACE_REFERENCE.md for all 35 command names and envelope contracts.
  • /cdp (legacy): low-level forwardCDPCommand relay path with explicit opt-in (--extension-legacy).

Challenge orchestration contract

  • Managed and /ops-backed manager responses preserve the shipped blocker fields meta.blocker, meta.blockerState, and meta.blockerResolution, and may append additive meta.challenge plus meta.challengeOrchestration.
  • Browser-assisted provider fallback reports explicit transport disposition: completed, challenge_preserved, deferred, or failed. When bounded challenge orchestration runs during fallback, decision evidence is recorded in details.challengeOrchestration.
  • Workflow and daemon callers can set challengeAutomationMode to off, browser, or browser_with_helper. Effective precedence is run > session > config.
  • Shipped config defaults now resolve to providers.challengeOrchestration.mode = browser_with_helper and providers.challengeOrchestration.optionalComputerUseBridge.enabled = true.
  • meta.challengeOrchestration and fallback details.challengeOrchestration can expose mode, source, standDownReason, and helperEligibility so stand-down decisions stay explicit.
  • ProviderRegistry is the only durable anti-bot pressure authority used by policy, runtime routing, and workflow summaries. Provider modules only contribute extraction logic and optional recoveryHints().
  • Direct browser, /ops, and provider fallback flows share one bounded challenge plane. It can try auth navigation, legitimate session or cookie reuse, non-secret field fill, and bounded browser-native interaction experimentation before yielding.
  • The optional helper bridge is browser-scoped, not a desktop agent. browser keeps it disabled and browser_with_helper only evaluates it after the existing hard gates pass.
  • Separate desktop.* config controls the shipped internal sibling desktop observation runtime. It stays permission-off by default, adds no public CLI command family, is never enabled by challengeAutomationMode, and only the internal core entrypoint composes observation with browser review.
  • Provider and workflow auto-resume still happen only after manager-owned verification clears the blocker.
  • In scope: preserved sessions, visual observation loops, low-level pointer controls, bounded interaction experimentation, reclaimable human yield packets, and owned-environment fixtures that use vendor test keys only.
  • Out of scope: hidden bypass paths, CAPTCHA-solving services, challenge token harvesting, or autonomous unsandboxed solving of third-party anti-bot systems.

Commands

Install (default)

# Interactive - prompts for global or local
npx opendevbrowser

# Global installation (user-wide)
npx opendevbrowser --global
npx opendevbrowser -g

# Local installation (current project)
npx opendevbrowser --local
npx opendevbrowser -l

# Skip prompts, use default (global)
npx opendevbrowser --no-prompt
npx opendevbrowser --no-interactive

# Full install (config + extension assets)
npx opendevbrowser --full

# Also create opendevbrowser.jsonc config file
npx opendevbrowser --global --with-config

# Full install (plugin + config + bundled skills)
npx opendevbrowser --global --with-config --skills-global

# Install skills locally (project scope)
npx opendevbrowser --skills-local

# Skip installing skills
npx opendevbrowser --no-skills

On successful installs, the CLI reconciles daemon auto-start on supported platforms (macOS/Windows) so the relay is available on login. Existing installs are rechecked and repaired when the per-user auto-start entry is missing or stale on macOS and Windows, and when the macOS LaunchAgent is malformed. If the current CLI entrypoint lives under a transient temp-root path (for example a first-run /tmp or /private/tmp npx workspace), OpenDevBrowser refuses to persist that path as auto-start. Plugin install still succeeds, but auto-start repair warns and you must rerun opendevbrowser daemon install from a stable install location, or npx --no-install opendevbrowser daemon install from a persistent local package install. You can remove auto-start later with opendevbrowser daemon uninstall.

Update

Clear the OpenCode cache to trigger reinstallation of the latest version.

npx opendevbrowser --update
npx opendevbrowser -u

This removes cached files from ~/.cache/opencode/node_modules/opendevbrowser/. OpenCode will download the latest version on next run.

Uninstall

Remove the plugin from configuration.

# Remove from global config
npx opendevbrowser --uninstall --global

# Remove from local config
npx opendevbrowser --uninstall --local

# Interactive - prompts which to remove if both exist
npx opendevbrowser --uninstall

Help / Version

npx opendevbrowser --help
npx opendevbrowser -h

npx opendevbrowser help

npx opendevbrowser --version
npx opendevbrowser -v

--help and help print the same generated first-contact inventory:

  • An Agent Quick Start block that tells agents to start with opendevbrowser_prompting_guide or opendevbrowser_skill_load opendevbrowser-best-practices "quick start" before low-level browser commands.
  • A follow-up validated_lanes entry that points agents to opendevbrowser_skill_load opendevbrowser-best-practices "validated capability lanes" for the current reliable transcript, research, and shopping runbook.
  • A direct pointer to opendevbrowser_skill_list when an agent needs a different local skill lane.
  • The complete generated CLI command, flag, and opendevbrowser_* tool inventories.
  • Canonical pointers to docs/FIRST_RUN_ONBOARDING.md, skills/opendevbrowser-best-practices/SKILL.md, and docs/SURFACE_REFERENCE.md.

Operational help parity check:

npx opendevbrowser --help
npx opendevbrowser help

First-run proof lane:

node scripts/cli-onboarding-smoke.mjs

Automation commands (daemon)

Serve (daemon)

Start a local daemon to keep sessions alive between commands.

npx opendevbrowser serve
npx opendevbrowser serve --port 8788 --token my-token

# Stop the daemon
npx opendevbrowser serve --stop

The daemon listens on 127.0.0.1 and starts the relay the extension connects to. Metadata lives in ~/.cache/opendevbrowser/daemon.json (cache only); /status is the source of truth. The daemon port/token are persisted in opendevbrowser.jsonc as daemonPort/daemonToken. serve now performs a stale-daemon preflight and terminates orphan opendevbrowser serve processes before starting (or before returning "already running"), while preserving the active daemon on the requested port.

If you run onboarding tests alongside an existing daemon, isolate config/cache via OPENCODE_CONFIG_DIR and OPENCODE_CACHE_DIR to avoid token/port collisions between sessions.

If nativeExtensionId is set in opendevbrowser.jsonc, serve will auto-install the native messaging host when it is missing. If it is not set, serve attempts to auto-detect the extension ID from Chrome, Brave, or Chromium profiles; if detection fails it continues startup.

Relay HTTP endpoints (/config, /status, /pair) accept extension origins and loopback requests with no Origin (including Origin: null) to support MV3 + PNA. Non-extension origins are rejected; preflights include Access-Control-Allow-Private-Network: true when requested.

Manual recovery (if the daemon is down or stuck)

# Start the daemon manually
npx opendevbrowser serve

# Stop/kill an existing daemon before restarting
npx opendevbrowser serve --stop

Daemon auto-start

Install or remove OS-level auto-start for the daemon. This persists an absolute node + cli + serve entrypoint (no PATH reliance) only when the current CLI path is stable. Temporary npx caches and temp onboarding workdirs are rejected instead of being written to LaunchAgent or Task Scheduler state, and all commands return machine-readable output with --output-format json.

opendevbrowser daemon install
opendevbrowser daemon uninstall
opendevbrowser daemon status

# Persistent local package install alternative
npx --no-install opendevbrowser daemon install

Behavior:

  • macOS: LaunchAgent at ~/Library/LaunchAgents/com.opendevbrowser.daemon.plist targeting an absolute node + cli + serve entrypoint.
  • Windows: per-user Task Scheduler logon task targeting an absolute node + cli + serve entrypoint; status inspects the persisted scheduled-task action from Task Scheduler XML instead of task presence alone.
  • daemon status --output-format json keeps top-level installed and running, adds nested autostart on supported platforms, and includes status only when the daemon is running.
  • autostart is the canonical detail object and includes health, needsRepair, reason, command, and expectedCommand.
  • autostart.reason can be transient_cli_path when an existing LaunchAgent or Task Scheduler action points at a temp-root CLI path that should be repaired.
  • when the current invocation is transient, a stable persisted auto-start entry can still report health="healthy"; expectedCommand is omitted instead of advertising the transient current path as the repair target.
  • daemon status returns exit code 0 when the daemon is reachable even if auto-start is missing, stale, or malformed, and 10 when the daemon is not running.
  • Successful plugin installs surface auto-start reconciliation through autostartAction; autostartError is included only when repair fails.
  • If install-time reconciliation is running from a transient temp-root CLI path, it refuses to write auto-start and reports autostartAction="repair_failed" with guidance to rerun opendevbrowser daemon install from a stable install location.

Exit codes align with the CLI:

  • 0: success
  • 1: usage error
  • 2: execution error (permissions, missing binary, OS service failure, unsupported daemon install|uninstall, or unexpected status evaluation failure)
  • 10: disconnected/not running (status only)

Auto-start install + manual fallback

# Install auto-start (recommended)
opendevbrowser daemon install

# Or, from a persistent local package install
npx --no-install opendevbrowser daemon install

# If auto-start fails, start manually
npx opendevbrowser serve

# Stop/kill before restarting
npx opendevbrowser serve --stop

If you are running from a first-run temp workspace or transient npx cache, rerun opendevbrowser daemon install from a stable install location before expecting login auto-start to persist.

Native messaging host

Install the native messaging host for the extension to use as a fallback transport when the relay WebSocket is unavailable.

# Install native host (requires extension ID)
npx opendevbrowser native install <extension-id>

# Check native host status
npx opendevbrowser native status

# Remove native host
npx opendevbrowser native uninstall

Notes:

  • Supported on macOS, Linux, and Windows.
  • Windows install writes a registry entry under HKCU\Software\Google\Chrome\NativeMessagingHosts\com.opendevbrowser.native.
  • native install requires the extension ID (chrome://extensions → copy ID).
  • Set nativeExtensionId in opendevbrowser.jsonc to allow serve to auto-install the native host when missing (preferred).
  • serve also attempts auto-detection from Chrome, Brave, or Chromium profiles, but explicit config is more reliable.
  • native status reports installed state + extension ID from the manifest.
  • Use --transport native with status to check native host status without requiring the daemon.

Workflow wrappers

The workflow wrappers expose the finalized research/shopping/product-video surfaces from docs/RESEARCH_SHOPPING_PRODUCT_VIDEO_FINAL_SPEC.md.

Research (research run)

npx opendevbrowser research run --topic "browser automation" --days 30 --mode compact
npx opendevbrowser research run --topic "Chrome extension debugging workflows" --days 30 --source-selection auto --mode json
npx opendevbrowser research run --topic "creator tools" --sources web,shopping --include-engagement --limit-per-source 5 --mode context

Flags:

  • --topic (required)
  • --days
  • --from
  • --to
  • --source-selection (auto|web|community|social|shopping|all)
  • --sources (comma-separated concrete sources)
  • --mode (compact|json|md|context|path)
  • --include-engagement
  • --limit-per-source
  • --timeout-ms
  • --output-dir
  • --ttl-hours
  • --use-cookies (true|false; bare flag means true)
  • --challenge-automation-mode (off|browser|browser_with_helper)
  • --cookie-policy-override (off|auto|required)
  • --cookie-policy (alias of --cookie-policy-override)

Notes:

  • Use --source-selection auto for generic topical research.
  • In the current contract, auto and all both stay inside the public topical families (web, community, social).
  • Add shopping only with --source-selection shopping or explicit --sources ...shopping... when the task is deliberately commercial.

Shopping (shopping run)

npx opendevbrowser shopping run --query "usb microphone" --mode compact
npx opendevbrowser shopping run --query "wireless ergonomic mouse" --providers shopping/bestbuy,shopping/ebay --budget 150 --browser-mode managed --mode json --output-format json
npx opendevbrowser shopping run --query "27 inch 4k monitor" --providers shopping/bestbuy,shopping/ebay --budget 350 --sort lowest_price --browser-mode managed --mode json --output-format json
npx opendevbrowser shopping run --query "wireless earbuds" --providers shopping/amazon --region us --browser-mode managed --mode json --output-format json

Flags:

  • --query (required)
  • --providers (comma-separated; defaults to all v1 adapters)
  • --budget
  • --region
  • --browser-mode (auto|extension|managed)
  • --sort (best_deal|lowest_price|highest_rating|fastest_shipping)
  • --mode (compact|json|md|context|path)
  • --timeout-ms
  • --output-dir
  • --ttl-hours
  • --use-cookies (true|false; bare flag means true)
  • --challenge-automation-mode (off|browser|browser_with_helper)
  • --cookie-policy-override (off|auto|required)
  • --cookie-policy (alias of --cookie-policy-override)

Notes:

  • Use explicit providers plus --browser-mode managed for the most reproducible live reruns.
  • Treat --region as advisory unless meta.selection.region_authoritative=true.
  • When a run returns no final offers, inspect meta.primaryConstraintSummary and meta.offerFilterDiagnostics before classifying the provider path as broken.

Product presentation asset (product-video run)

npx opendevbrowser product-video run --product-url "https://example.com/p/1" --include-screenshots
npx opendevbrowser product-video run --product-name "Sample Product" --provider-hint shopping/amazon --output-dir /tmp/product-assets

Flags:

  • --product-url (required unless --product-name is provided)
  • --product-name (required unless --product-url is provided)
  • --provider-hint
  • --include-screenshots (true|false; bare flag means true)
  • --include-all-images (true|false; bare flag means true)
  • --include-copy (true|false; bare flag means true)
  • --timeout-ms
  • --output-dir
  • --ttl-hours
  • --use-cookies (true|false; bare flag means true)
  • --challenge-automation-mode (off|browser|browser_with_helper)
  • --cookie-policy-override (off|auto|required)
  • --cookie-policy (alias of --cookie-policy-override)

Wrapper behavior:

  • Timebox semantics are strict (--days is mutually exclusive with --from/--to).
  • Render modes for research and shopping are shared: compact|json|md|context|path.
  • product-video run always returns a path-based local asset pack.
  • Path-bearing modes persist artifacts under the configured output directory (or default tmp namespace) and include TTL metadata in manifest files.
  • Workflow cookie policy defaults to providers.cookiePolicy=auto and source defaults to providers.cookieSource (file, env, or inline).
  • Effective policy precedence is --cookie-policy-override/--cookie-policy > --use-cookies > config defaults.
  • auto attempts injection when cookies are available and continues when cookies are missing/unusable.
  • required fails fast with reasonCode=auth_required when cookie loading/injection/verification cannot establish a session.
  • Workflow challenge automation defaults to providers.challengeOrchestration.mode.
  • Effective challenge precedence is challengeAutomationMode with run > session > config.
  • off keeps detection and reporting active but stands down challenge actions.
  • browser enables only browser-native lanes and forces the helper bridge to stand down.
  • browser_with_helper preserves browser-first lane ordering and only evaluates the browser-scoped helper bridge when hard gates pass.
  • The helper bridge is browser-scoped and is not a desktop agent.
  • Cookie diagnostics are exposed in workflow metrics under meta.metrics.cookie_diagnostics and meta.metrics.cookieDiagnostics.
  • Shopping providers that return zero usable offer records now emit meta.failures[*].error.reasonCode=env_limited instead of silently counting as success.

Artifact lifecycle cleanup

Use the artifact cleanup command to remove expired bundles generated by workflow runs:

npx opendevbrowser artifacts cleanup --expired-only
npx opendevbrowser artifacts cleanup --expired-only --output-dir /tmp/opendevbrowser

Script helper:

./scripts/artifacts-cleanup.sh
./scripts/artifacts-cleanup.sh /tmp/opendevbrowser

Notes:

  • --expired-only is required.
  • Default cleanup root is ${TMPDIR:-/tmp}/opendevbrowser.
  • Output includes removed and skipped run paths.

Run (single-shot script)

Run a JSON script without the daemon.

npx opendevbrowser run --script ./script.json --output-format json

# Or pipe JSON
cat ./script.json | npx opendevbrowser run --output-format stream-json

# Optional launch flags for run
npx opendevbrowser run --script ./script.json --headless --profile default --start-url https://example.com
npx opendevbrowser run --script ./script.json --chrome-path "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --flag "--disable-gpu"

Supported run launch flags:

  • --headless
  • --profile
  • --persist-profile
  • --chrome-path
  • --start-url
  • --flag (repeatable)

--chrome-path accepts Google Chrome, Chromium, or a Playwright-installed Chrome for Testing binary when you need a deterministic automation browser.

Script format:

[
  { "action": "goto", "args": { "url": "https://example.com" } },
  { "action": "snapshot" },
  { "action": "click", "args": { "ref": "r1" } }
]

Session commands (daemon required)

Launch

npx opendevbrowser launch --profile default --start-url https://example.com

# Extension relay controls
npx opendevbrowser launch --extension-only
npx opendevbrowser launch --no-extension
npx opendevbrowser launch --extension-legacy
npx opendevbrowser launch --wait-for-extension --wait-timeout-ms 30000

Flags:

  • --headless
  • --profile
  • --start-url
  • --chrome-path
  • --persist-profile
  • --flag (repeatable)
  • --no-extension
  • --extension-only
  • --extension-legacy
  • --wait-for-extension
  • --wait-timeout-ms

Default behavior:

  • Extension relay (extension mode) is the default when available, using the /ops WebSocket.
  • If the extension is not connected, launch fails with guidance and exact commands for the explicit alternatives.
  • Headless is never the default.
  • Extension headless is unsupported. launch --headless must be paired with --no-extension; extension-intent headless requests fail with unsupported_mode.
  • When hub mode is enabled, there is no local relay fallback. If the hub is unavailable, commands fail with guidance.
  • Extension relay requires Chrome 125+ (flat CDP sessions).
  • Managed and cdpConnect sessions automatically try to bootstrap readable cookies from the discovered system Chrome-family profile before first navigation. Extension mode reuses the already logged-in tab or profile instead of importing cookies.
  • For isolated automation harnesses that rely on browser startup flags such as --disable-extensions-except, prefer Chromium or Chrome for Testing. Google Chrome stable may ignore those flags.

Interactive vs non-interactive:

  • Interactive CLI (TTY): you will be prompted to connect the extension, then explicitly choose Managed or CDPConnect if you want to proceed.
  • Non-interactive (agents/CI): the command fails fast and prints the exact commands to run for Managed or CDPConnect.
  • If status --daemon shows ext=on but handshake=off, reopen the extension popup and click Connect again to re-establish a clean daemon-extension handshake before retrying extension-mode work.

Connection flags & status semantics

Flag / Status Meaning Notes
--no-extension Force managed mode Bypasses relay and extension entirely.
--extension-only Require extension mode Fails if extension is not connected/handshaken.
--extension-legacy Use legacy extension relay Routes through relay /cdp instead of /ops.
--wait-for-extension Wait for extension handshake Only applies to extension mode; waits up to --wait-timeout-ms.
--wait-timeout-ms Max wait for extension Defaults to 30s.
extensionConnected Extension websocket connected false means popup isn’t connected to relay.
extensionHandshakeComplete Extension handshake done false means reconnect/repair from popup.
annotationConnected Active /annotation client attached Expected false unless annotate relay transport is active.
opsConnected Active /ops client attached Presence-only signal; it does not prove the current extension target is owned by /ops.
canvasConnected Active /canvas client attached Expected false unless a design-canvas session is using relay preview/overlay features.
cdpConnected Active /cdp client attached Expected false until a legacy /cdp session connects.
pairingRequired Relay token required When true, /ops, /canvas, /annotation, and /cdp require a token (auto-fetched).

Connect

npx opendevbrowser connect --ws-endpoint ws://127.0.0.1:9222/devtools/browser/...
npx opendevbrowser connect --host 127.0.0.1 --cdp-port 9222

This command starts a cdpConnect session (attach to an existing Chrome with remote debugging enabled). If the --ws-endpoint points at the local relay (for example ws://127.0.0.1:8787 or ws://127.0.0.1:8787/ops), the CLI will normalize to /ops and route through the extension relay (extension mode). Use --extension-legacy if you need the legacy /cdp relay path. When routing through the relay, the CLI automatically fetches relay config and the pairing token (if required) and authenticates the /ops or /cdp connection. Direct relay websocket connections without a token are rejected when pairing is enabled. Direct cdpConnect sessions use the same automatic Chrome-family cookie bootstrap path as managed launches.

Relay binding queue

Hub binding is exclusive only for binding/legacy paths (for example /cdp and commands that require a binding). Additional clients are queued FIFO and wait up to 30s by default. If you see RELAY_WAIT_TIMEOUT, retry after the current binding expires or stop the other bound client.

Relay behavior note: extension uses a single extension websocket, while the relay can serve multiple /ops clients. Disconnecting the extension or restarting the relay drops active sessions, including annotation flows. Reconnect via the popup (or restart the daemon) before retrying.

Concurrency semantics

  • Transport-level concurrency: /ops supports multi-client access and multiple sessions.
  • Runtime scheduling uses ExecutionKey = (sessionId, targetId) with target-scoped queues.
  • Same target stays FIFO; different targets in one session run in parallel up to effectiveParallelCap.
  • session-per-worker remains the safest baseline for simple operational isolation, but in-session multi-target parallelism is supported on /ops, managed, and cdpConnect.
  • Use explicit --target-id routing for concurrent flows; treat target-use as ergonomic fallback only.
  • Use /ops as the default concurrent relay channel. Use --extension-legacy (/cdp) only for compatibility-specific paths.
  • Legacy /cdp does not coexist with an active /ops lease. If launch fails with cdp_attach_blocked, disconnect the /ops session and retry --extension-legacy.
  • Legacy /cdp stays sequential (effectiveParallelCap=1) by design.
  • For managed parallel launches with persisted profiles, use unique profile directories per session (or disable persistence) to avoid ProcessSingleton/SingletonLock collisions.
  • Parity divergences are registry-bound in docs/PARITY_DECLARED_DIVERGENCES.md.

Disconnect

npx opendevbrowser disconnect --session-id <session-id>
npx opendevbrowser disconnect --session-id <session-id> --close-browser

Status

npx opendevbrowser status               # daemon status (default)
npx opendevbrowser status --daemon      # daemon status (explicit)
npx opendevbrowser status --session-id <session-id>
npx opendevbrowser status --transport native

Cookie import

npx opendevbrowser cookie-import \
  --session-id <session-id> \
  --cookies '[{"name":"session","value":"abc123","url":"https://example.com"}]'

npx opendevbrowser cookie-import \
  --session-id <session-id> \
  --cookies-file ./cookies.json \
  --strict=false \
  --request-id req-cookie-001

Notes:

  • Provide exactly one cookies source: --cookies or --cookies-file.
  • --strict defaults to true.
  • Managed and cdpConnect sessions already attempt Chrome-family cookie bootstrap on session creation; use cookie-import when you need to add or override cookies explicitly.
  • Supported across managed, default extension /ops, extension legacy /cdp, and direct cdpConnect sessions.

Cookie list

npx opendevbrowser cookie-list \
  --session-id <session-id>

npx opendevbrowser cookie-list \
  --session-id <session-id> \
  --url https://example.com \
  --url https://shop.example.com \
  --request-id req-cookie-list-001

Notes:

  • --url is optional and repeatable; each value is normalized and deduplicated.
  • Supports managed, default extension /ops, extension legacy /cdp, and direct cdpConnect sessions.

Macro resolve

npx opendevbrowser macro-resolve --expression '@web.search("openai")'
npx opendevbrowser macro-resolve --expression '@social.post("x", "ship it")' --default-provider social/x --include-catalog
npx opendevbrowser macro-resolve --expression '@web.search("opendevbrowser")' --execute --output-format json
npx opendevbrowser macro-resolve --expression '@media.search("youtube transcript parity", "youtube", 5)' --execute --timeout-ms 120000 --output-format json
npx opendevbrowser macro-resolve --expression '@community.search("browser automation failures", 4)' --execute --challenge-automation-mode browser_with_helper --output-format json

Notes:

  • Default mode is resolve-only (returns the resolved action/provenance payload).
  • --execute runs the resolved provider action and returns additive execution metadata (meta.tier.selected, meta.tier.reasonCode, meta.provenance.provider, meta.provenance.retrievalPath, meta.provenance.retrievedAt).
  • --timeout-ms sets client-side daemon transport timeout for slow --execute runs.
  • --challenge-automation-mode is accepted for --execute runs and maps to challengeAutomationMode with the same run > session > config precedence as workflow commands.
  • opendevbrowser --help includes this timeout flag in the global flag inventory.

Blocker contract (v2)

Compatibility rule (v2):

  • Blocker fields are additive-only and live under meta.blocker (or execution.meta.blocker for macro-resolve --execute).
  • Existing success/error fields and codes remain unchanged.
  • Consumers should treat missing blocker fields as backward-compatible no blocker metadata.

Canonical placement:

  • goto: data.meta.blockerState + optional data.meta.blocker.
  • wait: data.meta.blockerState + optional data.meta.blocker.
  • debug-trace-snapshot: data.meta.blockerState + optional data.meta.blocker + optional data.meta.blockerArtifacts.
  • macro-resolve --execute: data.execution.meta.ok + optional data.execution.meta.blocker.
  • status: data.meta.blockerState + optional data.meta.blockerResolution (resolved | unresolved | deferred).

Canonical examples:

{
  "command": "goto",
  "success": true,
  "data": {
    "finalUrl": "https://example.com",
    "status": 200,
    "timingMs": 412,
    "meta": {
      "blockerState": "clear"
    }
  }
}
{
  "command": "goto",
  "success": true,
  "data": {
    "finalUrl": "https://x.com/i/flow/login",
    "status": 200,
    "timingMs": 588,
    "meta": {
      "blockerState": "active",
      "blocker": {
        "schemaVersion": "1.0",
        "type": "auth_required",
        "source": "navigation",
        "confidence": 0.97,
        "retryable": false
      }
    }
  }
}
{
  "command": "wait",
  "success": true,
  "data": {
    "timingMs": 221,
    "meta": {
      "blockerState": "clear"
    }
  }
}
{
  "command": "status",
  "success": true,
  "data": {
    "mode": "managed",
    "activeTargetId": "target-1",
    "url": "https://x.com/i/flow/login",
    "title": "Log in to X / X",
    "meta": {
      "blockerState": "active",
      "blockerResolution": {
        "status": "unresolved",
        "reason": "verification_timeout",
        "updatedAt": "2026-02-15T14:18:28.000Z"
      }
    }
  }
}
{
  "command": "wait",
  "success": true,
  "data": {
    "timingMs": 1470,
    "meta": {
      "blockerState": "active",
      "blocker": {
        "schemaVersion": "1.0",
        "type": "anti_bot_challenge",
        "source": "navigation",
        "confidence": 0.96,
        "retryable": false
      }
    }
  }
}
{
  "command": "debug-trace-snapshot",
  "success": true,
  "data": {
    "requestId": "req-debug-001",
    "meta": {
      "blockerState": "clear"
    }
  }
}
{
  "command": "debug-trace-snapshot",
  "success": true,
  "data": {
    "requestId": "req-debug-002",
    "meta": {
      "blockerState": "active",
      "blocker": {
        "schemaVersion": "1.0",
        "type": "anti_bot_challenge",
        "source": "network",
        "confidence": 0.96,
        "retryable": false
      },
      "blockerArtifacts": {
        "schemaVersion": "1.0",
        "hosts": ["www.recaptcha.net", "challenges.cloudflare.com"]
      }
    }
  }
}
{
  "command": "macro-resolve --execute",
  "success": true,
  "data": {
    "runtime": "macros",
    "execution": {
      "meta": {
        "ok": true,
        "partial": false
      }
    }
  }
}
{
  "command": "macro-resolve --execute",
  "success": true,
  "data": {
    "runtime": "macros",
    "execution": {
      "meta": {
        "ok": false,
        "partial": true,
        "blocker": {
          "schemaVersion": "1.0",
          "type": "env_limited",
          "source": "macro_execution",
          "confidence": 0.9,
          "retryable": true
        }
      }
    }
  }
}

Design Canvas

Use canvas to call the typed canvas.* surface through the daemon. The normal sequence is: canvas.session.open -> inspect the handshake -> canvas.plan.set -> canvas.document.patch (including governance.update blocks) -> canvas.preview.render or canvas.feedback.poll. Additional same-session clients use canvas.session.attach with attachMode=observer or attachMode=lease_reclaim. Unless params.repoRoot is provided explicitly, the CLI injects the caller cwd as the canvas session repo root. Relative canvas.document.save, canvas.document.export, and canvas.code.* paths resolve against that session root even when the daemon is launchd-owned or started from another working directory.

# Open a canvas session bound to an existing browser session
npx opendevbrowser canvas --command canvas.session.open \
  --params '{"browserSessionId":"<session-id>","documentId":"landing-page","mode":"dual-track"}' \
  --output-format json

# Submit a generation plan (required before patching)
npx opendevbrowser canvas --command canvas.plan.set --params-file ./canvas-plan.json --output-format json

# Apply a patch batch against a specific revision, including governance blocks required before save
npx opendevbrowser canvas --command canvas.document.patch \
  --params '{"canvasSessionId":"<canvas-session-id>","leaseId":"<lease-id>","baseRevision":1,"patches":[{"op":"governance.update","block":"intent","changes":{"summary":"Marketing landing page refresh"}},{"op":"governance.update","block":"designLanguage","changes":{"profile":"clean-room"}},{"op":"page.create","page":{"id":"page_home","rootNodeId":null,"name":"Home","path":"/","description":"Marketing landing page"}}]}' \
  --output-format json

# Save the canonical design document back into the repo
npx opendevbrowser canvas --command canvas.document.save \
  --params '{"canvasSessionId":"<canvas-session-id>","leaseId":"<lease-id>"}' \
  --output-format json

canvas.session.open returns a handshake with canvasSessionId, leaseId, governance block states, required generation-plan fields, runtime budgets, and warning classes. canvas.document.patch is blocked until canvas.plan.set succeeds. canvas.document.save and canvas.document.export return policy_violation until all requiredBeforeSave governance blocks are present. canvas.document.import now imports Figma file URLs, node URLs, or raw file-key inputs into the same lease-governed document surface; it resolves auth from FIGMA_ACCESS_TOKEN first and integrations.figma.accessToken second, caches image and SVG receipts under .opendevbrowser/canvas/assets/figma/<fileKey>/, records provenance in document.meta.imports[], and degrades variables/local failures with typed feedback (scope_denied, plan_limited, account_limited, or variables_unavailable) instead of opaque fatal errors. canvas.history.undo and canvas.history.redo are now public lease-governed mutations; they are unavailable before the first accepted-plan edit, require the active lease holder, and invalidate deterministically when document revision drift makes the recorded stack stale. In extension mode, canvas.tab.open opens an extension-hosted canvas.html infinite-canvas editor that persists full page state in IndexedDB, converges same-origin tabs through BroadcastChannel, forwards editor-originated patch requests through /canvas, exposes pages/layers/properties/history controls plus keyboard shortcuts, and keeps freeform region annotation scoped to the extension-hosted stage. canvas.feedback.poll remains the snapshot query for cursor-based audits, while canvas.feedback.subscribe, canvas.feedback.next, and canvas.feedback.unsubscribe now expose the public pull-stream contract. In stream-json mode, the CLI emits initialItems, then loops on canvas.feedback.next until feedback.complete or CLI timeout, and finally best-effort calls canvas.feedback.unsubscribe. canvas.inventory.list now returns the merged reusable inventory surface: document-backed promoted items plus the shipped built-in kit catalog entries. canvas.inventory.insert materializes either kind of inventory template back onto the stage as a governed mutation. canvas.starter.list exposes the eight shipped built-in starters, and canvas.starter.apply now seeds a generation plan when needed, merges built-in kit token collections, installs required kit inventory entries into the live document, and inserts a starter shell with semantic fallback when the requested framework or adapter is unavailable. For starter application, prefer libraryAdapterId when selecting or reading the resolved built-in kit adapter; the legacy adapterId field remains as a backward-compatible alias and is distinct from code-sync frameworkAdapterId. The public /canvas surface is now 35 commands. The tool wrapper stays thin and uses the same public opendevbrowser_canvas commands through repeated calls. canvas.code.bind, canvas.code.unbind, canvas.code.pull, canvas.code.push, canvas.code.status, and canvas.code.resolve add framework-adapter-backed code sync on top of the same session. Built-in lanes currently ship for builtin:react-tsx-v2, builtin:html-static-v1, builtin:custom-elements-v1, builtin:vue-sfc-v1, and builtin:svelte-sfc-v1; legacy tsx-react-v1 bindings and manifests migrate on load to builtin:react-tsx-v2 instead of failing ambiguously. Bound source manifests are stored under .opendevbrowser/canvas/code-sync/<documentId>/<bindingId>.json; preview targets default to projected canvas_html and only attempt bound_app_runtime reconciliation when the binding opts in and runtime bridge preflight succeeds. canvas.code.status returns frameworkAdapterId, frameworkId, sourceFamily, declared/granted capabilities, explicit denial entries, and deterministic reasonCode values such as framework_migrated, manifest_migrated, plugin_not_found, and plugin_load_failed. Repo-local BYO adapter plugins are discovered from workspace package.json, .opendevbrowser/canvas/adapters.json, and explicit local config declarations only; declaration-level capabilityOverrides narrow plugin capabilities rather than widening them. See docs/CANVAS_ADAPTER_PLUGIN_CONTRACT.md for the plugin manifest and trust model, and node scripts/canvas-competitive-validation.mjs --out <report.json> for the grouped canvas validator.

RPC (power-user, internal)

Execute any daemon command directly. This bypasses the stable CLI command surface, is intentionally unsafe/internal, and requires --unsafe-internal.

# Minimal call (empty params object)
npx opendevbrowser rpc --unsafe-internal --name relay.status --output-format json

# With inline JSON params
npx opendevbrowser rpc --unsafe-internal --name nav.goto \
  --params '{"sessionId":"<session-id>","url":"https://example.com","waitUntil":"load","timeoutMs":30000}' \
  --timeout-ms 45000 --output-format json

# With params from file
npx opendevbrowser rpc --unsafe-internal --name session.status --params-file ./rpc-params.json --output-format json

Notes:

  • Params must be a JSON object.
  • Use --output-format json for machine-readable responses.
  • rpc is CLI-only by design and is not part of the stable tool parity surface.
  • rpc command names/params are internal and may change without compatibility guarantees.
  • A bad rpc call can close sessions, navigate logged-in tabs, or trigger unintended side effects.
  • Prefer stable commands (goto, snapshot, click, type, and related tool equivalents) whenever possible.
  • Use rpc only when necessary, validate params carefully, and test in a disposable session first.

Navigation commands (daemon required)

Goto

npx opendevbrowser goto --session-id <session-id> --url https://example.com
npx opendevbrowser goto --session-id <session-id> --url https://example.com --wait-until load --timeout-ms 30000

Wait

npx opendevbrowser wait --session-id <session-id> --until load
npx opendevbrowser wait --session-id <session-id> --ref r12 --state visible --timeout-ms 15000

Snapshot

npx opendevbrowser snapshot --session-id <session-id>
npx opendevbrowser snapshot --session-id <session-id> --max-chars 16000 --cursor <cursor>

Review

Use review as the explicit snapshot -> review -> action step when you want the active target summary plus a fresh actionables capture in one response.

npx opendevbrowser review --session-id <session-id>
npx opendevbrowser review --session-id <session-id> --target-id <target-id> --max-chars 16000 --cursor <cursor>

Interaction commands (daemon required)

Click

npx opendevbrowser click --session-id <session-id> --ref r12 [--timeout-ms <ms>]

Notes:

  • --timeout-ms sets the client-side daemon timeout for the click request.
  • Without --timeout-ms, click uses a 60s client-side daemon timeout so blocking browser dialogs can be inspected and handled without the opener expiring immediately.

Hover

npx opendevbrowser hover --session-id <session-id> --ref r12

Press

npx opendevbrowser press --session-id <session-id> --key Enter
npx opendevbrowser press --session-id <session-id> --key Enter --ref r12

Check / Uncheck

npx opendevbrowser check --session-id <session-id> --ref r12
npx opendevbrowser uncheck --session-id <session-id> --ref r12

Type

npx opendevbrowser type --session-id <session-id> --ref r12 --text "hello"
npx opendevbrowser type --session-id <session-id> --ref r12 --text "hello" --clear --submit

Select

npx opendevbrowser select --session-id <session-id> --ref r12 --values value1,value2

Scroll

npx opendevbrowser scroll --session-id <session-id> --dy 500
npx opendevbrowser scroll --session-id <session-id> --ref r12 --dy 300

Scroll into view

npx opendevbrowser scroll-into-view --session-id <session-id> --ref r12

Upload

npx opendevbrowser upload --session-id <session-id> --ref r12 --files ./avatar.png
npx opendevbrowser upload --session-id <session-id> --target-id <target-id> --ref r12 --files ./front.png,./back.png

Notes:

  • --files accepts a comma-separated list of host file paths.
  • Upload resolves the target from the existing ref model and reports mode as direct_input or file_chooser.

Annotation (direct + relay)

Annotations are available through both the CLI command and the opendevbrowser_annotate tool. The default transport (auto) uses direct CDP when possible and falls back to relay in extension sessions. annotate --stored resolves the shared repo-local agent inbox first, then the extension-local stored payload fallback. See docs/ANNOTATE.md for setup and details.

npx opendevbrowser annotate --session-id <session-id>

# Force direct annotate on a target
npx opendevbrowser annotate --session-id <session-id> --transport direct --target-id <target-id>

# Force relay annotate on a specific tab
npx opendevbrowser annotate --session-id <session-id> --transport relay --tab-id 123

# With URL + context + debug metadata
npx opendevbrowser annotate --session-id <session-id> --url https://example.com \
  --screenshot-mode visible --context "Review the hero layout" --timeout-ms 90000 --debug

# Return the last stored annotation payload
npx opendevbrowser annotate --session-id <session-id> --stored

# Prefer the extension-local in-memory stored payload with screenshots when still available
npx opendevbrowser annotate --session-id <session-id> --stored --include-screenshots

Target commands (daemon required)

Targets list

npx opendevbrowser targets-list --session-id <session-id>
npx opendevbrowser targets-list --session-id <session-id> --include-urls

Target use

npx opendevbrowser target-use --session-id <session-id> --target-id <target-id>

Target new

npx opendevbrowser target-new --session-id <session-id> --url https://example.com

Target close

npx opendevbrowser target-close --session-id <session-id> --target-id <target-id>

Page commands (daemon required)

Page open

npx opendevbrowser page --session-id <session-id> --name main
npx opendevbrowser page --session-id <session-id> --name main --url https://example.com

Pages list

npx opendevbrowser pages --session-id <session-id>

Page close

npx opendevbrowser page-close --session-id <session-id> --name main

DOM commands (daemon required)

DOM HTML

npx opendevbrowser dom-html --session-id <session-id> --ref r12 --max-chars 8000

DOM Text

npx opendevbrowser dom-text --session-id <session-id> --ref r12 --max-chars 8000

DOM Attribute

npx opendevbrowser dom-attr --session-id <session-id> --ref r12 --attr aria-label

DOM Value

npx opendevbrowser dom-value --session-id <session-id> --ref r12

DOM State Checks

npx opendevbrowser dom-visible --session-id <session-id> --ref r12
npx opendevbrowser dom-enabled --session-id <session-id> --ref r12
npx opendevbrowser dom-checked --session-id <session-id> --ref r12

Export commands (daemon required)

Clone page

npx opendevbrowser clone-page --session-id <session-id>

Clone component

npx opendevbrowser clone-component --session-id <session-id> --ref r12

Devtools commands (daemon required)

Performance metrics

npx opendevbrowser perf --session-id <session-id>

Screenshot

npx opendevbrowser screenshot --session-id <session-id>
npx opendevbrowser screenshot --session-id <session-id> --path ./capture.png
npx opendevbrowser screenshot --session-id <session-id> --ref r12
npx opendevbrowser screenshot --session-id <session-id> --full-page
npx opendevbrowser screenshot --session-id <session-id> --path ./capture.png --timeout-ms 60000

Notes:

  • --ref and --full-page are mutually exclusive.
  • --timeout-ms sets client-side daemon timeout for screenshot capture.
  • Default visible capture may still report the existing viewport-only fallback warning when extension capture has to degrade, but ref and full-page requests do not silently reuse that fallback.

Dialog

npx opendevbrowser dialog --session-id <session-id>
npx opendevbrowser dialog --session-id <session-id> --action dismiss
npx opendevbrowser dialog --session-id <session-id> --action accept --prompt-text "Ship it"

Notes:

  • --action supports status, accept, and dismiss.
  • --prompt-text is only valid when --action accept is used for a prompt dialog.
  • --timeout-ms sets the client-side daemon timeout for the dialog request.
  • Without --timeout-ms, dialog uses a 30s client-side daemon timeout.

Console poll

npx opendevbrowser console-poll --session-id <session-id> --since-seq 0 --max 50

Network poll

npx opendevbrowser network-poll --session-id <session-id> --since-seq 0 --max 50

Debug trace snapshot

npx opendevbrowser debug-trace-snapshot --session-id <session-id>
npx opendevbrowser debug-trace-snapshot \
  --session-id <session-id> \
  --since-console-seq 100 \
  --since-network-seq 80 \
  --since-exception-seq 10 \
  --max 200 \
  --request-id req-debug-001

Session inspector

npx opendevbrowser session-inspector --session-id <session-id>
npx opendevbrowser session-inspector \
  --session-id <session-id> \
  --include-urls \
  --since-console-seq 100 \
  --since-network-seq 80 \
  --since-exception-seq 10 \
  --max 50 \
  --request-id req-session-inspector-001

Notes:

  • Returns session status, relay health, target summary, proof artifact metadata, healthState, and a suggested next action in one payload.
  • --include-urls keeps target URLs in the target summary. Omit it to use the default runtime behavior.
  • --since-console-seq, --since-network-seq, --since-exception-seq, and --max mirror the trace cursors used by debug-trace-snapshot.

Flags reference

Global flags

Flag Short Description
--global -g Install to ~/.config/opencode/opencode.json
--local -l Install to ./opencode.json
--update -u Clear cache to trigger reinstall
--uninstall Remove plugin from config
--with-config Also create opendevbrowser.jsonc
--full -f Create config and pre-extract extension assets
--no-prompt Skip prompts, use defaults
--no-interactive Alias of --no-prompt
--quiet Suppress output
--output-format text, json, or stream-json
--transport Transport selector for transport-aware commands (status: `relay
--daemon Daemon status selector for status
--skills-global Install skills to global OpenCode/Codex/ClaudeCode/AmpCLI directories (legacy claude/amp aliases also synced)
--skills-local Install skills to project-local OpenCode/Codex/ClaudeCode/AmpCLI directories (legacy claude/amp aliases also synced)
--no-skills Skip installing bundled skills
--help -h Show usage information
--version -v Show version number

Serve flags

Flag Description
--port Override daemon port
--token Override daemon token
--stop Stop the daemon

Command-specific flags

Session + connection

Flag Used by Description
--session-id most daemon commands Active session id from launch/connect
--close-browser disconnect Close managed browser on disconnect
--ws-endpoint connect Remote debugging websocket URL
--host connect Host for CDP connection (--cdp-port required)
--cdp-port connect CDP port for host-based connect
--daemon status Force daemon status mode (mutually exclusive with --session-id)
--no-extension launch Force managed mode (ignore extension)
--extension-only launch Fail if extension not connected
--extension-legacy launch, connect Use legacy extension relay (/cdp)
--wait-for-extension launch Wait for extension handshake
--wait-timeout-ms launch Max wait for extension handshake
--cookies cookie-import Inline JSON array of cookie objects
--cookies-file cookie-import Path to JSON file containing cookie objects
--strict cookie-import Reject on invalid cookie entries (true/false)
--request-id cookie-import, cookie-list, debug-trace-snapshot, session-inspector Optional request correlation id
--expression macro-resolve Macro expression to resolve
--default-provider macro-resolve Provider fallback for shorthand macros
--include-catalog macro-resolve Include macro catalog in response
--execute macro-resolve Execute the resolved provider action and include additive meta.* fields
--timeout-ms macro-resolve Client-side daemon call timeout in ms
--use-cookies research run, shopping run, product-video run Enable/disable provider cookie injection for the run (`true
--challenge-automation-mode research run, shopping run, product-video run, macro-resolve --execute Per-run challenge automation override stored as challengeAutomationMode (`off
--cookie-policy-override research run, shopping run, product-video run Per-run provider cookie policy override (`off
--cookie-policy research run, shopping run, product-video run Alias of --cookie-policy-override

Browser launch (launch/run)

Flag Used by Description
--headless launch, run Run managed Chrome headless
--profile launch, run Profile directory name
--persist-profile launch, run Keep profile directory after run
--chrome-path launch, run Explicit Chrome executable path
--start-url launch, run Initial URL for the session
--flag launch, run Additional Chrome flag (repeatable)
--script run JSON script path

Navigation + waiting

Flag Used by Description
--url goto, page, target-new, cookie-list URL to navigate/open or filter cookie listing
--wait-until goto Load state (load, domcontentloaded, etc.)
--timeout-ms goto, wait, review Timeout in ms
--ref wait Element ref to wait for
--state wait Element state (e.g. visible)
--until wait Page load state
--mode snapshot Snapshot mode (outline or actionables)
--target-id review Optional target override for the review payload
--max-chars snapshot, review, dom-* Max characters returned
--cursor snapshot, review Snapshot pagination cursor

Annotation

Flag Used by Description
--transport annotate auto (default), direct, or relay
--target-id annotate Target id for direct annotate
--tab-id annotate Chrome tab id for relay annotate
--screenshot-mode annotate visible (default), full, or none
--include-screenshots annotate When used with --stored, prefer the in-memory payload that still includes screenshots if available
--context annotate Optional context text pre-filled in the UI
--debug annotate Include debug metadata in the payload
--stored annotate Return the last stored annotation payload for the session
--timeout-ms annotate Annotation timeout in ms

Canvas

Flag Used by Description
--command canvas canvas.* command name (for example canvas.session.open)
--params canvas Inline JSON object command params
--params-file canvas Path to JSON object command params
--timeout-ms canvas Client-side daemon call timeout in ms

RPC (internal)

Flag Used by Description
--unsafe-internal rpc Required opt-in acknowledging unsafe/internal RPC execution (power-user only)
--name rpc Daemon command name (for example relay.status)
--params rpc Inline JSON object command params
--params-file rpc Path to JSON object params file
--timeout-ms rpc Client-side daemon call timeout in ms

Interaction

Flag Used by Description
--ref element commands Element ref from snapshot
--timeout-ms click Client-side daemon call timeout in ms; defaults to 60s
--text type Text to type
--clear type Clear input before typing
--submit type Submit after typing
--values select Comma-separated values
--files upload Comma-separated file paths for upload
--dy scroll Scroll delta on Y axis
--key press Keyboard key name (e.g. Enter)

Targets + pages

Flag Used by Description
--target-id target-use, target-close Target id from targets-list
--include-urls targets-list, session-inspector Include URLs in target or session-inspector target-list output
--name page, page-close Named page identifier

Devtools

Flag Used by Description
--attr dom-attr Attribute name to read
--path screenshot Output file path
--ref screenshot Capture an element screenshot by ref
--full-page screenshot Capture the full scrollable page
--action dialog Dialog action: status, accept, or dismiss
--prompt-text dialog Prompt text to submit when accepting a prompt dialog
--timeout-ms screenshot Explicit client-side daemon call timeout in ms
--timeout-ms dialog Client-side daemon call timeout in ms; defaults to 30s
--since-seq console-poll, network-poll Start sequence number
--since-console-seq debug-trace-snapshot, session-inspector Resume cursor for console channel
--since-network-seq debug-trace-snapshot, session-inspector Resume cursor for network channel
--since-exception-seq debug-trace-snapshot, session-inspector Resume cursor for exception channel
--max console-poll, network-poll, debug-trace-snapshot, session-inspector Max events to return per channel

CLI smoke test

Run the automated CLI coverage script (managed mode):

npm run build
node scripts/cli-smoke-test.mjs

The script uses temporary config/cache directories and exercises all CLI commands, including the new interaction and DOM state checks. Validate extension mode separately with launch + disconnect while the extension is connected.

Direct live regression harness

Run the direct scenario pack instead of the old broad matrix:

npm run build
node scripts/live-regression-direct.mjs

What it runs:

  • scripts/cli-smoke-test.mjs
  • scripts/canvas-live-workflow.mjs --surface managed-headless
  • scripts/canvas-live-workflow.mjs --surface managed-headed
  • scripts/canvas-live-workflow.mjs --surface extension
  • scripts/canvas-live-workflow.mjs --surface cdp
  • scripts/annotate-live-probe.mjs --transport relay
  • scripts/annotate-live-probe.mjs --transport direct

Strict release gate mode:

node scripts/live-regression-direct.mjs --release-gate --out artifacts/release/vX.Y.Z/live-regression-direct.json

Behavior:

  • Runs each scenario as an explicit child script with its own artifact instead of a nested matrix.
  • Prints per-step progress so long runs do not idle silently.
  • Fails on any direct scenario failure in --release-gate mode.
  • Records infra.daemon_status as an initial preflight snapshot before child scenarios run. If a later child script repairs native messaging state, rerun opendevbrowser status --daemon --output-format json after the pack for final daemon/native truth.
  • Uses temporary managed profiles for the managed canvas surfaces and the direct annotate probe so persisted-profile locks do not contaminate release runs.
  • Waits for /ops ownership to drain before the legacy /cdp scenario so extension-backed CDP attach does not race a prior extension canvas run.
  • Treats manual annotation timeout boundaries as skipped in --release-gate mode instead of misreporting them as runtime failures.
  • Requires a healthy daemon and a connected extension before running extension or CDP scenarios.

Direct provider runs

Run provider-by-provider live checks:

npm run build
node scripts/provider-direct-runs.mjs --out /tmp/odb-provider-direct-runs.json

Strict release gate mode:

npm run build
node scripts/provider-direct-runs.mjs --release-gate --out artifacts/release/vX.Y.Z/provider-direct-runs.json

Smoke mode:

npm run build
node scripts/provider-direct-runs.mjs --smoke --out /tmp/odb-provider-direct-runs-smoke.json

What it covers:

  • Web/default direct search and fetch probes.
  • Community/default direct search probes.
  • Social/search and shopping/provider probes through the same direct CLI entrypoints used in real runs.
  • Generic timeout outcomes stay visible as fail; env_limited is reserved for explicit environment/capability boundaries such as auth walls, browser-required shells, or challenge pages.
  • Social platform search probes for every registered platform in src/providers/social/index.ts.
  • Shopping provider runs for every registered shopping provider in src/providers/shopping/index.ts.
  • Optional social post probes for explicitly requested write-path validation.

Key options:

  • --include-auth-gated includes auth-dependent provider scenarios.
  • --include-high-friction includes high-friction shopping providers.
  • --include-social-posts includes social post scenarios.
  • --use-global-env is kept as a compatibility flag; direct runs already use the current environment.
  • --release-gate enables auth-gated + high-friction + social-post cases and fails on any non-pass status.

Run contract parity and skill-asset gates as part of release checks:

npm run test -- tests/parity-matrix.test.ts
npm run test -- tests/providers-performance-gate.test.ts
./skills/opendevbrowser-best-practices/scripts/validate-skill-assets.sh

These commands are release guards, not the live release-proof lane. Use the direct-run harness commands above for release evidence.

Release gate source of truth: docs/RELEASE_RUNBOOK.md and docs/RELEASE_0.0.17_EVIDENCE.md. Benchmark fixture manifest: docs/benchmarks/provider-fixtures.md.


Extension-only manual test (no OpenCode plugin)

Use this to validate the Chrome extension + relay without starting OpenCode.

  1. Ensure the daemon is running: npx opendevbrowser serve (manual). opendevbrowser daemon install configures auto-start on supported platforms from a stable install location; for this manual test, use npx opendevbrowser serve as the explicit start command for the current session.
  2. Build and load the extension: npm run extension:build, then Chrome → chrome://extensions → Developer mode → Load unpacked → extension/.
  3. Open a normal http(s) tab (not chrome:// or extension pages).
  4. Open the extension popup, confirm Auto-connect + Auto-pair are ON, click Connect.
  5. Verify the popup shows Connected and npx opendevbrowser status --daemon reports extensionConnected: true and extensionHandshakeComplete: true.
  6. Optional session check: npx opendevbrowser launch --extension-only --wait-for-extension, then npx opendevbrowser disconnect --session-id <id>.
  7. Optional annotation check (OpenCode): call opendevbrowser_annotate and confirm screenshots are written to a temp folder.

If it fails, run npx opendevbrowser serve --stop then npx opendevbrowser serve, and confirm site access includes http://127.0.0.1/* and http://localhost/* in the extension settings.

Configuration files

OpenCode config

The CLI modifies opencode.json to register the plugin:

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["opendevbrowser"]
}

Locations:

  • Global: ~/.config/opencode/opencode.json
  • Local: ./opencode.json

Plugin config (optional)

When using --with-config, a opendevbrowser.jsonc is created with documented defaults:

{
  "headless": false,
  "profile": "default",
  "persistProfile": true,
  "snapshot": { "maxChars": 16000, "maxNodes": 1000 },
  "export": { "maxNodes": 1000, "inlineStyles": true },
  "devtools": { "showFullUrls": false, "showFullConsole": false },
  "security": {
    "allowRawCDP": false,
    "allowNonLocalCdp": false,
    "allowUnsafeExport": false
  },
  "skillPaths": [],
  "skills": {
    "nudge": {
      "enabled": true,
      "keywords": ["quick start", "getting started", "launch", "connect", "setup"],
      "maxAgeMs": 60000
    }
  },
  "continuity": {
    "enabled": true,
    "filePath": "opendevbrowser_continuity.md",
    "nudge": {
      "enabled": true,
      "keywords": ["plan", "multi-step", "long-running", "refactor", "migration", "rollout", "continue"],
      "maxAgeMs": 60000
    }
  },
  "providers": {
    "antiBotPolicy": {
      "enabled": true,
      "cooldownMs": 30000,
      "maxChallengeRetries": 1,
      "allowBrowserEscalation": true
      // "proxyHint": "residential_pool_a",
      // "sessionHint": "warm_profile"
    },
    "transcript": {
      "modeDefault": "auto",
      "strategyOrder": ["youtubei", "native_caption_parse", "ytdlp_audio_asr", "apify"],
      "enableYtdlp": false,
      "enableAsr": false,
      "enableYtdlpAudioAsr": true,
      "enableApify": true,
      "apifyActorId": "streamers/youtube-scraper",
      "enableBrowserFallback": false,
      "ytdlpTimeoutMs": 10000
    }
  },
  "desktop": {
    "permissionLevel": "off",
    "commandTimeoutMs": 10000,
    "auditArtifactsDir": ".opendevbrowser/desktop-runtime",
    "accessibilityMaxDepth": 2,
    "accessibilityMaxChildren": 25
  },
  "daemonPort": 8788,
  "daemonToken": "auto-generated-on-first-run",
  "flags": [],
  "checkForUpdates": false
}

The optional skills.nudge section controls the small one-time prompt hint that encourages early skill(...) usage on skill-relevant tasks. The optional continuity section controls the long-running task nudge and the ledger file path. Fingerprint runtime defaults are Tier 1/2/3 enabled, with Tier 2 and Tier 3 driven by continuous signals (debug trace remains readout/reporting). Provider runtime anti-bot/transcript controls default to a public-first YouTube resolver chain:

  • Transcript mode semantics: auto | web | no-auto | yt-dlp | apify.
  • Request filter precedence is filters.youtube_mode > providers.transcript.modeDefault > auto.
  • No CLI mode flag is introduced in this phase; mode is configured in providers.transcript.modeDefault or per-request youtube_mode filter.
  • Auto mode fallback chain is youtubei -> native_caption_parse -> ytdlp_audio_asr -> apify.
  • yt-dlp audio transcription requires providers.transcript.enableYtdlpAudioAsr=true.
  • Apify requires providers.transcript.enableApify=true, a valid APIFY_TOKEN, and legal checklist approval for apify.
  • Browser-assisted fallback is opt-in only and requires providers.transcript.enableBrowserFallback=true plus providers.antiBotPolicy.allowBrowserEscalation=true.
  • If browser fallback is enabled, run it in an isolated automation profile instead of a daily logged-in Google profile.

Provider workflow and execution outputs now include normalized transcript/anti-bot telemetry:

  • Primary provider follow-up summary: meta.primaryConstraintSummary.
  • Failure reason codes: meta.metrics.reasonCodeDistribution for research/shopping, meta.reasonCodeDistribution for product-video, and reasonCode on provider failures.
  • Transcript fallback diagnostics: meta.metrics.transcript_strategy_failures (legacy) and meta.metrics.transcriptStrategyFailures (camelCase alias).
  • Strategy-detail diagnostics: meta.metrics.transcript_strategy_detail_failures/meta.metrics.transcriptStrategyDetailFailures and meta.metrics.transcript_strategy_detail_distribution/meta.metrics.transcriptStrategyDetailDistribution.
  • Durability/pressure dimensions: meta.metrics.transcriptDurability and meta.metrics.antiBotPressure (snake_case aliases are also emitted).
  • YouTube fetch metadata: transcript_strategy (legacy bucket), transcript_strategy_detail (exact strategy), attempt_chain, and failure reasonCode when transcript retrieval is unavailable.

Provider reliability criteria (resolver/browser fallback):

  • npm run test -- tests/providers-performance-gate.test.ts must pass.
  • Latest observation window must satisfy meta.metrics.transcriptDurability.attempted >= 10 and meta.metrics.transcriptDurability.success_rate >= 0.85.
  • Latest observation window must satisfy meta.metrics.antiBotPressure.anti_bot_failure_ratio <= 0.15.
  • Trigger remediation immediately if either condition fails in two consecutive windows.