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-gateTreat 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.
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 --versioncd <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 helpLoad 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/cacheBy 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-globaland--skills-localsync the 9 canonicalopendevbrowser-*packs underskills/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
researchorshoppingleftovers 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.
The skill loader discovers skills in this order (first match wins):
- Project-local:
./.opencode/skill - Global:
~/.config/opencode/skill(or$OPENCODE_CONFIG_DIR/skill) - Compatibility (project):
./.codex/skills - Compatibility (global):
$CODEX_HOME/skills(fallback~/.codex/skills) - Compatibility (project):
./.claude/skills - Compatibility (global):
$CLAUDECODE_HOME/skillsor$CLAUDE_HOME/skills(fallback~/.claude/skills) - Compatibility (project):
./.amp/skills - Compatibility (global):
$AMPCLI_HOME/skillsor$AMP_CLI_HOME/skillsor$AMP_HOME/skills(fallback~/.amp/skills) - Extra paths from
skillPaths(advanced) - Bundled package fallback: packaged
skills/directory afterskillPathswhen no installed copy matches
Use --output-format to switch output formats for automation.
text(default): human-friendly outputjson: single JSON objectstream-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.
0: success1: 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 }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
Canonical inventory document: docs/SURFACE_REFERENCE.md.
- 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).
- 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.
/ops(default extension channel): high-level command protocol; seedocs/SURFACE_REFERENCE.mdfor all59command names./canvas(design-canvas channel): typed design-canvas protocol; seedocs/SURFACE_REFERENCE.mdfor all35command names and envelope contracts./cdp(legacy): low-levelforwardCDPCommandrelay path with explicit opt-in (--extension-legacy).
- Managed and
/ops-backed manager responses preserve the shipped blocker fieldsmeta.blocker,meta.blockerState, andmeta.blockerResolution, and may append additivemeta.challengeplusmeta.challengeOrchestration. - Browser-assisted provider fallback reports explicit transport
disposition:completed,challenge_preserved,deferred, orfailed. When bounded challenge orchestration runs during fallback, decision evidence is recorded indetails.challengeOrchestration. - Workflow and daemon callers can set
challengeAutomationModetooff,browser, orbrowser_with_helper. Effective precedence isrun > session > config. - Shipped config defaults now resolve to
providers.challengeOrchestration.mode = browser_with_helperandproviders.challengeOrchestration.optionalComputerUseBridge.enabled = true. meta.challengeOrchestrationand fallbackdetails.challengeOrchestrationcan exposemode,source,standDownReason, andhelperEligibilityso stand-down decisions stay explicit.ProviderRegistryis the only durable anti-bot pressure authority used by policy, runtime routing, and workflow summaries. Provider modules only contribute extraction logic and optionalrecoveryHints().- 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.
browserkeeps it disabled andbrowser_with_helperonly 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 bychallengeAutomationMode, 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.
# 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-skillsOn 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.
Clear the OpenCode cache to trigger reinstallation of the latest version.
npx opendevbrowser --update
npx opendevbrowser -uThis removes cached files from ~/.cache/opencode/node_modules/opendevbrowser/. OpenCode will download the latest version on next run.
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 --uninstallnpx 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 Startblock that tells agents to start withopendevbrowser_prompting_guideoropendevbrowser_skill_load opendevbrowser-best-practices "quick start"before low-level browser commands. - A follow-up
validated_lanesentry that points agents toopendevbrowser_skill_load opendevbrowser-best-practices "validated capability lanes"for the current reliable transcript, research, and shopping runbook. - A direct pointer to
opendevbrowser_skill_listwhen 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, anddocs/SURFACE_REFERENCE.md.
Operational help parity check:
npx opendevbrowser --help
npx opendevbrowser helpFirst-run proof lane:
node scripts/cli-onboarding-smoke.mjsStart 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 --stopThe 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.
# Start the daemon manually
npx opendevbrowser serve
# Stop/kill an existing daemon before restarting
npx opendevbrowser serve --stopInstall 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 installBehavior:
- macOS: LaunchAgent at
~/Library/LaunchAgents/com.opendevbrowser.daemon.plisttargeting an absolutenode + cli + serveentrypoint. - Windows: per-user Task Scheduler logon task targeting an absolute
node + cli + serveentrypoint; status inspects the persisted scheduled-task action from Task Scheduler XML instead of task presence alone. daemon status --output-format jsonkeeps top-levelinstalledandrunning, adds nestedautostarton supported platforms, and includesstatusonly when the daemon is running.autostartis the canonical detail object and includeshealth,needsRepair,reason,command, andexpectedCommand.autostart.reasoncan betransient_cli_pathwhen 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";expectedCommandis omitted instead of advertising the transient current path as the repair target. daemon statusreturns exit code0when the daemon is reachable even if auto-start is missing, stale, or malformed, and10when the daemon is not running.- Successful plugin installs surface auto-start reconciliation through
autostartAction;autostartErroris 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 rerunopendevbrowser daemon installfrom a stable install location.
Exit codes align with the CLI:
0: success1: usage error2: execution error (permissions, missing binary, OS service failure, unsupporteddaemon install|uninstall, or unexpected status evaluation failure)10: disconnected/not running (status only)
# 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 --stopIf 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.
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 uninstallNotes:
- Supported on macOS, Linux, and Windows.
- Windows install writes a registry entry under
HKCU\Software\Google\Chrome\NativeMessagingHosts\com.opendevbrowser.native. native installrequires the extension ID (chrome://extensions → copy ID).- Set
nativeExtensionIdinopendevbrowser.jsoncto allowserveto auto-install the native host when missing (preferred). servealso attempts auto-detection from Chrome, Brave, or Chromium profiles, but explicit config is more reliable.native statusreports installed state + extension ID from the manifest.- Use
--transport nativewithstatusto check native host status without requiring the daemon.
The workflow wrappers expose the finalized research/shopping/product-video surfaces from
docs/RESEARCH_SHOPPING_PRODUCT_VIDEO_FINAL_SPEC.md.
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 contextFlags:
--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 meanstrue)--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 autofor generic topical research. - In the current contract,
autoandallboth stay inside the public topical families (web,community,social). - Add shopping only with
--source-selection shoppingor explicit--sources ...shopping...when the task is deliberately commercial.
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 jsonFlags:
--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 meanstrue)--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 managedfor the most reproducible live reruns. - Treat
--regionas advisory unlessmeta.selection.region_authoritative=true. - When a run returns no final offers, inspect
meta.primaryConstraintSummaryandmeta.offerFilterDiagnosticsbefore classifying the provider path as broken.
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-assetsFlags:
--product-url(required unless--product-nameis provided)--product-name(required unless--product-urlis provided)--provider-hint--include-screenshots(true|false; bare flag meanstrue)--include-all-images(true|false; bare flag meanstrue)--include-copy(true|false; bare flag meanstrue)--timeout-ms--output-dir--ttl-hours--use-cookies(true|false; bare flag meanstrue)--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 (
--daysis mutually exclusive with--from/--to). - Render modes for
researchandshoppingare shared:compact|json|md|context|path. product-video runalways 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=autoand source defaults toproviders.cookieSource(file,env, orinline). - Effective policy precedence is
--cookie-policy-override/--cookie-policy>--use-cookies> config defaults. autoattempts injection when cookies are available and continues when cookies are missing/unusable.requiredfails fast withreasonCode=auth_requiredwhen cookie loading/injection/verification cannot establish a session.- Workflow challenge automation defaults to
providers.challengeOrchestration.mode. - Effective challenge precedence is
challengeAutomationModewithrun > session > config. offkeeps detection and reporting active but stands down challenge actions.browserenables only browser-native lanes and forces the helper bridge to stand down.browser_with_helperpreserves 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_diagnosticsandmeta.metrics.cookieDiagnostics. - Shopping providers that return zero usable offer records now emit
meta.failures[*].error.reasonCode=env_limitedinstead of silently counting as success.
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/opendevbrowserScript helper:
./scripts/artifacts-cleanup.sh
./scripts/artifacts-cleanup.sh /tmp/opendevbrowserNotes:
--expired-onlyis required.- Default cleanup root is
${TMPDIR:-/tmp}/opendevbrowser. - Output includes
removedandskippedrun paths.
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" } }
]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 30000Flags:
--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 (
extensionmode) is the default when available, using the/opsWebSocket. - 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 --headlessmust be paired with--no-extension; extension-intent headless requests fail withunsupported_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
cdpConnectsessions 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 --daemonshowsext=onbuthandshake=off, reopen the extension popup and click Connect again to re-establish a clean daemon-extension handshake before retrying extension-mode work.
| 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). |
npx opendevbrowser connect --ws-endpoint ws://127.0.0.1:9222/devtools/browser/...
npx opendevbrowser connect --host 127.0.0.1 --cdp-port 9222This 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.
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.
- Transport-level concurrency:
/opssupports 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-workerremains the safest baseline for simple operational isolation, but in-session multi-target parallelism is supported on/ops, managed, andcdpConnect.- Use explicit
--target-idrouting for concurrent flows; treattarget-useas ergonomic fallback only. - Use
/opsas the default concurrent relay channel. Use--extension-legacy(/cdp) only for compatibility-specific paths. - Legacy
/cdpdoes not coexist with an active/opslease. If launch fails withcdp_attach_blocked, disconnect the/opssession and retry--extension-legacy. - Legacy
/cdpstays 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.
npx opendevbrowser disconnect --session-id <session-id>
npx opendevbrowser disconnect --session-id <session-id> --close-browsernpx opendevbrowser status # daemon status (default)
npx opendevbrowser status --daemon # daemon status (explicit)
npx opendevbrowser status --session-id <session-id>
npx opendevbrowser status --transport nativenpx 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-001Notes:
- Provide exactly one cookies source:
--cookiesor--cookies-file. --strictdefaults totrue.- Managed and
cdpConnectsessions already attempt Chrome-family cookie bootstrap on session creation; usecookie-importwhen you need to add or override cookies explicitly. - Supported across
managed, default extension/ops, extension legacy/cdp, and directcdpConnectsessions.
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-001Notes:
--urlis optional and repeatable; each value is normalized and deduplicated.- Supports
managed, default extension/ops, extension legacy/cdp, and directcdpConnectsessions.
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 jsonNotes:
- Default mode is resolve-only (returns the resolved action/provenance payload).
--executeruns 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-mssets client-side daemon transport timeout for slow--executeruns.--challenge-automation-modeis accepted for--executeruns and maps tochallengeAutomationModewith the samerun > session > configprecedence as workflow commands.opendevbrowser --helpincludes this timeout flag in the global flag inventory.
Compatibility rule (v2):
- Blocker fields are additive-only and live under
meta.blocker(orexecution.meta.blockerformacro-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+ optionaldata.meta.blocker.wait:data.meta.blockerState+ optionaldata.meta.blocker.debug-trace-snapshot:data.meta.blockerState+ optionaldata.meta.blocker+ optionaldata.meta.blockerArtifacts.macro-resolve --execute:data.execution.meta.ok+ optionaldata.execution.meta.blocker.status:data.meta.blockerState+ optionaldata.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
}
}
}
}
}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 jsoncanvas.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.
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 jsonNotes:
- Params must be a JSON object.
- Use
--output-format jsonfor machine-readable responses. rpcis CLI-only by design and is not part of the stable tool parity surface.rpccommand names/params are internal and may change without compatibility guarantees.- A bad
rpccall 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
rpconly when necessary, validate params carefully, and test in a disposable session first.
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 30000npx opendevbrowser wait --session-id <session-id> --until load
npx opendevbrowser wait --session-id <session-id> --ref r12 --state visible --timeout-ms 15000npx opendevbrowser snapshot --session-id <session-id>
npx opendevbrowser snapshot --session-id <session-id> --max-chars 16000 --cursor <cursor>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>npx opendevbrowser click --session-id <session-id> --ref r12 [--timeout-ms <ms>]Notes:
--timeout-mssets the client-side daemon timeout for the click request.- Without
--timeout-ms,clickuses a 60s client-side daemon timeout so blocking browser dialogs can be inspected and handled without the opener expiring immediately.
npx opendevbrowser hover --session-id <session-id> --ref r12npx opendevbrowser press --session-id <session-id> --key Enter
npx opendevbrowser press --session-id <session-id> --key Enter --ref r12npx opendevbrowser check --session-id <session-id> --ref r12
npx opendevbrowser uncheck --session-id <session-id> --ref r12npx opendevbrowser type --session-id <session-id> --ref r12 --text "hello"
npx opendevbrowser type --session-id <session-id> --ref r12 --text "hello" --clear --submitnpx opendevbrowser select --session-id <session-id> --ref r12 --values value1,value2npx opendevbrowser scroll --session-id <session-id> --dy 500
npx opendevbrowser scroll --session-id <session-id> --ref r12 --dy 300npx opendevbrowser scroll-into-view --session-id <session-id> --ref r12npx 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.pngNotes:
--filesaccepts a comma-separated list of host file paths.- Upload resolves the target from the existing ref model and reports
modeasdirect_inputorfile_chooser.
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-screenshotsnpx opendevbrowser targets-list --session-id <session-id>
npx opendevbrowser targets-list --session-id <session-id> --include-urlsnpx opendevbrowser target-use --session-id <session-id> --target-id <target-id>npx opendevbrowser target-new --session-id <session-id> --url https://example.comnpx opendevbrowser target-close --session-id <session-id> --target-id <target-id>npx opendevbrowser page --session-id <session-id> --name main
npx opendevbrowser page --session-id <session-id> --name main --url https://example.comnpx opendevbrowser pages --session-id <session-id>npx opendevbrowser page-close --session-id <session-id> --name mainnpx opendevbrowser dom-html --session-id <session-id> --ref r12 --max-chars 8000npx opendevbrowser dom-text --session-id <session-id> --ref r12 --max-chars 8000npx opendevbrowser dom-attr --session-id <session-id> --ref r12 --attr aria-labelnpx opendevbrowser dom-value --session-id <session-id> --ref r12npx 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 r12npx opendevbrowser clone-page --session-id <session-id>npx opendevbrowser clone-component --session-id <session-id> --ref r12npx opendevbrowser perf --session-id <session-id>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 60000Notes:
--refand--full-pageare mutually exclusive.--timeout-mssets 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.
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:
--actionsupportsstatus,accept, anddismiss.--prompt-textis only valid when--action acceptis used for a prompt dialog.--timeout-mssets the client-side daemon timeout for the dialog request.- Without
--timeout-ms,dialoguses a 30s client-side daemon timeout.
npx opendevbrowser console-poll --session-id <session-id> --since-seq 0 --max 50npx opendevbrowser network-poll --session-id <session-id> --since-seq 0 --max 50npx 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-001npx 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-001Notes:
- Returns session status, relay health, target summary, proof artifact metadata,
healthState, and a suggested next action in one payload. --include-urlskeeps target URLs in the target summary. Omit it to use the default runtime behavior.--since-console-seq,--since-network-seq,--since-exception-seq, and--maxmirror the trace cursors used bydebug-trace-snapshot.
| 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 |
| Flag | Description |
|---|---|
--port |
Override daemon port |
--token |
Override daemon token |
--stop |
Stop the daemon |
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 |
Run the automated CLI coverage script (managed mode):
npm run build
node scripts/cli-smoke-test.mjsThe 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.
Run the direct scenario pack instead of the old broad matrix:
npm run build
node scripts/live-regression-direct.mjsWhat it runs:
scripts/cli-smoke-test.mjsscripts/canvas-live-workflow.mjs --surface managed-headlessscripts/canvas-live-workflow.mjs --surface managed-headedscripts/canvas-live-workflow.mjs --surface extensionscripts/canvas-live-workflow.mjs --surface cdpscripts/annotate-live-probe.mjs --transport relayscripts/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.jsonBehavior:
- 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-gatemode. - Records
infra.daemon_statusas an initial preflight snapshot before child scenarios run. If a later child script repairs native messaging state, rerunopendevbrowser status --daemon --output-format jsonafter 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
/opsownership to drain before the legacy/cdpscenario so extension-backed CDP attach does not race a prior extension canvas run. - Treats manual annotation timeout boundaries as
skippedin--release-gatemode instead of misreporting them as runtime failures. - Requires a healthy daemon and a connected extension before running extension or CDP scenarios.
Run provider-by-provider live checks:
npm run build
node scripts/provider-direct-runs.mjs --out /tmp/odb-provider-direct-runs.jsonStrict release gate mode:
npm run build
node scripts/provider-direct-runs.mjs --release-gate --out artifacts/release/vX.Y.Z/provider-direct-runs.jsonSmoke mode:
npm run build
node scripts/provider-direct-runs.mjs --smoke --out /tmp/odb-provider-direct-runs-smoke.jsonWhat 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_limitedis 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-gatedincludes auth-dependent provider scenarios.--include-high-frictionincludes high-friction shopping providers.--include-social-postsincludes social post scenarios.--use-global-envis kept as a compatibility flag; direct runs already use the current environment.--release-gateenables auth-gated + high-friction + social-post cases and fails on any non-passstatus.
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.shThese 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.
Use this to validate the Chrome extension + relay without starting OpenCode.
- Ensure the daemon is running:
npx opendevbrowser serve(manual).opendevbrowser daemon installconfigures auto-start on supported platforms from a stable install location; for this manual test, usenpx opendevbrowser serveas the explicit start command for the current session. - Build and load the extension:
npm run extension:build, then Chrome →chrome://extensions→ Developer mode → Load unpacked →extension/. - Open a normal
http(s)tab (notchrome://or extension pages). - Open the extension popup, confirm Auto-connect + Auto-pair are ON, click Connect.
- Verify the popup shows Connected and
npx opendevbrowser status --daemonreportsextensionConnected: trueandextensionHandshakeComplete: true. - Optional session check:
npx opendevbrowser launch --extension-only --wait-for-extension, thennpx opendevbrowser disconnect --session-id <id>. - Optional annotation check (OpenCode): call
opendevbrowser_annotateand 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.
The CLI modifies opencode.json to register the plugin:
Locations:
- Global:
~/.config/opencode/opencode.json - Local:
./opencode.json
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.modeDefaultor per-requestyoutube_modefilter. - Auto mode fallback chain is
youtubei -> native_caption_parse -> ytdlp_audio_asr -> apify. yt-dlpaudio transcription requiresproviders.transcript.enableYtdlpAudioAsr=true.- Apify requires
providers.transcript.enableApify=true, a validAPIFY_TOKEN, and legal checklist approval forapify. - Browser-assisted fallback is opt-in only and requires
providers.transcript.enableBrowserFallback=trueplusproviders.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.reasonCodeDistributionfor research/shopping,meta.reasonCodeDistributionfor product-video, andreasonCodeon provider failures. - Transcript fallback diagnostics:
meta.metrics.transcript_strategy_failures(legacy) andmeta.metrics.transcriptStrategyFailures(camelCase alias). - Strategy-detail diagnostics:
meta.metrics.transcript_strategy_detail_failures/meta.metrics.transcriptStrategyDetailFailuresandmeta.metrics.transcript_strategy_detail_distribution/meta.metrics.transcriptStrategyDetailDistribution. - Durability/pressure dimensions:
meta.metrics.transcriptDurabilityandmeta.metrics.antiBotPressure(snake_case aliases are also emitted). - YouTube fetch metadata:
transcript_strategy(legacy bucket),transcript_strategy_detail(exact strategy),attempt_chain, and failurereasonCodewhen transcript retrieval is unavailable.
Provider reliability criteria (resolver/browser fallback):
npm run test -- tests/providers-performance-gate.test.tsmust pass.- Latest observation window must satisfy
meta.metrics.transcriptDurability.attempted >= 10andmeta.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.
{ "$schema": "https://opencode.ai/config.json", "plugin": ["opendevbrowser"] }