pi-agent-browser-native 0.3.0 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/CHANGELOG.md +265 -0
  2. package/README.md +130 -54
  3. package/dist/extensions/agent-browser/index.js +781 -169
  4. package/dist/extensions/agent-browser/lib/argv-descriptor.js +35 -3
  5. package/dist/extensions/agent-browser/lib/argv-grammar.js +50 -2
  6. package/dist/extensions/agent-browser/lib/batch-lifecycle.js +71 -0
  7. package/dist/extensions/agent-browser/lib/command-policy.js +5 -8
  8. package/dist/extensions/agent-browser/lib/command-taxonomy.js +53 -12
  9. package/dist/extensions/agent-browser/lib/config-policy.js +25 -1
  10. package/dist/extensions/agent-browser/lib/config.js +1 -1
  11. package/dist/extensions/agent-browser/lib/input-modes/job.js +61 -13
  12. package/dist/extensions/agent-browser/lib/input-modes/lookups.js +2 -2
  13. package/dist/extensions/agent-browser/lib/input-modes/params.js +23 -24
  14. package/dist/extensions/agent-browser/lib/input-modes/script.js +462 -0
  15. package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +51 -12
  16. package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +26 -4
  17. package/dist/extensions/agent-browser/lib/managed-session-policy-lock.js +6 -139
  18. package/dist/extensions/agent-browser/lib/managed-session-restore.js +26 -116
  19. package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +2 -4
  20. package/dist/extensions/agent-browser/lib/managed-session-storage.js +54 -25
  21. package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +26 -5
  22. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +110 -30
  23. package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +2 -1
  24. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +54 -48
  25. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +71 -5
  26. package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +2 -1
  27. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-policy.js +6 -7
  28. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +119 -2
  29. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +7 -6
  30. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +152 -64
  31. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +244 -102
  32. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +63 -37
  33. package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +20 -21
  34. package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +36 -18
  35. package/dist/extensions/agent-browser/lib/orchestration/output-file.js +41 -21
  36. package/dist/extensions/agent-browser/lib/orchestration/script-mode.js +299 -0
  37. package/dist/extensions/agent-browser/lib/page-target-validation.js +270 -0
  38. package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +32 -10
  39. package/dist/extensions/agent-browser/lib/playbook.js +29 -25
  40. package/dist/extensions/agent-browser/lib/process-environment.js +14 -0
  41. package/dist/extensions/agent-browser/lib/process-identity.js +5 -12
  42. package/dist/extensions/agent-browser/lib/process.js +130 -104
  43. package/dist/extensions/agent-browser/lib/recording-reservations.js +116 -0
  44. package/dist/extensions/agent-browser/lib/results/action-recommendations.js +63 -6
  45. package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +62 -4
  46. package/dist/extensions/agent-browser/lib/results/categories.js +6 -1
  47. package/dist/extensions/agent-browser/lib/results/next-actions.js +19 -5
  48. package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +85 -38
  49. package/dist/extensions/agent-browser/lib/results/presentation/batch.js +86 -18
  50. package/dist/extensions/agent-browser/lib/results/presentation/common.js +38 -2
  51. package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +18 -17
  52. package/dist/extensions/agent-browser/lib/results/presentation/errors.js +2 -1
  53. package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +38 -20
  54. package/dist/extensions/agent-browser/lib/results/presentation/registry.js +60 -15
  55. package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +1 -10
  56. package/dist/extensions/agent-browser/lib/results/presentation.js +36 -6
  57. package/dist/extensions/agent-browser/lib/results/recovery-actions.js +3 -1
  58. package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +9 -0
  59. package/dist/extensions/agent-browser/lib/results/selector-recovery.js +54 -11
  60. package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +13 -7
  61. package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +2 -1
  62. package/dist/extensions/agent-browser/lib/results/snapshot.js +4 -4
  63. package/dist/extensions/agent-browser/lib/runtime.js +186 -108
  64. package/dist/extensions/agent-browser/lib/session-page-state.js +71 -10
  65. package/dist/extensions/agent-browser/lib/temp.js +1 -2
  66. package/dist/extensions/agent-browser/lib/upstream-version.js +14 -0
  67. package/dist/extensions/agent-browser/lib/web-search.js +108 -24
  68. package/dist/extensions/agent-browser/script-worker.js +169 -0
  69. package/dist/scripts/agent-browser-target.mjs +21 -0
  70. package/docs/ARCHITECTURE.md +57 -34
  71. package/docs/COMMAND_REFERENCE.md +255 -68
  72. package/docs/ELECTRON.md +2 -2
  73. package/docs/RELEASE.md +12 -10
  74. package/docs/REQUIREMENTS.md +11 -8
  75. package/docs/SUPPORT_MATRIX.md +36 -24
  76. package/docs/TOOL_CONTRACT.md +169 -95
  77. package/package.json +3 -1
  78. package/platform-smoke.config.mjs +2 -2
  79. package/scripts/agent-browser-capability-baseline.mjs +87 -9
  80. package/scripts/agent-browser-target.mjs +21 -0
  81. package/scripts/build.mjs +41 -0
  82. package/scripts/config.mjs +1 -0
  83. package/scripts/doctor.mjs +16 -9
  84. package/scripts/platform-smoke/browser-dogfood-windows.ps1 +9 -3
  85. package/scripts/platform-smoke/targets.mjs +12 -6
  86. package/dist/extensions/agent-browser/lib/managed-session-capabilities.js +0 -20
  87. package/dist/extensions/agent-browser/lib/managed-session-state-policy.js +0 -583
  88. package/dist/extensions/agent-browser/lib/navigation-policy.js +0 -78
  89. package/dist/extensions/agent-browser/lib/results/presentation/managed-list-filter.js +0 -37
@@ -18,19 +18,60 @@ This project intentionally blocks normal `agent-browser` bash usage in most agen
18
18
 
19
19
  <!-- agent-browser-capability-baseline:start upstream-baseline -->
20
20
  <!-- Generated from scripts/agent-browser-capability-baseline.mjs. Run `npm run docs -- command-reference write` to update. Do not edit manually. -->
21
- This reference is baselined to the locally installed `agent-browser 0.33.2` command/help surface, audited against vercel-labs/agent-browser@93cdda5709e8861c0c26b0b955d8d746e9fda0d7. Upstream `agent-browser` remains the source of truth for command semantics; this file is the local fallback for Pi agent sessions where direct binary help is blocked or discouraged.
21
+ This reference is baselined to the locally installed `agent-browser 0.36.0` command/help surface, audited against vercel-labs/agent-browser@eb05921bad874cd2a1b4fa5d1149f1ed26576cae. Upstream `agent-browser` remains the source of truth for command semantics; this file is the local fallback for Pi agent sessions where direct binary help is blocked or discouraged.
22
22
 
23
23
  The lightweight drift check is `npm run verify -- command-reference`. Run it whenever the installed upstream `agent-browser` version changes or this reference is edited.
24
24
 
25
25
  <!-- agent-browser-capability-baseline:end upstream-baseline -->
26
26
 
27
+ ### Upstream 0.36.0 rebaseline
28
+
29
+ The recommended 0.36.0 release adds experimental page-provided WebMCP tools while preserving the stable 0.35.0 runtime floor.
30
+
31
+ - `webmcp list` discovers tools registered by the current page. `webmcp invoke <tool>` accepts JSON or file input, frame selection, detached execution, and a timeout; `webmcp result <id>` waits for a detached call and `webmcp cancel <id>` cancels one.
32
+ - Locally managed Chrome enables WebMCP by default. `--no-webmcp`, `AGENT_BROWSER_NO_WEBMCP`, and upstream config `noWebmcp` disable it; attached browsers, remote providers, Lightpanda, Safari/iOS, and older Chrome builds may return `webmcp_unsupported` instead. The wrapper treats `--no-webmcp` as launch-scoped.
33
+ - `webmcp list` is read-only. Because `invoke`, `result`, and `cancel` can run page code that mutates, rerenders, or navigates, the wrapper rechecks the live page and invalidates prior page-scoped refs. A detached call that remains pending keeps the page target unverified, as does a failed `result` / `cancel` attempt while that target is unknown; settle or cancel it successfully, or use the `verify-page-target-after-pending-webmcp` (`get url`) next action / explicit navigation before taking a fresh snapshot. In `batch --bail`, put `get url` between a completed WebMCP mutation and `snapshot -i`.
34
+ - `skills get webmcp-gen` loads the bundled workflow for creating `webmcp.init.js` and validating it against the existing UI. External MCP clients can opt into page tools with `mcp --tools core,webmcp`; the native Pi wrapper continues to use direct `args` rather than starting an MCP server.
35
+ - Upstream also updates its separate Eve integration, dependency resolutions, and Lightpanda launch arguments. This wrapper adds no Eve layer or compatibility shim.
36
+
37
+ ### Upstream 0.35.2 rebaseline
38
+
39
+ Upstream 0.35.2 hardens the standalone dashboard against DNS rebinding and cross-origin access. `dashboard start --allowed-origins <origins>` accepts comma-separated exact HTTPS reverse-proxy origins, with `AGENT_BROWSER_DASHBOARD_ALLOWED_ORIGINS` as the environment equivalent; the wrapper keeps this local lifecycle command sessionless. The release also fixes root remote CDP WebSocket URLs that contain query strings without requiring a wrapper shim.
40
+
41
+ ### Upstream 0.35.1 rebaseline
42
+
43
+ The 0.35.1 baseline is a bug-fix release with no new commands or flags. Browser-backed calls accept stable `agent-browser` versions at or above the 0.35.0 floor.
44
+
45
+ - Snapshot diffs reset element-ref numbering for each diff, invalidate refs across URL navigation, and preserve previous refs when a diff fails.
46
+ - Stream URL events now follow the active main frame across full-document, History API, fragment, and active-tab changes while ignoring child frames and background tabs.
47
+ - The Windows ARM64 launcher prefers a native executable and falls back to the published x64 binary through Windows emulation.
48
+ - `rustls-webpki` and `quinn-proto` received upstream dependency updates.
49
+
50
+ ### Upstream 0.35.0 rebaseline
51
+
52
+ The 0.35.0 release is the current runtime floor and adds private proxy CA trust plus one bundled workflow skill.
53
+
54
+ - `--ca-cert <path>` / `AGENT_BROWSER_CA_CERT` loads a PEM bundle or DER certificate into an isolated NSS trust store for locally launched Linux Chromium. Normal hostname, validity, and unrelated-authority checks remain enabled. Equivalent certificate content reuses Chromium; changed content relaunches it. `--no-ca-cert` / `AGENT_BROWSER_CLEAR_CA_CERT` clears retained trust.
55
+ - Use CA trust only with a fresh managed session. The wrapper treats `--ca-cert` and `--no-ca-cert` as launch-scoped for managed-session planning, disables automatic managed restore when CA trust is enabled, and passes caller-selected certificate paths through unchanged. Upstream rejects CA trust with profiles, CDP/auto-connect, providers, Lightpanda, `--ignore-https-errors`, macOS, or Windows, and requires `certutil` (`install --with-deps` installs it on supported Linux systems).
56
+ - `skills get protected-vercel-deployments --full` loads the bundled short-lived Trusted Sources OIDC workflow. It uses `vc project token` and the `x-vercel-trusted-oidc-idp-token` header, avoids persisting tokens, and hands dashboard-only access-control changes to an authorized human.
57
+ - The release also restores ARM64 build artifacts; no wrapper shim is needed.
58
+
59
+ ### Upstream 0.34.0 rebaseline
60
+
61
+ The 0.34.0 release added persistent session-to-tab binding for shared Chrome sessions. It is below the current 0.35.0 runtime floor: before browser-backed work, the extension caches one `agent-browser --version` check per cwd/PATH and fails below-floor or malformed versions with expected/observed version details. Plain help/version, close recovery, and sessionless local setup/diagnostics remain available.
62
+
63
+ - Named sessions on `--cdp` or `--auto-connect` remember their CDP target across commands and daemon restarts. CDP target ids from `tab list --json` are accepted as tab refs and stay stable across daemon restarts, unlike `t<N>` ids.
64
+ - `--pin-tab` (`AGENT_BROWSER_PIN_TAB`) is sticky per session and is not launch-scoped: pass it once, including on an already-live session, so a closed bound tab fails with `tab_gone` instead of adopting a neighbor. JSON includes `code=tab_gone`, `data.targetId`, and optional sanitized `data.lastUrl`; batch exposes the same recovery object under `result`. Recover with `tab new` or `tab list`. `--no-pin-tab` turns the pin off again. Optional booleans use separated tokens (`--pin-tab false`).
65
+ - This wrapper classifies `tab_gone` as `failureCategory: "tab-gone"` and returns `list-tabs-after-tab-gone` plus `open-tab-after-tab-gone`. `tab list` presentation includes `target=<id>` when upstream reports `data.targetId`.
66
+ - Doctor no longer hangs on Chrome version detection. The Remote Agent Browser provider guide is upstream documentation only; this wrapper adds no new provider mode.
67
+
27
68
  ### Upstream 0.33.2 rebaseline
28
69
 
29
- The 0.33.1–0.33.2 releases harden daemon lifecycle and live streaming without new core page commands:
70
+ The 0.33.1–0.33.2 releases harden daemon lifecycle and live streaming without new core page commands. Package 0.4.1 targeted exactly `agent-browser 0.33.2`: before browser-backed work, the extension caches one `agent-browser --version` check per cwd/PATH and fails a mismatch with expected/observed version details. Plain help/version, close recovery, and sessionless local setup/diagnostics remain available.
30
71
 
31
72
  - 0.33.1 ships a default daemon idle timeout of 1 hour (`AGENT_BROWSER_IDLE_TIMEOUT_MS`, default `3600000`; `0` disables). Sessions without a restore key discard transient cookies/tabs on idle shutdown. Headed, Safari/iOS WebDriver, and user-attached browsers are exempt from that default. Tab recovery also revives Memory Saver-discarded tabs on connect/switch/close and reports recovery fields such as `revived` / `dialogBlocked` / `activeTabRevived`.
32
73
  - 0.33.2 makes stream frame delivery latest-wins, prioritizes input over frame writes, adds per-client `maxFps` / ack pacing, and adds `AGENT_BROWSER_STREAM_QUALITY`, `AGENT_BROWSER_STREAM_MAX_WIDTH`, and `AGENT_BROWSER_STREAM_MAX_HEIGHT` for screencast bandwidth control.
33
- - This wrapper keeps its managed-session idle override (default 15 minutes via `PI_AGENT_BROWSER_IMPLICIT_SESSION_IDLE_TIMEOUT_MS` / `AGENT_BROWSER_IDLE_TIMEOUT_MS`) and enables Git-checkout-generation-stable `AGENT_BROWSER_RESTORE` for wrapper-owned managed sessions so SSO cookies survive browser relaunches. Caller-owned `--session` names do not get that inject, and foreign `piab-*` names are rejected unless this extension instance owns the exact namespace/session. Managed daemon inspection uses its own bounded timeout rather than a caller's short `PI_AGENT_BROWSER_PROCESS_TIMEOUT_MS`. Local browser navigation into `.agent-browser` state storage is blocked, including encoded `file:` paths, local-directory file ref interactions, batches, and later capture from a tracked protected target. Set `PI_AGENT_BROWSER_MANAGED_SESSION_RESTORE=0` to disable restore injection. No Eve-specific Pi runtime is added.
74
+ - This wrapper keeps its managed-session idle override and enables transcript- and checkout-scoped `AGENT_BROWSER_RESTORE` for wrapper-owned implicit sessions so browser state can survive relaunch, reload, and `/resume`; set `PI_AGENT_BROWSER_MANAGED_SESSION_RESTORE=0` to disable it. Explicit sessions, restore/state paths, config, file access, launch arguments, environment, local pages, and close arguments pass through unchanged. Session/state lists keep every upstream row and restore identifier visible. Managed daemon inspection only coordinates the wrapper's automatic restore lifecycle.
34
75
 
35
76
  ### Upstream 0.33.0 rebaseline
36
77
 
@@ -57,7 +98,7 @@ The current audit also closes a command-reference/presentation gap for upstream
57
98
  The 0.32.0 rebaseline hardens domain containment and fixes completed-page waits without adding a new native Pi input mode:
58
99
 
59
100
  - `--allowed-domains <list>` now contains request traffic across pages, iframes, workers, service workers, shared workers, and popups. Chromium `RTCPeerConnection` is disabled while containment is active to prevent WebRTC bypasses.
60
- - The wrapper treats argv-supplied `--allowed-domains` as launch-scoped. Use `sessionMode: "fresh"` for a fresh local Chrome context; upstream rejects CDP/auto-connect, profiles, restore/state replay, direct-page providers, iOS/Safari, and startup/profile Chrome args because those launch paths cannot guarantee containment. The wrapper's final observed-URL check remains defense in depth.
101
+ - The wrapper treats argv-supplied `--allowed-domains` as launch-scoped. Use `sessionMode: "fresh"` for a fresh local Chrome context; upstream owns containment and incompatible-mode rejection, and the wrapper passes its result through unchanged.
61
102
  - `wait --load load` and `wait --load domcontentloaded` now resolve immediately when the current document already reached the requested state instead of waiting for a future lifecycle event. The wrapper still treats `waited:timeout` as inconclusive rather than success.
62
103
  - Upstream also publishes `@agent-browser/eve`, a separate Eve extension with namespaced browser tools and sandbox helpers. It is not bundled by this Pi extension and does not change the native `agent_browser` schema.
63
104
 
@@ -65,7 +106,7 @@ The 0.32.0 rebaseline hardens domain containment and fixes completed-page waits
65
106
 
66
107
  The 0.31.2 rebaseline adds a WebGPU launch preset and periodic restore-state autosaves:
67
108
 
68
- - `--webgpu` (also `AGENT_BROWSER_WEBGPU`; standalone upstream additionally accepts `"webgpu": true` in `agent-browser.json`) enables the upstream platform preset. Browser-backed native calls reject upstream config files, so use the flag or environment form through this tool. It uses Metal on macOS, D3D on Windows, and SwiftShader software Vulkan on Linux. The native Pi wrapper passes it through as a launch-scoped optional boolean, so use `sessionMode: "fresh"` after an implicit session exists; `--webgpu false` explicitly disables a config/environment default.
109
+ - `--webgpu` (also `AGENT_BROWSER_WEBGPU`; upstream config accepts `"webgpu": true`) enables the upstream platform preset. Native calls preserve project/user config plus explicit `--config` and `AGENT_BROWSER_CONFIG`. It uses Metal on macOS, D3D on Windows, and SwiftShader software Vulkan on Linux. The Pi wrapper treats it as launch-scoped, so use `sessionMode: "fresh"` after an implicit session exists; `--webgpu false` explicitly disables a config/environment default.
69
110
  - WebGPU requires a local browser launch. Upstream rejects enabled WebGPU with `--cdp`, `--auto-connect`, or `-p` / `--provider`. Use `doctor --webgpu` to pixel-check rendering and screenshot capture; use `doctor --webgpu --headed` when validating the headed capture path.
70
111
  - Headless WebGPU screenshots work on macOS. Upstream documents black headless WebGPU canvas captures on Windows and Linux even when in-page rendering succeeds; Windows needs a logged-in headed desktop, while Linux can use `--headed` with automatic Xvfb unless `AGENT_BROWSER_NO_XVFB=1`. Linux software rendering also needs `libvulkan1` and `mesa-vulkan-drivers`.
71
112
  - Restore-enabled sessions now save periodically while the browser remains open, including idle page-driven cookie/storage changes. `AGENT_BROWSER_AUTOSAVE_INTERVAL_MS` defaults to `30000`; `0` disables periodic saves but keeps native close saves. The existing `--restore-save` policy still controls whether automatic saves are allowed. For wrapper-owned headed launches, this extension defaults the interval to `0` because upstream 0.33.2 collects multi-origin storage through visible temporary tabs; upstream exempts headed browsers from idle shutdown, so direct window close can lose newer state unless an explicit interval was set before launch. The wrapper retains the effective launch-time interval across resume and rejects changes in either direction on a running wrapper-owned headed daemon until close plus a fresh launch.
@@ -113,9 +154,13 @@ The 0.27.3 rebaseline is an install-only compatibility update: upstream changed
113
154
 
114
155
  ## Core mental model
115
156
 
116
- Input mode chooser (one per call): **`args`** for the default open → snapshot -i → click/fill `@refs` flow; **`semanticAction`** for stable role/text/label targets; **`job`** / **`qa`** for multi-step checks; **`electron`** for desktop apps only; **`sourceLookup`** / **`networkSourceLookup`** are **experimental candidates-only** helpers (not authoritative mappings). Do not pass `--json` in `args`—the wrapper injects it. Match link and button text to the latest snapshot (on `https://example.com/` the main link is `Learn more`, not legacy `More information...` copy). See [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#input-mode-chooser) for snapshot variants (`-i` vs `--compact` vs full) and batching three or more getters.
157
+ Input mode chooser (one per call): **`script`** for one-shot loops, branches, or multi-page aggregation; **`args`** for the default open → snapshot -i → click/fill `@refs` flow; **`semanticAction`** for stable role/text/label targets; **`job`** / **`qa`** for multi-step checks; **`electron`** for desktop apps only; **`sourceLookup`** / **`networkSourceLookup`** are **experimental candidates-only** helpers (not authoritative mappings). Do not pass `--json` in `args`—the wrapper injects it. Match link and button text to the latest snapshot (on `https://example.com/` the main link is `Learn more`, not legacy `More information...` copy). See [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#input-mode-chooser) for snapshot variants (`-i` vs `--compact` vs full) and batching three or more getters.
158
+
159
+ Tool parameters (use exactly one of `script`, `args`, `semanticAction`, `job`, `qa`, `sourceLookup`, `networkSourceLookup`, or `electron`):
117
160
 
118
- Tool parameters (use exactly one of `args`, `semanticAction`, `job`, `qa`, `sourceLookup`, `networkSourceLookup`, or `electron`):
161
+ ```json
162
+ { "script": "const page = await browser({ args: ['get', 'title'] }); if (!page.ok) throw new Error(page.error); emit(page.data.title ?? page.data.result);" }
163
+ ```
119
164
 
120
165
  ```json
121
166
  { "args": ["open", "https://example.com"], "sessionMode": "auto" }
@@ -148,21 +193,40 @@ Tool parameters (use exactly one of `args`, `semanticAction`, `job`, `qa`, `sour
148
193
  { "electron": { "action": "launch", "appName": "Visual Studio Code", "handoff": "snapshot" } }
149
194
  ```
150
195
 
151
- - `args`: exact `agent-browser` CLI tokens after the binary name. Omit when using `semanticAction`, `job`, `qa`, `sourceLookup`, `networkSourceLookup`, or `electron` instead (mutually exclusive).
196
+ - `script`: one-shot sandboxed async JavaScript with `browser({ args, stdin?, timeoutMs? })` and `emit(value)`. Use it for loops, conditional page branches, or aggregation only; every invocation gets a unique non-profile session, clears ambient upstream launch controls, closes afterward, and has no host APIs or reusable-name/state surface.
197
+ - `args`: exact `agent-browser` CLI tokens after the binary name. Omit when using `script`, `semanticAction`, `job`, `qa`, `sourceLookup`, `networkSourceLookup`, or `electron` instead (mutually exclusive).
152
198
  - `semanticAction`: optional shorthand for common `find` flows, direct selector/ref click/check/fill, and native dropdown `select`; compiles to upstream argv and is rejected together with `args`, `job`, `qa`, `sourceLookup`, `networkSourceLookup`, or `electron` on the same call.
153
199
  - `job`: optional constrained short-workflow schema; compiles to existing upstream `batch` args/stdin, defaults to `batch --bail` (`failFast: true`), and reports the compiled plan in `details.compiledJob`. Keep stateful jobs short around navigation, click, and rerender boundaries on dynamic apps.
154
200
  - `qa`: optional lightweight QA preset; compiles to the same fail-fast batch path and reports `details.compiledQaPreset` plus `details.qaPreset` pass/fail evidence.
155
201
  - `sourceLookup`: **EXPERIMENTAL — candidates only** for local UI-to-source hints; compiles to the same `batch` path, reports `details.compiledSourceLookup` and `details.sourceLookup`, and never reclassifies a fully successful upstream batch as failed the way `qa` can (see [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#sourcelookup) and the longer notes below).
156
202
  - `networkSourceLookup`: **EXPERIMENTAL — candidates only** for failed request-to-source hints; compiles to generated `batch`, reports `details.compiledNetworkSourceLookup` and `details.networkSourceLookup`, and never assigns blame or edits files.
157
203
  - `electron`: optional Electron desktop-app shorthand. `list`, `status`, `cleanup`, and `probe` are wrapper-owned host/session helpers; `launch` starts a wrapper-owned isolated Electron profile and attaches through upstream `connect`.
158
- - `stdin`: only for `batch`, `eval --stdin`, and `auth save --password-stdin`; other command/stdin combinations are rejected before `agent-browser` is launched. `job`, `qa`, `sourceLookup`, `networkSourceLookup`, and `electron` generate or manage their own input.
159
- - `outputPath`: optional wrapper-owned local file sink for successful results. Use it for durable `eval`, `get`, `snapshot`, or diagnostic outputs, not as the destination for screenshots, downloads, recordings, or other browser artifacts; if the paths resolve to the same file, the browser artifact is preserved and the result-data write fails validation. `details.outputFile` reports the saved path and byte count. If caller argv includes upstream `--json`, the visible JSON content stays parseable and the save notice is only in `details.outputFile`.
204
+ - `stdin`: top-level stdin is only for `batch`, `eval --stdin`, and `auth save --password-stdin`; other combinations are rejected before `agent-browser` is launched. `script` puts inner stdin on `browser({ stdin })`; `job`, `qa`, `sourceLookup`, `networkSourceLookup`, and `electron` generate or manage their own input.
205
+ - `outputPath`: optional wrapper-owned local file sink for successful results. Use it for durable `eval`, `get`, `snapshot`, or diagnostic outputs, not as the destination for screenshots, downloads, recordings, or other browser artifacts; if the paths resolve to the same file, the browser artifact is preserved and the result-data write fails validation. If presentation compacted a large direct result, a result row, or the whole `batch`, the writer copies each full command-redacted pre-compaction value only from its matching live wrapper-manifest spill; if any required spill is unavailable or untrusted, it fails without writing compact metadata. `details.outputFile` reports the saved path and byte count. If caller argv includes upstream `--json`, the visible JSON content stays parseable and the save notice is only in `details.outputFile`.
160
206
  - `timeoutMs`: optional per-call wrapper subprocess watchdog override in milliseconds for the requested browser CLI process. Managed-session policy inspection can independently consume up to 35 seconds before that process; this preflight is intentionally not shortened by `timeoutMs` because a busy but valid daemon must remain distinguishable from an unverifiable one.
161
207
  - `sessionMode`:
162
208
  - `"auto"` reuses the extension-managed session when possible.
163
- - `"fresh"` rotates that managed session to a fresh upstream launch so launch-scoped flags (`--allowed-domains`, `--auto-connect`, `--cdp`, `--enable`, `--executable-path`, `--webgpu`, `--init-script`, `--idle-timeout`, `--headed`, `--device`, `--namespace`, `--profile`, `--provider`, `-p`, `--restore`, `--restore-save`, `--restore-check-url`, `--restore-check-text`, `--restore-check-fn`, `--session-name`, `--state`) apply.
209
+ - `"fresh"` rotates that managed session to a fresh upstream launch so launch-scoped flags (`--allowed-domains`, `--auto-connect`, `--args`, `--ca-cert`, `--no-ca-cert`, `--cdp`, `--enable`, `--executable-path`, `--webgpu`, `--init-script`, `--idle-timeout`, `--user-agent`, `--headed`, `--device`, `--namespace`, `--profile`, `--provider`, `-p`, `--restore`, `--restore-save`, `--restore-check-url`, `--restore-check-text`, `--restore-check-fn`, `--session-name`, `--state`) apply.
164
210
  - If a fresh launch fails or times out, read `details.managedSessionOutcome` for `preserved` vs `abandoned` (and related fields). A model-visible `Managed session outcome: …` line is appended for failing calls that used `sessionMode: "fresh"` and when automatic close of a replaced session fails; `"auto"` failures can still populate the struct without that extra line. If you explicitly close the current wrapper-managed session with `--session <name> close`, later default auto calls rotate to a new wrapper-generated session instead of reusing the closed name; repeated closes and branch restores keep those generated names monotonic.
165
211
 
212
+ ### One-shot code mode
213
+
214
+ Use `script` when a loop, an optional page branch, or multi-page aggregation would otherwise require several top-level tool calls and artifact reads. Source runs as an async JavaScript body. Call `await browser({ args, stdin?, timeoutMs? })`, check its `{ ok, data, details?, error?, failureCategory?, nextActions?, resultCategory, successCategory?, summary, text }` envelope, then call `emit(value)` with the one JSON-compatible value the model needs. Inner calls still traverse the ordinary wrapper executor, including policy checks, redaction, presentation, compact-spill rehydration, artifacts, and timeouts.
215
+
216
+ ```json
217
+ {
218
+ "script": "const titles = []; for (const url of ['https://example.com', 'https://example.org']) { const opened = await browser({ args: ['open', url] }); if (!opened.ok) throw new Error(opened.error); const title = await browser({ args: ['get', 'title'] }); if (!title.ok) throw new Error(title.error); titles.push({ url, title: title.data.title ?? title.data.result }); } emit(titles);"
219
+ }
220
+ ```
221
+
222
+ The wrapper serializes inner calls, caps them at 25, caps source/final JSON at 64 KiB, defaults the whole script to 120 seconds, and rejects more than 300 seconds. Final data is redacted, compact-serialized, and byte-checked again before presentation so nesting cannot amplify small JSON into unbounded prose. Inner summaries/text are bounded, complete envelopes are checked against the IPC cap, and script-visible browser `nextActions` retain only policy-compatible calls after the isolated identity prefix is removed. It launches a separate permissioned Node child with no imports, process, filesystem, network, timers, dynamic code generation, or host object/function references. `Promise.all` is allowed for local orchestration but does not make browser calls concurrent. Pi approval covers the one visible top-level input and may therefore authorize all 25 inner calls. The collapsed Pi tool row shows a bounded terminal-safe source preview with line breaks marked as `↵`; expand the row to inspect the full terminal-safe source before approval. JavaScript CR/U+2028/U+2029 line terminators remain visible newlines, and removed terminal/directional/zero-width controls become visible markers.
223
+
224
+ A script invocation uses a unique `piab-script-<uuid>` browser identity in an empty namespace with managed restore disabled. It cannot name or attach to sessions, use profiles/providers/state/restore/raw launch mutation, issue lifecycle/sessionless/local commands, or nest `batch` or another top-level input mode. Every inner helper and cleanup process also clears ambient `AGENT_BROWSER_*` and standard proxy variables before the wrapper reapplies its own safe config, namespace, timeout, and compatibility values. It never replaces the implicit conversation browser and always closes its isolated session. Use ordinary `args` with a requested profile/attachment for authenticated state.
225
+
226
+ Pi persistence is required because the extension appends a strict model-invisible cleanup lease before the first inner browser launch. Pi branch changes, quit, and reload abort the script and await normal isolated-session cleanup before state restoration continues. A failed close is retried on the active branch after restart and returns `failureCategory: "cleanup-failed"` plus exact `details.scriptSession.closeCommandArgs` / `close-script-session-after-cleanup-failure`. Any rejected inner policy/validation call fails the top-level result even if source consumes its envelope. See [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#script) for the full schema, limits, result fields, rejected controls, and recovery semantics.
227
+
228
+ Code mode remains ad hoc: there is no name, registry, imported module, persistent workflow state, or versioned recipe. Keep recurring linear flows in `job`, `qa`, raw `batch`, or docs instead of building a script catalog.
229
+
166
230
  ### Debug, diff, stream, dashboard, and chat families
167
231
 
168
232
  Upstream also exposes non-core families (`network`, `diff`, `trace` / `profiler` / `record`, `console` / `errors` / `a11y` / `highlight` / `inspect` / `clipboard`, `stream`, `dashboard`, `chat`, and related subcommands). The wrapper still owns argv planning, `--json`, managed sessions where applicable, artifact metadata, and model-facing presentation: structured results are compacted and scrubbed in `extensions/agent-browser/lib/results/presentation.ts`, and echoed argv uses the same `redactInvocationArgs` rules as core commands (see [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details) for the field contract). Deterministic fake-upstream coverage for representative JSON shapes and redaction lives in `test/agent-browser.extension-validation.test.ts` under `agentBrowserExtension passes through non-core network debug diff stream dashboard and chat families`.
@@ -200,11 +264,11 @@ For a WebGPU page, enable the launch preset before the first navigation. Treat i
200
264
 
201
265
  Run `{ "args": ["doctor", "--webgpu"] }` before trusting a black or blank WebGPU capture. On Linux/Windows capture paths, use `doctor --webgpu --headed` and follow upstream's platform requirements; do not combine enabled WebGPU with `--cdp`, `--auto-connect`, or provider launches.
202
266
 
203
- Treat headed success as browser-context success, not proof that a window is visible on the user's display. Remote shells, containers, virtual framebuffers, or upstream/provider-owned browser hosts can still put the visible window somewhere the user cannot see. If a user reports no window, gather evidence with `screenshot`, `tab list`, `get url`, or `snapshot -i`; then relaunch with the right display/profile/provider setup rather than assuming the user missed it.
267
+ On a successful first/fresh local wrapper-managed headed launch, including a launch inside `batch`, whose upstream lifecycle proves a browser launched, `details.browserWindow` reports `{ mode: "headed", ownership: "wrapper-managed", sessionName, visibility: "unverified" }` and the result adds one visible login handoff. CDP, auto-connect, provider, and Electron attachments suppress this local-window claim. Treat it as headed-launch evidence, not proof that a window is visible on the user's display. Remote shells, containers, virtual framebuffers, or upstream/provider-owned browser hosts can still put the window somewhere the user cannot see. If visible, let the user complete the login and continue the same wrapper session with `sessionMode: "auto"`; otherwise gather evidence with `screenshot`, `tab list`, `get url`, or `snapshot -i`, then fix display/profile/provider setup.
204
268
 
205
- For local fixtures, remember that `localhost` and `127.0.0.1` are resolved from the browser host, which may differ from the shell that started a temporary HTTP server. `net::ERR_EMPTY_RESPONSE` on `http://localhost:<port>` usually means the browser could not reach that server, not that the page rendered blank; the wrapper appends a local fixture hint for common loopback failures. Prefer an environment-specific host-reachable HTTP(S) address. Do not switch to `file://`: the native wrapper blocks content-returning local-URL calls plus follow-up inspection, scripting, interaction, and Electron probes on local file pages to protect authenticated `.agent-browser` state. Protected artifact destinations and top-level `outputPath` also fail before browser spawn or directory creation.
269
+ For local fixtures, remember that `localhost` and `127.0.0.1` are resolved from the browser host, which may differ from the shell that started a temporary HTTP server. `net::ERR_EMPTY_RESPONSE` on `http://localhost:<port>` usually means the browser could not reach that server, not that the page rendered blank. Use a host-reachable HTTP(S) address or a `file://` fixture when upstream browser settings allow it. Local paths, artifact destinations, and top-level `outputPath` are caller-owned and pass through normally.
206
270
 
207
- For a caller-owned explicit `--session`, content-bearing reads and interactions first run a session-scoped `get url`; missing or stale transcript page state is not trusted. If the probe fails or resolves to a protected local target, the requested content command does not run. Calls to the same effective canonical namespace/session are serialized inside one extension instance; explicit namespace argv overrides inherited `AGENT_BROWSER_NAMESPACE`, including an explicit empty default across preparation helpers, that live probe, any semantic-action snapshot, and the requested command; different caller-owned sessions can still overlap. This does not coordinate direct `agent-browser` calls or another Pi process. Windows drive-relative forms such as `C:.agent-browser\\state\\...` are paths, not URL schemes. Nested `batch` steps are rejected. Raw batch command strings mirror upstream's ASCII-space tokenizer, including its single/double-quote and backslash handling; other Unicode whitespace remains part of a token. When later batch content depends on navigation, use exact `batch --bail` or split the calls: a non-bail batch is rejected if any failed transition could leave a local or unverified page active. Non-bail diagnostics remain available when every retained target is already verified safe.
271
+ For an explicit `--session`, content-bearing reads and interactions first run a session-scoped `get url`; missing or stale transcript page state is not trusted, and a failed probe stops the requested content command. Calls to the same canonical namespace/session are serialized through that probe and command. Nested `batch` steps remain unsupported; raw batch command strings mirror upstream's ASCII-space tokenizer, including quoting and backslash handling.
208
272
 
209
273
  Temporary HTTP servers and their port/process lifecycle stay outside the native tool. Extension maintainers running real-upstream contract tests can reuse `startAgentBrowserContractFixtureServer()` in [`test/helpers/agent-browser-harness.ts`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/test/helpers/agent-browser-harness.ts) instead of ad-hoc `python3 -m http.server` processes.
210
274
 
@@ -263,13 +327,13 @@ Examples:
263
327
  { "args": ["snapshot", "-i"] }
264
328
  ```
265
329
 
266
- The optional native `semanticAction` object is only a thin schema for common locator-based actions, direct selector/ref click/check/fill, and native dropdown selection; it compiles locator actions to existing upstream `find` commands, direct selector/ref actions to `click` / `check` / `fill`, compiles `action: "select"` to upstream `select <selector> <value...>`, and reports the compiled argv in `details.compiledSemanticAction` (see [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#semanticaction) for the full field rules). For `locator: "role"`, pass either `value: "button"` or `role: "button"`; if both are present they must match. It is a top-level alternative to `args`, `job`, `qa`, `sourceLookup`, `networkSourceLookup`, and `electron`, not a nested shape inside `batch` stdin arrays. Add `session` inside `semanticAction` when the shorthand should target a named upstream browser session; the compiled argv prepends `--session <name>` before `find`, direct selector/ref commands, or `select`, and fallback candidate actions preserve that prefix. For active sessions, role/name click/check/fill shorthands may resolve through the current `snapshot -i` refs before execution so hidden duplicate matches do not steal the action; fill only resolves when there is one exact editable current ref match. Inspect `details.effectiveArgs` when you need the exact executed argv. `semanticAction` does not expose `uncheck` because upstream `find` actions are only `click, fill, check, hover, text`; use raw `uncheck <selector-or-ref>` after choosing a stable selector or current snapshot ref. `select` shorthand intentionally requires a stable selector or current `@ref` plus `value`/`values`; upstream `find` does not expose a verified `select` action, so role/name/label dropdown resolution stays a snapshot/selector decision instead of hidden wrapper magic. If a raw `find` or semantic action misses with `selector-not-found`, the wrapper may take one fresh snapshot and append `Current snapshot ref fallback` when that snapshot has exact visible role/name matches for the failed target. Non-fill matches can include direct `try-current-visible-ref*` next actions. Semantic click misses may also include `Agent-browser candidate fallbacks`; `details.nextActions` first recommends a fresh `snapshot -i` and may include bounded role/name retries such as `button`/`link` for a missed `text` click, each as a `try-*-candidate` entry carrying redacted `find role …` argv.
330
+ The optional native `semanticAction` object is only a thin schema for common locator-based actions, direct selector/ref click/check/fill, and native dropdown selection; it compiles click/check/fill locator actions to existing upstream `find` commands, direct selector/ref actions to `click` / `check` / `fill`, and direct `action: "select"` to upstream `select <selector> <value...>`. Active-session role/name (`combobox` or `listbox`) and label select locators are resolved through one fresh snapshot to exactly one current visible ref before direct `select` execution; `details.compiledSemanticAction.args` reports that resolved `select @ref` argv (see [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#semanticaction) for the full field rules). For `locator: "role"`, pass either `value: "button"` or `role: "button"`; if both are present they must match. It is a top-level alternative to `script`, `args`, `job`, `qa`, `sourceLookup`, `networkSourceLookup`, and `electron`, not a nested shape inside `batch` stdin arrays. Add `session` inside `semanticAction` when the shorthand should target a named upstream browser session; the compiled argv prepends `--session <name>` before `find`, direct selector/ref commands, or `select`, and fallback candidate actions preserve that prefix. For active sessions, role/name click/check/fill shorthands may resolve through the current `snapshot -i` refs before execution so hidden duplicate matches do not steal the action; fill only resolves when there is one exact editable current ref match. Inspect `details.effectiveArgs` when you need the exact executed argv. `semanticAction` does not expose `uncheck` because upstream `find` actions are only `click, fill, check, hover, text`; use raw `uncheck <selector-or-ref>` after choosing a stable selector or current snapshot ref. If a raw `find` or semantic action misses with `selector-not-found`, the wrapper may take one fresh snapshot and append `Current snapshot ref fallback` when that snapshot has exact visible role/name matches for the failed target. Non-fill matches can include direct `try-current-visible-ref*` next actions. Semantic click misses may also include `Agent-browser candidate fallbacks`; `details.nextActions` first recommends a fresh `snapshot -i` and may include bounded role/name retries such as `button`/`link` for a missed `text` click, each as a `try-*-candidate` entry carrying redacted `find role …` argv.
267
331
 
268
- For desktop, contenteditable, or host-controlled rich inputs, treat a semantic `fill` miss or mismatch differently. Active-session role/name fills can execute through one exact current editable `combobox`, `searchbox`, or `textbox` ref before upstream `find` runs. If a later selector miss still finds an exact current editable ref (`searchbox` or `textbox`), `details.richInputRecovery` and visible `Rich input recovery` describe the candidate and append `focus-current-editable-ref*` / `click-current-editable-ref*` next actions. Those actions deliberately do **not** copy the fill text and never press `Enter` or submit. Direct `fill @ref <text>` on contenteditable refs may also append/prepend instead of replacing; when the latest snapshot proves the target is contenteditable, the wrapper verifies `get text` after a successful fill and appends `details.fillVerification` plus `inspect-after-fill-verification` / `verify-filled-value` if the visible text does not match. Use the safe ladder instead: refresh refs, choose the current editable `@ref`, focus or click it, then send the intended text with `keyboard inserttext` or `keyboard type` in a separate call. Do not auto-submit unless the user flow explicitly calls for it.
332
+ For desktop, contenteditable, or host-controlled rich inputs, treat a semantic `fill` miss or mismatch differently. Active-session role/name fills can execute through one exact current editable `combobox`, `searchbox`, or `textbox` ref before upstream `find` runs. If a later selector miss still finds an exact current editable ref (`searchbox` or `textbox`), `details.richInputRecovery` and visible `Rich input recovery` describe the candidate and append `focus-current-editable-ref*` / `click-current-editable-ref*` next actions. Those actions deliberately do **not** copy the fill text and never press `Enter` or submit. Direct `fill @ref <text>` on contenteditable refs may also append/prepend instead of replacing; when the latest snapshot proves the target is contenteditable, the wrapper verifies `get text` after a successful fill and appends `details.fillVerification` plus `inspect-after-fill-verification` / `verify-filled-value` if the visible text does not match. Use the safe ladder instead: refresh refs, choose the current editable `@ref`, focus or click it, then use `keyboard type` for framework-controlled editors that require real key events. `keyboard inserttext` is paste-like: it can change a DOM value without updating application state, so use it only when later application-state evidence proves the edit was accepted. Do not auto-submit unless the user flow explicitly calls for it.
269
333
 
270
- Do not assume Playwright selector dialects such as `text=Close` or `button:has-text('Close')` are supported wrapper syntax. If you need those forms, verify current upstream `agent-browser` behavior first; otherwise use refs, `find`, or known CSS selectors.
334
+ Do not assume Playwright selector dialects such as `text=Close` or `button:has-text('Close')` are supported wrapper syntax. In particular, current upstream can report successful `scrollintoview text=...` without moving the page, so the wrapper rejects that form before dispatch—directly or in an effective raw/stdin batch row—and shows executable `find text <label> hover` plus snapshot/ref recovery payloads in visible failure text and `details.nextActions`. `scrollintoview ... --help` and `-h` remain native help calls. Use `scrollintoview` with CSS, `xpath=...`, or a current `@e…` ref; use `find` for semantic text targets.
271
335
 
272
- Treat `@e…` refs as page-scoped. After a successful `snapshot`, the wrapper records the latest refs and page target for that session; mutation-prone ref commands such as non-form `click @e4`, `select @e5 chocolate`, or batch steps with old refs fail with `failureCategory: "stale-ref"` when the page target changed or the ref is absent from the latest same-page snapshot. If a session `snapshot -i` fails with `No active page`, the wrapper invalidates prior refs for that session; later mutation-prone `@e…` calls fail before upstream until a successful fresh `snapshot -i` records refs again. Inside `batch` stdin JSON, the wrapper also walks steps in order before spawn: steps whose first token can navigate or mutate set a latch; a later step whose first token is `snapshot` clears that latch for following rows; guarded steps that still mention `@e…` after an uncleared latch fail with the same `stale-ref` bucket without launching upstream. Same-snapshot form fills and native form-control steps are allowed before a click or submit step, so `fill`, `check`/`uncheck` checkbox or radio refs, checkbox/radio `click`/`tap` refs, `select` combobox refs, then a final submit `click` can run from one snapshot. Split dynamic or autosubmit forms with a fresh snapshot if a control interaction rerenders the targets. Follow the `refresh-interactive-refs` next action (it includes `--session <name>` when needed) and prefer stable `find` or `semanticAction` locators when navigation or rerendering is likely. Contract detail: [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details) (`refSnapshot`, `refSnapshotInvalidation`).
336
+ Treat `@e…` refs as page-scoped. After a successful `snapshot`, the wrapper records the latest refs and page target for that session; getter or mutation ref commands such as `get text @e4`, `click @e4`, `select @e5 chocolate`, or batch steps with old refs fail with `failureCategory: "stale-ref"` when the page target changed or the ref is absent from the latest same-page snapshot. If a session `snapshot -i` fails with `No active page`, the wrapper invalidates prior refs for that session; later mutation-prone `@e…` calls fail before upstream until a successful fresh `snapshot -i` records refs again. Inside `batch` stdin JSON, the wrapper also walks steps in order before spawn: steps whose first token can navigate or mutate set a latch; a later step whose first token is `snapshot` clears that latch for following rows; guarded steps that still mention `@e…` after an uncleared latch fail with the same `stale-ref` bucket without launching upstream. Same-snapshot form fills and native form-control steps are allowed before a click or submit step, so `fill`, `check`/`uncheck` checkbox or radio refs, checkbox/radio `click`/`tap` refs, `select` combobox refs, then a final submit `click` can run from one snapshot. Split dynamic or autosubmit forms with a fresh snapshot if a control interaction rerenders the targets. Follow the `refresh-interactive-refs` next action (it includes `--session <name>` when needed) and prefer stable `find` or `semanticAction` locators when navigation or rerendering is likely. Contract detail: [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details) (`refSnapshot`, `refSnapshotInvalidation`).
273
337
 
274
338
  A successful `click` result means upstream reported a target, not that the app definitely handled the event. For top-level non-Electron direct clicks on `xpath=` targets and eligible current `@e…` refs, the wrapper installs a bounded target-specific DOM-event probe when it can; when upstream reports success but no trusted event reaches the resolved target, it fails the tool and exposes `details.clickDispatch` plus a `Click dispatch diagnostic` line with explicit retry/inspect next actions (no in-page click replay). Raw `find … click` locator calls are not probed because the wrapper has no concrete element before upstream resolves the locator, and document-level probes can falsely fail frame-scoped clicks. Direct `@e…` click probes are role-gated to current snapshot refs whose accessible role is `button`, `checkbox`, `menuitem`, `radio`, `switch`, or `tab`; duplicate names use snapshot order. If the probe evidence shows the target is outside a nested scroll container or viewport, `details.clickDispatch.scrollContainer` and `scroll-target-into-view-after-dispatch-miss` point to `scrollintoview <target>` before retry. When the workflow depends on a mutation, use `details.pageChangeSummary`, a wait, URL/text extraction, or a fresh `snapshot -i` before trusting the state; if nothing changed, retry with a current visible ref or stable selector and report the workflow issue. For static local fixtures or debugging where the user explicitly accepts scripted activation, `eval --stdin` can call `document.querySelector(...).click()` to exercise inline handlers and app code; treat that as an untrusted programmatic event, not as evidence that CDP/user-like clicking works. Respect explicit user stop boundaries yourself: if the user says to stop before a final order, post, purchase, or submit action, gather evidence from that page and do not click the final action or use scripted activation to bypass the stop. The wrapper does not infer broad business intent from prompt text; `details.promptGuard` is reserved for concrete artifact-before-close checks. `press`, `key`, `keydown`, and `keyup` accept exactly one key token; focus or click the target first, then run `press Enter` or another single-key command.
275
339
 
@@ -286,7 +350,7 @@ Successful `snapshot -i` results can also surface `Possible overlay blockers` wh
286
350
  { "args": ["eval", "--stdin"], "stdin": "document.title" }
287
351
  ```
288
352
 
289
- Use `read [url]` for documentation and other unstructured text. `read <url> --raw` preserves the response body, `read <url> --require-md` requires `text/markdown`, `read <url> --llms <index|full>` reads the nearest ancestor llms index/full file, `read <url> --outline` emits headings, `read <url> --filter <text>` narrows matching sections/headings/links, and `read <url> --timeout <ms>` changes the request timeout. Explicit URL reads prefer markdown, try a `.md` path and nearby `llms.txt` links, then fall back to readable HTML without launching Chrome. Omit the URL to read rendered active-tab DOM, including current browser auth and client-side state; `--llms` / `--require-md` without a URL instead fetch from the active tab URL. The wrapper renders `data.content` first, retains source/content-type/status/final-URL metadata in `details.data`, keeps fetched URLs from replacing the active browser tab target, and extends its subprocess watchdog for explicit long read timeouts.
353
+ Use `read [url]` for documentation and other unstructured text. `read <url> --raw` preserves the response body, `read <url> --require-md` requires `text/markdown`, `read <url> --llms <index|full>` reads the nearest ancestor llms index/full file, `read <url> --outline` emits headings, `read <url> --filter <text>` narrows matching sections/headings/links, and `read <url> --timeout <ms>` changes the request timeout. Explicit URL reads prefer markdown, try a `.md` path and nearby `llms.txt` links, then fall back to readable HTML without requiring a Chrome page. The wrapper still starts the CLI under its managed identity. A visible `Read execution` line reports the fetch source, CLI start, managed browser lifecycle, and managed-session outcome; the same facts remain in `details.readSource`, `details.lifecycle.effectiveLaunch.browserLaunched`, `details.agentBrowserStarted`, and `details.managedSessionOutcome`. The lifecycle boolean can be `false` before any browser launch or `true` when reusing an active browser. Omit the URL to read rendered active-tab DOM, including current browser auth and client-side state; `--llms` / `--require-md` without a URL instead fetch from the active tab URL. The wrapper renders `data.content` first, retains source/content-type/status/final-URL metadata in `details.data`, keeps fetched URLs from replacing the active browser tab target, and extends its subprocess watchdog for explicit long read timeouts.
290
354
 
291
355
  When you already know several visible refs or selectors, extract them in one `batch` call instead of many serial getter calls:
292
356
 
@@ -296,7 +360,7 @@ When you already know several visible refs or selectors, extract them in one `ba
296
360
 
297
361
  Prefer `get` and scoped `eval --stdin` for read-only extraction. Getter names are grouped under `get`: use `get title`, `get url`, or `get text <selector>`, not shortcut commands such as `title` or `url`. When upstream reports an unknown command, unknown subcommand, or unrecognized command for a single-token shortcut (`attr`, `count`, `html`, `text`, `title`, `url`, or `value`), the wrapper adds a visible grouped-`get` hint; only `title` and `url` also get exact read-only `details.nextActions` (`use-get-title` / `use-get-url`, with `--session` preserved when the failed call named a session). If another `Agent-browser hint:` (selector dialect or stale-ref recovery) was already appended to the same error text, the getter hint is omitted.
298
362
 
299
- Return the intended JavaScript value from `eval --stdin` instead of relying on `console.log`. In the native pi tool, the JavaScript belongs in the top-level `stdin` field; do **not** write it as a third `args` item such as `{ "args": ["eval", "--stdin", "document.title"] }`. The wrapper tolerates that common misplaced form by moving the trailing token to stdin before spawn, but the explicit `stdin` field is the documented form and avoids ambiguity for multiline snippets. For object-shaped extraction, pass a plain expression such as `({ title: document.title, url: location.href })`; if the result should be kept outside the transcript as a durable file, add top-level `outputPath` (for example `{ "args": ["eval", "--stdin"], "stdin": "({ title: document.title })", "outputPath": "logs/page-title.json" }`). If you send a function-shaped snippet, invoke it explicitly, for example `(() => ({ title: document.title }))()`. When upstream serializes a function result to `{}`, the wrapper can append `Eval stdin hint` and `details.evalStdinHint`.
363
+ Return the intended JavaScript value from `eval --stdin` instead of relying on `console.log`. In the native pi tool, the JavaScript belongs in the top-level `stdin` field; do **not** write it as a third `args` item such as `{ "args": ["eval", "--stdin", "document.title"] }`. The wrapper tolerates that common misplaced form by moving the trailing token to stdin before spawn, but the explicit `stdin` field is the documented form and avoids ambiguity for multiline snippets. For object-shaped extraction, pass a plain expression such as `({ title: document.title, url: location.href })`; if the result should be kept outside the transcript as a durable file, add top-level `outputPath` (for example `{ "args": ["eval", "--stdin"], "stdin": "({ title: document.title })", "outputPath": "logs/page-title.json" }`). If you send a function-shaped snippet, invoke it explicitly, for example `(() => ({ title: document.title }))()`. When upstream serializes a function result to `{}`, the wrapper can append `Eval stdin hint` and `details.evalStdinHint`. Snippets run in the page's per-tab global scope, so top-level `const`/`let`/`function` declarations persist across calls and later snippets can fail with `SyntaxError: Identifier ... has already been declared`; wrap multi-statement extraction in an IIFE instead of redeclaring names. After a failed `eval`, `back`/`forward`/`reload`, `connect`, `state load`, or `tab` selection, the wrapper probes the live page URL itself and keeps an observed page verified, so follow-up reads do not need a manual `get url` unless the result says the page became unverified; because the failed command may still have changed the document, prior page-scoped refs are invalidated and need a fresh `snapshot -i` before reuse.
300
364
 
301
365
  On tabbed or hidden-DOM pages, `get text <selector>` reads the upstream-selected match, which may be hidden even when a later match is visible. For non-`@ref`, non-simple-id CSS selectors with multiple matches, including successful `batch` steps, the wrapper may add `Selector text visibility warning`, `details.selectorTextVisibility` (and `details.selectorTextVisibilityAll` for multiple batched warnings), and `inspect-visible-text-candidates` next actions. The warning names the matching `details.nextActions` id so agents know to use a fresher `snapshot -i`, a visible `@ref`, or a more specific selector instead of trusting hidden tab content. If the probe still leaves multiple visible candidates, do not keep reading the broad selector; switch to a current visible `@ref`, add a narrower selector such as a known panel/container id, or use a targeted `eval --stdin` expression that filters for visible elements and returns the intended index/text.
302
366
 
@@ -359,7 +423,7 @@ On app pages that expose a native dropdown, add a `select` step such as `{ "acti
359
423
 
360
424
  Use raw `args: ["batch"]` with `stdin` when you need arbitrary upstream commands, flags, or batch failure policies outside the constrained schema. Do not pass `stdin` with `job`, `qa`, `sourceLookup`, `networkSourceLookup`, or `electron`; those modes generate or manage their own input.
361
425
 
362
- For quick smoke/QA checks, use top-level `qa`. It clears enabled network/console/page-error buffers before opening the target URL, waits for page readiness, checks expected text/selector, then inspects fresh network requests, console messages, and page errors only if preceding assertions pass, and can capture an evidence screenshot. Successful reset rows are labeled as reset-scoped diagnostic output and are not counted as current-page QA failures; post-open diagnostic rows still fail or warn normally. The preset compiles to `batch --bail` so a missing text/selector assertion fails crisply instead of letting slower diagnostics burn the wrapper watchdog. Expected text compiles to bounded visible-text `wait --fn … --timeout 5000` predicates after load so dense pages can pass on visible headings/copy without dumping `body` text; missing text reports a crisp QA failure. The readiness wait defaults to `loadState: "domcontentloaded"`; set `loadState` to `"load"` or `"networkidle"` only when that stricter state is useful and the site is not expected to keep background requests alive. QA network diagnostics classify failed requests by likely impact and list failed rows first in the network preview: actionable document/script/API-style failures fail the preset, while common low-impact browser icon misses such as `favicon.ico` are surfaced as warnings (`qaPreset.warnings`) so they do not fail an otherwise healthy page. Successful QA with no failed checks returns compact model-visible prose (page URL/title when known, checks run, optional screenshot verification) while keeping the full step matrix in `details.qaPreset` and `details.batchSteps`. Failed QA presets report `details.resultCategory: "failure"`, `failureCategory: "qa-failure"`, keep verbose per-step batch output, and real Pi sessions treat the diagnostic as a failed tool result. Prose output also gets a model-visible result-category line including `Pi tool isError: true`; caller-requested `--json` output keeps the JSON string parseable and relies on the patched `isError` plus `details` fields.
426
+ For quick smoke/QA checks, use top-level `qa`. It clears enabled network/console buffers and snapshots any page-error residue after the unreliable upstream clear, then opens the target URL and gives immediate post-load console/page-error callbacks a bounded 150 ms settle, waits for page readiness, checks expected text/selector, then inspects fresh network requests, console messages, and page errors only if preceding assertions pass, and can capture an evidence screenshot. Successful reset rows are labeled as reset-scoped diagnostic output. Only unchanged page-error residue left after the clear is ignored; a matching error that reappears after a successful clear and other post-open diagnostic rows still fail or warn normally. The preset compiles to `batch --bail` so a missing text/selector assertion fails crisply instead of letting slower diagnostics burn the wrapper watchdog. Expected text compiles to bounded visible-text `wait --fn … --timeout 5000` predicates after load so dense pages can pass on visible headings/copy without dumping `body` text; missing text reports a crisp QA failure. The readiness wait defaults to `loadState: "domcontentloaded"`; set `loadState` to `"load"` or `"networkidle"` only when that stricter state is useful and the site is not expected to keep background requests alive. QA network diagnostics classify failed requests by likely impact and list failed rows first in the network preview: actionable document/script/API-style failures fail the preset, while common low-impact browser icon misses such as `favicon.ico` are surfaced as warnings (`qaPreset.warnings`) so they do not fail an otherwise healthy page. Successful QA with no failed checks returns compact model-visible prose (page URL/title when known, checks run, optional screenshot verification) while keeping the full step matrix in `details.qaPreset` and `details.batchSteps`. Failed QA presets report `details.resultCategory: "failure"`, `failureCategory: "qa-failure"`, keep verbose per-step batch output, and real Pi sessions treat the diagnostic as a failed tool result. Prose output also gets a model-visible result-category line including `Pi tool isError: true`; caller-requested `--json` output keeps the JSON string parseable and relies on the patched `isError` plus `details` fields.
363
427
 
364
428
  The same classification drives plain `network requests` presentation: when any row counts as failed (HTTP status ≥ 400, `failed: true`, or a string `error`), model-facing text starts with a line like `Network failure summary: 0 actionable, 1 benign low-impact (1 total).`, and each preview line can end with an impact tag such as `[benign: low-impact browser icon asset]` or `[actionable: document, script, API, or non-benign request failure]`. When safe request IDs are present, `details.nextActions` adds bounded read-only follow-ups such as `network request <id>`, `networkSourceLookup` for actionable failed rows, `network requests --filter <path>`, `network requests --clear` before a repro, and `network har start`; prefer those payloads over rebuilding request-id commands from prose. For aggregate buffers, the wrapper accepts `network requests --current-page` / `--current-origin` to render only rows matching the active page origin, or `--current-url` for exact active document URL matching; it strips those wrapper-only flags before upstream spawn and reports counts in `details.networkRequestsPageFilter`. If the wrapper has seen a prior `network route` in the same session, matching failed, pending, or CORS-looking fetch/XHR rows add `details.networkRouteDiagnostics` plus executable route-mock follow-ups (`inspect-routed-network-request` and `start-network-har-capture-for-route-mock`) so agents do not mistake an unfulfilled mock for a fulfilled mock; same-origin/CORS fixture retry guidance stays in visible prose. `network requests` also hides `data:image` screenshot/artifact noise from the compact preview by default while preserving raw rows in `details.data.requests`. Rules live in `classifyNetworkRequestFailure` / `summarizeNetworkFailures` in `extensions/agent-browser/lib/results/network.ts`; QA aggregation is `analyzeQaPresetResults` in `extensions/agent-browser/index.ts`.
365
429
 
@@ -369,7 +433,7 @@ The same classification drives plain `network requests` presentation: when any r
369
433
 
370
434
  Optional `loadState`, `checkNetwork`, `checkConsole`, and `checkErrors` default to `"domcontentloaded"`, `true`, `true`, and `true` for URL-opening QA; set a check to `false` to skip that diagnostic. For `qa.attached`, the diagnostic checks default to `false` because upstream buffers may predate the current check; opt in with `checkNetwork`, `checkConsole`, or `checkErrors` when preserved-buffer failures are desired. Omit `expectedText` and `expectedSelector` when you only need load plus diagnostics.
371
435
 
372
- For attached Electron or manually connected CDP sessions, use `qa.attached` after the session exists. It does not open a URL and rejects `sessionMode: "fresh"` because it checks the current managed session. Before running diagnostics, the wrapper requires a readable `http:` or `https:` page URL on the attached session; missing URLs, read failures, and non-http(s) surfaces fail fast with recovery `nextActions` such as `tab list` and `snapshot -i` instead of running the full QA batch. Unlike URL-opening QA, `qa.attached` preserves existing upstream network/console/page-error buffers; by default it does not inspect those buffers so stale rows do not false-fail a current-page smoke check. Set `checkNetwork`, `checkConsole`, or `checkErrors` to `true` to opt into preserved-buffer diagnostics; model-visible text and `details.compiledQaPreset.checks.diagnosticsResetAtStart` call out that preserved diagnostics may include earlier events.
436
+ For attached Electron or manually connected CDP sessions, use `qa.attached` after the session exists. It does not open a URL and rejects `sessionMode: "fresh"` because it checks the current managed session. Before running diagnostics, the wrapper requires a readable non-empty page URL on the attached session; missing URLs and read failures fail fast with recovery `nextActions` such as `tab list` and `snapshot -i` instead of running the full QA batch. `file:`, custom-scheme, and other attached targets are accepted. Unlike URL-opening QA, `qa.attached` preserves existing upstream network/console/page-error buffers; by default it does not inspect those buffers so stale rows do not false-fail a current-page smoke check. Set `checkNetwork`, `checkConsole`, or `checkErrors` to `true` to opt into preserved-buffer diagnostics; model-visible text and `details.compiledQaPreset.checks.diagnosticsResetAtStart` call out that preserved diagnostics may include earlier events.
373
437
 
374
438
  ```json
375
439
  { "qa": { "attached": true, "expectedText": "Explorer", "screenshotPath": ".dogfood/electron.png" } }
@@ -420,7 +484,7 @@ For local app debugging, top-level `sourceLookup` can gather candidate component
420
484
  { "sourceLookup": { "selector": "#save", "reactFiberId": "2", "componentName": "SaveButton" } }
421
485
  ```
422
486
 
423
- Top-level `networkSourceLookup` does the same for failed browser requests. When `requestId` is set it adds `network request <requestId>`; when `filter` or `url` is set it also adds `network requests --filter …`, using `url` as the filter pattern when `filter` is omitted. Add `namespace` / `session` when the generated batch should target an explicit upstream namespace/session. With `requestId` only, the compiled batch is just that request step; failed-request detection still walks the returned batch JSON and treats HTTP status ≥ 400, `failed: true`, or an `error` field as failure. When `filter` or `url` is present, the same heuristics apply but requests are correlated only if their URL matches that substring (either direction). Workspace URL literal search under the Pi session cwd reuses the `sourceLookup` scan rules (`maxWorkspaceFiles` defaults to 2000, hard cap 5000, at most ten `workspace-search` rows, up to eight URL/path needles from the query plus failed request URLs). It reports `details.networkSourceLookup.status` as `failed-requests-found`, `no-failed-requests`, or `no-candidates` and never assigns definitive blame. Request-detail URLs are diagnostic evidence, not active-tab evidence: standalone `network request …` and generated `networkSourceLookup` batches preserve the previous app page target and latest same-page `refSnapshot`.
487
+ Top-level `networkSourceLookup` does the same for failed browser requests. When `requestId` is set it adds `network request <requestId>`; when `filter` or `url` is set it also adds `network requests --filter …`, using `url` as the filter pattern when `filter` is omitted. Add `namespace` / `session` when the generated batch should target an explicit upstream namespace/session; `namespace: ""` explicitly selects the default namespace and overrides an ambient namespace. With `requestId` only, the compiled batch is just that request step; failed-request detection still walks the returned batch JSON and treats HTTP status ≥ 400, `failed: true`, or an `error` field as failure. When `filter` or `url` is present, the same heuristics apply but requests are correlated only if their URL matches that substring (either direction). Workspace URL literal search under the Pi session cwd reuses the `sourceLookup` scan rules (`maxWorkspaceFiles` defaults to 2000, hard cap 5000, at most ten `workspace-search` rows, up to eight URL/path needles from the query plus failed request URLs). It reports `details.networkSourceLookup.status` as `failed-requests-found`, `no-failed-requests`, or `no-candidates` and never assigns definitive blame. Request-detail URLs are diagnostic evidence, not active-tab evidence: standalone `network request …` and generated `networkSourceLookup` batches preserve the previous app page target and latest same-page `refSnapshot`.
424
488
 
425
489
  ```json
426
490
  { "networkSourceLookup": { "requestId": "req-1", "url": "/api/fail" } }
@@ -438,17 +502,17 @@ Do not omit the load state value; use `wait --load <state>` with `load`, `domcon
438
502
 
439
503
  For desktop-host readiness, prefer condition waits over fixed sleeps. Use this ladder: `wait --text` / `wait --url` / `wait --fn` / `wait --load <state>` / `wait --download` when a real condition exists; after raw `connect`, run `tab list` → `tab t<N>` → condition wait or `snapshot -i`; after wrapper-owned `electron.launch`, use `electron.probe` / `electron.status` for launch health or target mismatch; use `qa.attached` when expected text or selector plus diagnostics can express the check. Upstream `agent-browser 0.31.1` supports `wait --url` glob forms such as `**/dashboard` against the full active URL. Fixed waits are a last resort: use explicit `--timeout` or top-level `timeoutMs` for legitimately slow waits, and treat a successful fixed-wait payload such as `"waited":"timeout"` as elapsed time only, not proof that the desktop host finished. Verify with an observed condition, fresh snapshot, or screenshot before continuing.
440
504
 
441
- Use `wait --download [path]` after an earlier action has already started a browser download, such as a dashboard export button that responds asynchronously:
505
+ Use `wait --download [path]` after an earlier action has already started a browser download, such as a dashboard export button that responds asynchronously. Use the control's current snapshot ref (for example `@e5`):
442
506
 
443
507
  ```json
444
- { "args": ["click", "@export"] }
508
+ { "args": ["click", "@e5"] }
445
509
  { "args": ["wait", "--download", "/tmp/report.csv"] }
446
510
  ```
447
511
 
448
512
  For one-call flows, put the click and wait in `batch`; the wait step keeps the saved-file metadata in `details.batchSteps[n].savedFilePath` and `details.batchSteps[n].savedFile`:
449
513
 
450
514
  ```json
451
- { "args": ["batch"], "stdin": "[[\"click\",\"@export\"],[\"wait\",\"--download\",\"/tmp/report.csv\"]]" }
515
+ { "args": ["batch"], "stdin": "[[\"click\",\"@e5\"],[\"wait\",\"--download\",\"/tmp/report.csv\"]]" }
452
516
  ```
453
517
 
454
518
  A successful wait-based download renders a readable summary such as `Download completed: /tmp/report.csv` and exposes top-level `details.savedFilePath` plus `details.savedFile` for non-batch calls. With current upstream `agent-browser`, `wait --download <path>` may report the requested path before this environment can verify that the file was persisted there. Treat `details.savedFilePath` as upstream-reported metadata unless `details.artifacts[].exists` is true. Upstream tracking: [vercel-labs/agent-browser#1300](https://github.com/vercel-labs/agent-browser/issues/1300).
@@ -469,11 +533,11 @@ Prefer `download <selector> <path>` when the target element itself is the downlo
469
533
 
470
534
  For evidence-only screenshots, QA captures, or audit artifacts, save to an explicit path and branch on `details.artifactVerification` plus `details.artifacts` before reporting PASS/FAIL. Inline image attachments are optional convenience when size limits allow; do not require vision review unless the user asked for visual inspection.
471
535
 
472
- Wrapper result rendering is metadata-first for saved files:
536
+ Wrapper result rendering is metadata-first for saved files. An artifact-producing command fails as `artifact-missing` with artifact `status: "stale"` when the reported path's `mtimeMs` falls outside the command's bounded start/end window (with two seconds of filesystem precision tolerance), including a previous recording that `record restart` claims to finalize; clearly old or future-dated evidence is never accepted as a fresh capture. A batch, whether supplied through stdin arrays or argument command strings, must use distinct explicit artifact destinations; preflight canonicalizes existing path ancestry, compares existing file identities to catch hardlinks, and applies full Unicode plus platform case folding on macOS/Windows so aliases cannot satisfy another step's verification. The same preflight prevents `outputPath` from aliasing a same-call browser artifact, follows upstream's forward option consumption and final effective `-o` / `--output` for `diff screenshot`, and treats the optional path on `network har stop` as an artifact destination; upstream ignores positional paths on `network har start`. Artifact and lifecycle parsing first removes upstream global flags wherever they occur, so accepted forms such as `record --json start <path>` and `pdf --quiet <path>` cannot shift or bypass destination tracking. Screenshot destination parsing mirrors upstream's exact flag matching and `[selector] [path]` positional order: `--` is positional, `true` / `false` after screenshot-only `--full` / `-f` remain positional, extra positionals are ignored after the path slot, selector-prefixed (`.`, `#`, `@`) or uppercase-extension single arguments remain selectors, and lowercase image extensions or slash-bearing arguments are paths. The wrapper deliberately keeps its existing slash-bearing hidden-workspace path normalization (for example `.dogfood/run/foo.png`) before launch. `wait --download` is observational and may verify a download that completed just before the wait began, so it is exempt from the command-window mtime gate; an explicit wait destination, in long `--download <path>` or short `-d <path>` form (including after `--timeout`), still participates in active-recording reservation preflight; unsupported `--download=<path>` fails with split-argument guidance:
473
537
  - screenshots return a saved-path summary, visible artifact metadata, structured `details.artifacts` metadata, and an inline image attachment when safe; the visible block includes artifact type, requested path, absolute path, existence, size, cwd, session, and repair/copy status when applicable
474
538
  - downloads, PDFs, `wait --download` files, `state save` state files, diff screenshot output images, traces, CPU profiles, completed WebM recordings from `record stop`, and path-bearing HAR captures return concise saved-path summaries plus structured `details.artifacts` metadata without inlining large files
475
- - `record start <path>` and `record restart <path>` report that recording started and that output will be written on `record stop`; `details.artifacts` / `details.artifactVerification` mark that future file as `pending` with `recordingState: "openRecording"` and `willExistOnStop: true` instead of reporting a missing file. When `record restart` finalizes a previous wrapper-known recording and that file is now present on disk, the result also includes `Previous recording saved: …` before the new pending recording block. The target may not exist until recording stops, and upstream needs `ffmpeg` on `PATH` at stop time to encode the WebM. If `ffmpeg` is missing after a successful `record start` / `record restart`, the wrapper appends `Recording dependency warning: ffmpeg not found on PATH` and sets `details.recordingDependencyWarning` without blocking the upstream command.
476
- - `batch` keeps each step's artifacts in `details.batchSteps[].artifacts` and aggregates them in top-level `details.artifacts` in step order
539
+ - `record start <path>` and `record restart <path>` report `successCategory: "artifact-pending"` and that output will be written on `record stop`; `record start` also states that upstream switches to a fresh active page for video capture, prior in-page DOM and JavaScript state does not carry over, and the next interaction should follow a fresh snapshot — the wrapper invalidates the session’s prior ref snapshot (direct calls and batch steps alike, and even when the start fails with `Recording already active`, because upstream swaps the page before that check), so old `@e…` refs fail as `stale-ref` until a fresh `snapshot -i` succeeds; `record restart <path> <url>` navigates the current page and invalidates refs the same way, while a plain `record restart <path>` keeps the current page and refs; `details.artifacts` / `details.artifactVerification` mark that future file as `pending` with `recordingState: "openRecording"` and `willExistOnStop: true`, and `details.nextActions` includes exact `stop-pending-recording` args. When `record restart` finalizes a previous wrapper-known recording, that file must exist and fall within the command mtime window before the result includes `Previous recording saved: …`; a missing or stale prior file fails as `artifact-missing` while the new recording remains visible as pending and the prior manifest row is retired. Within one Pi extension process, an unbounded transcript-backed index reserves active recording destinations independently of the bounded artifact manifest. Artifact lifecycle calls and result `outputPath` writes serialize around that global check; reservations use canonical namespace/session identity, survive manifest eviction and branch replay, and retire after direct, ordered nested-batch, fresh-replacement, script, Electron, or shutdown close; the newest pending row per identity is authoritative. Legacy batch replay retires a pending manifest only when the ordered close lifecycle leaves recording closed; a later successful browser reactivation plus `record start` keeps the new pending reservation. Lexical, hardlink, existing/dangling symlink, full Unicode-fold, and macOS/Windows case aliases are rejected, so `record restart` must use a distinct new path. Do not place `record start` or `record restart` after `close` / `quit` / `exit` in one batch: wrapper preflight rejects it because upstream can report success without starting a recording; split the close and recording into separate calls. A definitive `No recording in progress` stop failure, whether direct or inside a batch, retires stale reservation state at that ordered step; a later successful batch recording row opens its new pending path normally. Any success or failure result that still contains pending recording output includes `stop-pending-recording`. The target may not exist until recording stops, and upstream needs `ffmpeg` on `PATH` at stop time to encode the WebM. If `ffmpeg` is missing after a successful `record start` / `record restart`, the wrapper appends `Recording dependency warning: ffmpeg not found on PATH` and sets `details.recordingDependencyWarning` without blocking the upstream command.
540
+ - `batch` keeps each step's artifacts in `details.batchSteps[].artifacts`; top-level `details.artifacts` and `details.artifactManifest` coalesce an earlier pending recording into the later saved, missing, or stale terminal result for the same namespace/session identity; a successful later close marks an unfinalized pending recording `missing` / `close-abandoned`, removes its stop action, and resets earlier ref/page/network-route batch state; a later successful `record stop` replaces that intermediate abandoned row with its verified saved artifact, and later rows—including failed rows—whose lifecycle reports a browser launch may rebuild state without triggering stale pre-close `about:blank` recovery; failed-step `batchSteps[]` retains only the bounded `lifecycle.effectiveLaunch.browserLaunched` boolean for replay, explicitly non-launching diagnostics leave the close terminal, missing lifecycle evidence remains conservatively active even on the first managed call, every successful close clears wrapper trace/profiler ownership before ordered later successful rows can rebuild it, namespace-scoped `close --all` clears all matching managed/attached/page/ref/route/trace/recording ownership, and any later same-session failure before recording stops keeps exact `stop-pending-recording` args alongside its normal recovery
477
541
 
478
542
  `diff screenshot` follows the file-artifact path above for the **diff** image: model-visible text and `details.artifacts` focus on that output, while baseline paths stay out of the artifact summary block, and Pi does **not** auto-inline the diff the way it inlines trusted `screenshot` captures. `state load` may print the loaded path in prose but does not add a saved-file artifact entry the way `state save` does.
479
543
 
@@ -493,7 +557,7 @@ This manifest cap controls what appears in `details.artifactManifest` and in sum
493
557
 
494
558
  Browser close commands (`close`, `quit`, or `exit`) are also not file cleanup. If `details.artifactManifest` is present with a non-empty `entries` list, a successful close command appends a compact `Artifact lifecycle` note and reports `details.artifactCleanup` with the current retention summary and the same host-owned cleanup `note` as the contract (`extensions/agent-browser/lib/orchestration/browser-run/diagnostics.ts`, `getArtifactCleanupGuidance`). Up to ten distinct user-chosen paths that still exist on disk appear in `explicitArtifactPaths` when matching `explicit-path` manifest rows exist in the recent window; deleted/stale paths are skipped. Otherwise that array is empty and the visible text stays compact while the structured detail still reminds you that close commands do not delete saved files. Delete any paths you care about with host file tools after inspection; the native browser tool intentionally does not remove arbitrary user-chosen filesystem paths.
495
559
 
496
- Oversized snapshots and oversized generic outputs are different: when a persisted pi session is available, their wrapper-managed spill files are stored under the private session artifact directory and are governed by the byte budget `PI_AGENT_BROWSER_SESSION_ARTIFACT_MAX_BYTES` (default 32 MiB). Raise that byte budget as well for long QA sessions that need many full raw snapshots or large text spills to survive reload/resume.
560
+ Oversized snapshots and oversized generic outputs are different: when a persisted pi session is available, their wrapper-managed spill files are stored under the private session artifact directory and are governed by the byte budget `PI_AGENT_BROWSER_SESSION_ARTIFACT_MAX_BYTES` (default 32 MiB). Raise that byte budget as well for long QA sessions that need many full redacted snapshots or large text spills to survive reload/resume.
497
561
 
498
562
  ### Switch from an already-active implicit session to a fresh profiled or alternate-browser launch
499
563
 
@@ -538,7 +602,7 @@ If the result says `Pending confirmation id: c_8f3a1234`, choose one follow-up:
538
602
  { "args": ["deny", "c_8f3a1234"] }
539
603
  ```
540
604
 
541
- Confirmation context may be redacted when it contains credentials, tokens, cookies, or auth-bearing URLs. Use the id exactly as printed.
605
+ Confirmation context may be redacted when it contains credentials, tokens, cookies, or auth-bearing URLs. URL scrubbing covers SAMLRequest, SAMLResponse, RelayState, and auth-context `state` / `nonce` while retaining ordinary non-auth state URLs; persisted snapshot spills receive the same redaction, while exact internal page-target URLs remain available to browser state logic. Use the id exactly as printed.
542
606
 
543
607
  ### Use stateful browser-context commands safely
544
608
 
@@ -583,7 +647,7 @@ Session note: `skills list`, `skills get …`, and `skills path …` are **state
583
647
  | `skills list` | List available CLI-bundled skills. |
584
648
  | `skills get core` | Print the core usage guide. |
585
649
  | `skills get core --full` | Print the full version-matched core command reference and templates. |
586
- | `skills get <name>` | Load a specialized skill such as `electron` or `slack`. Common specialized calls include `skills get electron`, `skills get slack`, `skills get dogfood`, `skills get vercel-sandbox`, `skills get agentcore`, and `skills get derive-client` (HAR-to-API-client workflow). |
650
+ | `skills get <name>` | Load a specialized skill such as `electron` or `slack`. Common specialized calls include `skills get electron`, `skills get slack`, `skills get dogfood`, `skills get vercel-sandbox`, `skills get agentcore`, `skills get derive-client` (HAR-to-API-client workflow), and `skills get webmcp-gen` (create and validate page tools). |
587
651
  | `skills get <name> --full` | Include a skill's supplementary references/templates when present. |
588
652
  | `skills get --all` | Print all visible bundled skills for broad audit/debug work. |
589
653
  | `skills path [name]` | Print a skill directory path. |
@@ -596,7 +660,7 @@ Skill-source debugging note: upstream honors `AGENT_BROWSER_SKILLS_DIR` as an ov
596
660
  | --- | --- |
597
661
  | `open [url]` | Launch the browser and optionally navigate. URL-less `open` stays on `about:blank` so agents can stage routes, cookies, or init scripts before first navigation. |
598
662
  | `open <url>` | Navigate to a URL; `goto <url>` and `navigate <url>` are equivalent navigation aliases when a URL is present. |
599
- | `read [url]` | Fetch agent-readable text from an explicit URL without launching Chrome, or omit the URL to read rendered active-tab DOM. Supports `--raw`, `--require-md`, `--llms <index|full>`, `--outline`, `--filter <text>`, and `--timeout <ms>`. |
663
+ | `read [url]` | Fetch agent-readable text from an explicit URL without requiring a Chrome page, or omit the URL to read rendered active-tab DOM. Supports `--raw`, `--require-md`, `--llms <index|full>`, `--outline`, `--filter <text>`, and `--timeout <ms>`. |
600
664
  | `click <sel>` | Click an element or `@ref`. |
601
665
  | `click <sel> --new-tab` | Click a link/control while requesting a new tab. |
602
666
  | `dblclick <sel>` | Double-click an element. |
@@ -631,9 +695,9 @@ Skill-source debugging note: upstream honors `AGENT_BROWSER_SKILLS_DIR` as an ov
631
695
  | `tap <selector>` | Touch-oriented tap alias for iOS/provider workflows. |
632
696
  | `swipe <direction> [distance]` | Touch-oriented swipe for iOS/provider workflows. |
633
697
 
634
- On dashboards and other apps with nested scroll containers, `scroll <dir> [px]` can miss because a page-level wheel does not move the document or the intended pane. Without startup-scoped launch flags, the wrapper first applies ordinary `scroll <up|down|left|right> [px|percent]` directly to `document.scrollingElement` with smooth scrolling temporarily disabled; successful movement reports `details.scrollPage`. If the document cannot move, it falls back to upstream wheel behavior. For large fallback calls on an existing or fresh managed session, the wrapper samples viewport and prominent scroll-container positions before and after the command; when nothing changes it prepends `Scroll completed with no observed movement`, appends `Scroll diagnostic: no observed scroll movement`, exposes `details.scrollNoop`, marks `details.data.scrolled: false`, and adds exact `details.nextActions` for a fresh `snapshot -i` and screenshot. Explicit CSS-container calls `scroll <selector> <up|down|left|right> [px|percent]` remain wrapper-handled and report `details.scrollContainer`; `scroll to end` / `scroll to top` report `details.scrollPage`. Calls with startup-scoped flags skip all helper shims so the requested launch configuration runs first. Use these paths before repeating page scrolls; when you need a specific element, prefer `scrollintoview <@ref>` or target the actual scrollable region.
698
+ On dashboards and other apps with nested scroll containers, `scroll <dir> [px]` can miss because a page-level wheel does not move the document or the intended pane. Without startup-scoped launch flags, the wrapper first applies ordinary `scroll <up|down|left|right> [px|percent]` directly to `document.scrollingElement` with smooth scrolling temporarily disabled; successful movement reports `details.scrollPage`. If the document cannot move, it falls back to upstream wheel behavior. For large fallback calls on an existing or fresh managed session, the wrapper samples viewport and prominent scroll-container positions before and after the command; when nothing changes it reclassifies the nominal upstream success as `failureCategory: "upstream-error"`, prepends `Scroll completed with no observed movement`, appends `Scroll diagnostic: no observed scroll movement`, exposes `details.scrollNoop`, marks `details.data.scrolled: false`, and adds exact `details.nextActions` for a fresh `snapshot -i` and screenshot. Explicit CSS-container calls `scroll <selector> <up|down|left|right> [px|percent]` remain wrapper-handled and report `details.scrollContainer`; `scroll to end` / `scroll to top` report `details.scrollPage`. Calls with startup-scoped flags skip all helper shims so the requested launch configuration runs first. Use these paths before repeating page scrolls; when you need a specific element, prefer `scrollintoview <@ref>` or target the actual scrollable region. Do not pass `text=...` to `scrollintoview`: the wrapper rejects that upstream false-success path and returns `scroll-semantic-text-target` (`find text ... hover`) plus `refresh-refs-for-scroll-target` (`snapshot -i`) actions.
635
699
 
636
- Comboboxes vary by app. For native `<select>` controls, prefer raw `select <selector> <value...>`, `semanticAction: { action: "select", selector, value|values }`, or a `job` `select` step instead of clicking option refs; native option refs can be non-boxed in CDP and fail before a real selection. A `click` or `semanticAction` role/name click may focus a searchable custom combobox without opening its option list. For explicit combobox-targeted actions such as `semanticAction` role `combobox`, the wrapper checks whether a combobox-like element is focused, has explicit `aria-expanded` state, and has no visible listbox/options open; this still applies when the semantic action first resolves to a current visible `@ref` before execution. When that happens it appends `Combobox diagnostic: focused combobox did not expose visible options`, exposes `details.comboboxFocus`, and adds exact `details.nextActions` for a fresh `snapshot -i`, `press ArrowDown`, and `press Enter`. Use those instead of assuming click alone expanded the control; reserve visible option refs for custom comboboxes after a fresh snapshot shows the intended option.
700
+ Comboboxes vary by app. For native `<select>` controls, prefer raw `select <selector> <value...>`, direct `semanticAction: { action: "select", selector, value|values }`, active-session semantic role/name or label select, or a `job` `select` step instead of clicking option refs; native option refs can be non-boxed in CDP and fail before a real selection. A `click` or `semanticAction` role/name click may focus a searchable custom combobox without opening its option list. For explicit combobox-targeted actions such as `semanticAction` role `combobox`, the wrapper checks whether a combobox-like element is focused, has explicit `aria-expanded` state, and has no visible listbox/options open; this still applies when the semantic action first resolves to a current visible `@ref` before execution. When that happens it appends `Combobox diagnostic: focused combobox did not expose visible options`, exposes `details.comboboxFocus`, and adds exact `details.nextActions` for a fresh `snapshot -i`, `press ArrowDown`, and `press Enter`. Use those instead of assuming click alone expanded the control; reserve visible option refs for custom comboboxes after a fresh snapshot shows the intended option.
637
701
 
638
702
  ### Navigation
639
703
 
@@ -685,7 +749,7 @@ These calls return plain text and stay stateless: the extension does not inject
685
749
  | `get attr <selector> <name>`, `get box <selector>`, `get styles <selector>` | Read an attribute, bounding box, or computed styles from matched elements. |
686
750
  | `is <what> <selector>` | Check `visible`, `enabled`, or `checked`. |
687
751
  | `find <locator> <value> <action> [text]` | Locator types include `role`, `text`, `label`, `placeholder`, `alt`, `title`, and `testid`; selector helpers include `find first <sel>`, `find last <sel>`, and `find nth <n> <sel>`. Role/text filters include `find role <role> --name <name>` and `find ... --exact`. Actions are `click, fill, check, hover, text` only. Prefer `find role` for semantic elements: implicit roles work (`find role heading text --name` for `<h2>`, list/banner landmarks, and similar). Default name matching is a case-insensitive substring; `--exact` makes the accessible name case-sensitive. On misses, upstream 0.32.4+ keeps locator detail such as `Names seen: …` or `No element found: getByRole(...)` instead of a generic flatten. |
688
- | `mouse <action> [args]` | `move <x> <y>`, `down [btn]`, `up [btn]`, `wheel <dy> [dx]`. Local directory `file:` pages reject interaction commands that could navigate through a ref or scripted event into protected `.agent-browser` state storage. |
752
+ | `mouse <action> [args]` | `move <x> <y>`, `down [btn]`, `up [btn]`, `wheel <dy> [dx]`. |
689
753
  | `set <setting> [value]` | `viewport <w> <h>`, `device <name>`, `geo <lat> <lng>`, `offline [on|off]`, `headers <json>`, `credentials <user> <pass>`, and `set media <features>` (`dark`, `light`, and/or `reduced-motion`). |
690
754
  | `network <action>` | `network route <url> [--abort|--body <json>] [--resource-type <csv>]`, `network unroute [url]`, `network requests [--clear] [--filter <pattern>] [--type <csv>] [--method <method>] [--status <code|range>]`, `network request <requestId>`, `network har start`, `network har start --content text` (default; embeds text bodies), `network har start --content all`, `network har start --content none`, and `network har stop [path]`. `--resource-type` filters intercepted requests by CDP resource type, such as `script`, `image`, `font`, `xhr`, or `fetch`; request listing filters accept resource types (`xhr,fetch`), methods (`POST`), and statuses (`2xx`, `400-499`). HAR files can include auth headers and bodies—do not share them unredacted. For turning a recording into a reusable API client, load `skills get derive-client`. |
691
755
  | `cookies [get|set|clear]` | Manage cookies. Full set form: `cookies set <name> <value> --url <url> --domain <domain> --path <path> --httpOnly --secure --sameSite <Strict|Lax|None> --expires <timestamp>`; also supports `cookies set --curl <file>` for JSON, cURL, or bare Cookie-header bulk imports. |
@@ -693,6 +757,23 @@ These calls return plain text and stay stateless: the extension does not inject
693
757
 
694
758
  Privacy note: `cookies get` can expose real profile cookies. Do not run it against `--profile Default` or other authenticated profiles unless the user explicitly needs cookie inspection; prefer task-specific page actions and storage checks.
695
759
 
760
+ ### WebMCP page tools
761
+
762
+ WebMCP support is experimental and browser-dependent. Locally managed Chrome enables it by default; use a fresh launch with `--no-webmcp` or set `AGENT_BROWSER_NO_WEBMCP=1` to disable it. Page tool metadata and results come from the page itself.
763
+
764
+ | Command | Purpose |
765
+ | --- | --- |
766
+ | `webmcp list` | List tools registered by the current page, including each tool's frame id, origin, schema, and annotations. |
767
+ | `webmcp invoke <tool>` | Invoke a page tool with an empty input object. |
768
+ | `webmcp invoke <tool> --params <json|@file>` | Pass a JSON object inline or read it from a caller-selected file. |
769
+ | `webmcp invoke <tool> --frame <frame-id>` | Select the registering frame when a tool name is ambiguous. |
770
+ | `webmcp invoke <tool> --detach` | Start the call and return its invocation id without waiting. |
771
+ | `webmcp invoke <tool> --timeout <ms>` | Bound a blocking invocation in milliseconds. |
772
+ | `webmcp result <id>` | Wait for or read a detached invocation result; accepts `--timeout <ms>`. |
773
+ | `webmcp cancel <id>` | Cancel an active detached invocation. |
774
+
775
+ `webmcp invoke`, `webmcp result`, and `webmcp cancel` can run page code that changes or navigates the document. The wrapper refreshes page-target evidence and invalidates prior `@e…` refs after these commands. A detached invocation that still reports `pending`, or fails to settle while its target is unknown, leaves the target unverified rather than trusting the immediate URL probe; `result`, `cancel`, `get url`, and explicit navigation remain available for recovery. `details.nextActions` replaces the blocked snapshot suggestion with `verify-page-target-after-pending-webmcp` (`get url`) and warns that the detached tool remains unsettled. After a completed WebMCP mutation, run `snapshot -i` before reusing refs; inside `batch --bail`, put `get url` before that snapshot. `webmcp list` does not invalidate refs. Attached browsers, providers, Lightpanda, Safari/iOS, and Chrome builds without the experimental CDP domain may return `webmcp_unsupported`.
776
+
696
777
  ### Tabs
697
778
 
698
779
  Stable tab ids look like `t1`, `t2`, and `t3`. Optional user labels such as `docs` or `app` are interchangeable with ids wherever a tab reference is accepted. Upstream help may refer to numeric tab positions, but this wrapper guidance uses stable `t<N>` ids because positional integers are not accepted by current upstream `agent-browser`.
@@ -703,8 +784,12 @@ Stable tab ids look like `t1`, `t2`, and `t3`. Optional user labels such as `doc
703
784
  | `tab list` | List open tabs with ids and labels. |
704
785
  | `tab new [url]` | Open a new tab. |
705
786
  | `tab new --label <name> [url]` | Open a new tab with a user label. |
706
- | `tab <t<N>|label>` | Switch to a tab by id or label. |
707
- | `tab close [t<N>|label]` | Close the current tab or a referenced tab. Generic references in workflows may say `tab close [target]`; use a stable `t<N>` id or label when you have one. |
787
+ | `tab <t<N>|label>` | Switch to a tab by id or label. CDP target ids from `tab list --json` are also accepted and stay stable across daemon restarts. |
788
+ | `tab close [t<N>|label|target]` | Close the current tab or a referenced tab. Generic references in workflows may say `tab close [target]`; use a stable `t<N>` id, label, or CDP target id when you have one. |
789
+
790
+ After successful standalone tab selection or close, the wrapper live-probes `get url` and, for non-blank pages, `get title` before committing the active target. Tab transitions always refresh the title even when the URL matches the prior tab, and an explicit selection of an existing `about:blank` tab or a close that reveals one remains on that live target instead of triggering prior-tab correction. A successful probe clears the unverified-page gate for the next command; if the probe fails, `details.sessionTabTargetUnknown` stays true and recovery still starts with `get url`.
791
+
792
+ With `--pin-tab`, a closed bound tab fails as `tab_gone` (`data.targetId`, optional `data.lastUrl`) instead of falling back to another tab.
708
793
 
709
794
  ### Snapshot
710
795
 
@@ -719,9 +804,9 @@ Stable tab ids look like `t1`, `t2`, and `t3`. Optional user labels such as `doc
719
804
  | `snapshot -d <n>` / `snapshot --depth <n>` | Limit tree depth. |
720
805
  | `snapshot -s <sel>` / `snapshot --selector <sel>` | Scope to a CSS selector. |
721
806
 
722
- When a snapshot is too large for inline output, the Pi wrapper renders a compact view before spilling the full raw snapshot to `details.fullOutputPath`. Compact snapshots are main-content-first, but dense pages and desktop host screens can still hide actionable controls in omitted content; scan `Omitted high-value controls` before opening the spill file. That bounded section favors editable/searchbox/textbox/combobox controls, named tab/surface controls, primary action buttons, and high-signal named links such as repository search results, then includes other useful controls such as checkboxes, radios, options, and menuitems that were not already listed under key refs or other refs. When that section appears, `details.data.highValueControlRefIds` repeats the same visible ref ids for programmatic follow-up alongside fields such as `previewMode`, `previewSections`, and counts on `details.data` (see [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details)).
807
+ When a snapshot is too large for inline output, the Pi wrapper renders a compact view before spilling the full redacted snapshot to `details.fullOutputPath`. Compact snapshots are main-content-first, but dense pages and desktop host screens can still hide actionable controls in omitted content; scan `Omitted high-value controls` before opening the spill file. That bounded section favors editable/searchbox/textbox/combobox controls, named tab/surface controls, primary action buttons, and named action links such as row/navigation links and repository-style result links, then includes other useful controls such as checkboxes, radios, options, and menuitems that were not already listed under key refs or other refs. When that section appears, `details.data.highValueControlRefIds` repeats the same visible ref ids for programmatic follow-up alongside fields such as `previewMode`, `previewSections`, and counts on `details.data` (see [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details)).
723
808
 
724
- For dense pages, the wrapper also accepts `snapshot -i --search <text>` and `snapshot -i --filter role=<role>` as wrapper-side filters. It runs upstream `snapshot` without those wrapper-only flags, records the full returned ref map in `details.refSnapshot` for stale-ref safety, and renders matching direct refs plus surrounding snapshot context in the model-visible snapshot with `details.snapshotFilter` counts. The visible summary distinguishes direct ref matches from surrounding lines so contextual/nested output does not look like a ref-count mismatch. Add wrapper-side `--viewport` when scroll position, viewport size, document size, and sampled scroll-container offsets matter; it runs one read-only `eval --stdin` probe and reports `details.snapshotViewport`. Add wrapper-side `--diff` to compare the current ref map with the previous wrapper-tracked snapshot for that session and report `details.snapshotDiff` added/removed/changed refs. Use these flags when you need controls like checkout buttons, all comboboxes, above/below-fold context, or a quick before/after ref delta without reading a full spill file.
809
+ For dense pages, the wrapper also accepts `snapshot -i --search <text>` and `snapshot -i --filter role=<role>` as wrapper-side filters. It runs upstream `snapshot` without those wrapper-only flags, records the full returned ref map in `details.refSnapshot` for stale-ref safety, and renders matching direct refs plus surrounding snapshot context in the model-visible snapshot with `details.snapshotFilter` counts. Search also runs one bounded read-only rendered-DOM text probe across the full document, including below-fold content and accessible labels, so visible warnings or label-only controls omitted from the accessibility snapshot still surface under `Rendered page text matches`; hidden elements stay excluded. The visible summary distinguishes direct ref matches from rendered-text/context matches so contextual output does not look like a ref-count mismatch. Add wrapper-side `--viewport` when scroll position, viewport size, document size, and sampled scroll-container offsets matter; it runs one read-only `eval --stdin` probe and reports `details.snapshotViewport`. Add wrapper-side `--diff` to compare the current ref map with the previous wrapper-tracked snapshot for that session and report `details.snapshotDiff` added/removed/changed refs. Use these flags when you need controls like checkout buttons, all comboboxes, above/below-fold context, or a quick before/after ref delta without reading a full spill file.
725
810
 
726
811
  ### Wait
727
812
 
@@ -729,7 +814,7 @@ For dense pages, the wrapper also accepts `snapshot -i --search <text>` and `sna
729
814
  | --- | --- |
730
815
  | `wait <selector>` | Wait for an element to appear. |
731
816
  | `wait <ms>` | Wait for a fixed number of milliseconds. The native Pi wrapper now forwards long waits and derives a subprocess watchdog from the explicit wait duration when the caller does not provide top-level `timeoutMs`. |
732
- | `wait --url <pattern>` | Wait for the URL to match a pattern. |
817
+ | `wait --url <pattern>` | Wait for the URL to match a pattern. On timeout the wrapper appends a `fresh-session-after-url-wait-timeout` next action (`sessionMode: "fresh"` + `open about:blank`, after the inspect action): if a preceding click or submit reported success but the page never navigated, upstream click dispatch may have silently missed, so replace about:blank with the target URL and replay the flow as one batch in a fresh session instead of retrying the wait. |
733
818
  | `wait --load <state>` | Wait for load state: `load`, `domcontentloaded`, or `networkidle`. |
734
819
  | `wait --fn <expression>` | Wait for a JavaScript expression to become truthy. |
735
820
  | `wait --text <text>` | Wait for text to appear on the page; failures may include `inspect-after-text-assertion-failure` with a session-scoped `snapshot -i` payload. |
@@ -792,6 +877,7 @@ Long-running or lifecycle commands should be explicitly paired with cleanup call
792
877
  | `chat` | Start interactive chat when stdin is a TTY. |
793
878
  | `dashboard [start]` | Start the dashboard server on the default port `4848`. |
794
879
  | `dashboard start --port <n>` | Start the dashboard on a specific port. |
880
+ | `dashboard start --allowed-origins <origins>` | Allow comma-separated exact HTTPS reverse-proxy origins. Environment: `AGENT_BROWSER_DASHBOARD_ALLOWED_ORIGINS`. |
795
881
  | `dashboard stop` | Stop the dashboard server. |
796
882
  | `device list` | List available iOS simulators. Use with `-p ios` when exercising iOS provider flows. |
797
883
  | `install` | Install browser binaries. |
@@ -804,10 +890,10 @@ Long-running or lifecycle commands should be explicitly paired with cleanup call
804
890
  | `plugin run <name> <type>` | Run a `command.run` or custom plugin request over the agent-browser plugin stdio protocol. |
805
891
  | `auth login <name> --credential-provider <plugin>` | Resolve credentials just-in-time from a configured credential plugin (e.g. a vault) instead of saved passwords; pair with `--item <ref>` and optional selector overrides. Credentials are not stored locally. |
806
892
  | `mcp --help` | Show MCP server help through the native tool. |
807
- | `mcp` | Start a local MCP stdio server for external MCP clients; bare native-tool calls are rejected before spawn. |
893
+ | `mcp` | Start a local MCP stdio server for external MCP clients; bare native-tool calls are rejected before spawn. External clients can opt into experimental page tools with `mcp --tools core,webmcp`. |
808
894
  | `profiles` | List available Chrome profiles. |
809
895
 
810
- When these commands are invoked through the native `agent_browser` tool, structured diagnostic/status outputs are rendered as compact summaries. As a checkout-auth isolation boundary, `session list` omits wrapper-managed `piab-*` live-session rows, `state list` omits wrapper-managed `piab-r2-*` rows and legacy `piab-r-*` rows, and explicit `piab-*` session targets are rejected unless this extension instance owns that exact namespace/session; foreign managed `--restore`, `--state`, `state show`, and `state load` references fail before spawn. Broad `state clear` / `state clean` and managed save/rename targets are also blocked; targeted caller-owned state names and paths remain available. Local inspection/setup calls (`auth save/list/show/delete/remove`, `dashboard start/stop`, `device list`, `doctor`, `install`, `upgrade`, `profiles`, `session id`, `session info`, `session list`, `plugin add/list/show/run`, `state list/show/rename`, and targeted `state clear <caller-owned-name>`) are sessionless unless you explicitly pass `--session`; bare `mcp` server calls are blocked except help. Context-dependent calls such as root `session`, untargeted `state clear`, `auth login`, `chat`, and `state save/load` keep normal session behavior. List-like outputs such as sessions, Chrome profiles, auth profiles, network requests, console messages, and page errors include counts and key fields; large outputs are previewed with a `Full output path:` spill file instead of dumping the entire payload into context. For `network requests`, the wrapper shows a failed-request summary split into actionable versus benign low-impact rows, then status, method, URL, resource/mime type, request id, and, when the installed upstream output includes body-like fields, bounded redacted payload, response, and failure/error snippets. Safe request IDs also produce `details.nextActions` for exact request details, actionable failed-request source lookup candidates, filtered request lists, or starting HAR capture before a repro. If the same session has active wrapper-observed network routes, failed/pending/CORS-looking matched request rows add `details.networkRouteDiagnostics` and executable route-mock next actions before the generic request actions. `data:image` artifact rows are omitted from compact request previews but remain in raw `details.data.requests`. `network request <requestId>` can expose upstream full-detail body fields such as response bodies using the same bounded model-facing preview; its request URL stays diagnostic-only and does not overwrite `details.sessionTabTarget` for later ref guards. Clipboard failures that mention `NotAllowedError` or permission denial are usually browser/OS capability limits, not proof that a read, paste, or page mutation happened; prefer page-native reads (`snapshot -i`, `get text`, `eval --stdin`) or direct typing (`keyboard inserttext` / `keyboard type`) when the workflow allows it, and retry true clipboard flows only from an allowed profile/session on a normal `http(s)` page. Header, cookie, auth, token, and other secret-like fields are not expanded in model-facing text or `details.data`; low-risk primitive storage values may remain visible, while command echoes still redact `--body`, `--headers`, `--password`, proxy credentials, auth-bearing URLs, `clipboard write` text, cookie/storage set values, and bearer/basic credential text in positional arguments. Use upstream HAR or full raw details only when complete data is required.
896
+ When these commands are invoked through the native `agent_browser` tool, structured diagnostic/status outputs are rendered as compact summaries. `session list` and `state list` keep every upstream row and restore identifier visible. Explicit sessions, state/restore paths, broad state lifecycle commands, config, local files, and launch environment pass through unchanged. Local inspection/setup calls remain sessionless unless you explicitly pass `--session`; browser-backed or context-dependent calls keep normal managed-session behavior when no explicit session is supplied. List-like outputs such as sessions, Chrome profiles, auth profiles, network requests, console messages, and page errors include counts and key fields; large outputs are previewed with a `Full output path:` spill file instead of dumping the entire payload into context. For `network requests`, the wrapper shows a failed-request summary split into actionable versus benign low-impact rows, then status, method, URL, resource/mime type, request id, and, when the installed upstream output includes body-like fields, bounded redacted payload, response, and failure/error snippets. Safe request IDs also produce `details.nextActions` for exact request details, actionable failed-request source lookup candidates, filtered request lists, or starting HAR capture before a repro. If the same session has active wrapper-observed network routes, failed/pending/CORS-looking matched request rows add `details.networkRouteDiagnostics` and executable route-mock next actions before the generic request actions. `data:image` artifact rows are omitted from compact request previews but remain in raw `details.data.requests`. `network request <requestId>` can expose upstream full-detail body fields such as response bodies using the same bounded model-facing preview; its request URL stays diagnostic-only and does not overwrite `details.sessionTabTarget` for later ref guards. Clipboard failures that mention `NotAllowedError` or permission denial are usually browser/OS capability limits, not proof that a read, paste, or page mutation happened; prefer page-native reads (`snapshot -i`, `get text`, `eval --stdin`) or direct typing (`keyboard inserttext` / `keyboard type`) when the workflow allows it, and retry true clipboard flows only from an allowed profile/session on a normal `http(s)` page. Header, cookie, auth, token, and other secret-like fields are not expanded in model-facing text or `details.data`; low-risk primitive storage values may remain visible, while command echoes still redact `--body`, `--headers`, `--password`, proxy credentials, auth-bearing URLs, `clipboard write` text, cookie/storage set values, and bearer/basic credential text in positional arguments. Use upstream HAR or full raw details only when complete data is required.
811
897
 
812
898
  ## Optional package config and companion web search
813
899
 
@@ -829,6 +915,7 @@ cat > ~/.pi/config/pi-agent-browser-native/config.json <<'JSON'
829
915
  "webSearch": {
830
916
  "enabled": true,
831
917
  "preferredProvider": "exa",
918
+ "defaultSearchType": "deep-lite",
832
919
  "exaApiKey": "$EXA_API_KEY",
833
920
  "braveApiKey": "$BRAVE_API_KEY"
834
921
  }
@@ -853,7 +940,21 @@ npm exec --yes --package pi-agent-browser-native@latest -- pi-agent-browser-conf
853
940
  npm exec --yes --package pi-agent-browser-native@latest -- pi-agent-browser-config browser executable set "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"
854
941
  ```
855
942
 
856
- The optional `agent_browser_web_search` tool is available when Exa or Brave credentials are visible from startup config or trusted session config and the runtime config has not set `webSearch.enabled` to `false`. It is a separate custom tool, not an `agent_browser` input mode, and does not launch a browser. Use it when current/live external web information would help; use `agent_browser` for browser interaction, screenshots, authenticated/profile pages, and DOM inspection after you have a target URL. Prefer it over driving public search-engine forms such as Google with browser `job`/`type` flows, which can redirect headless automation to anti-bot or CAPTCHA pages; do not attempt CAPTCHA bypass. Disable scope is explicit: `web-search disable --global` sets the normal user default, `web-search disable --project` disables it for one repo, and a `PI_AGENT_BROWSER_CONFIG` override containing `{ "version": 1, "webSearch": { "enabled": false } }` wins over both for a hard per-run disable. Loaded config may use plaintext, custom env aliases, interpolation literals, malformed-or-late-bound `$` values, and command-backed web-search keys; the resolved secret reaches the provider request while model-facing tool output and status text stay redacted. `web-search set-key`, `set-command`, and `clear` require `--provider`; `set-env` infers Exa/Brave from `EXA_API_KEY` or `BRAVE_API_KEY` unless you pass `--provider`. For Exa, the tool defaults to `searchType: "auto"` with `contents.highlights: true`; use `fast`, `instant`, `deep-lite`, `deep`, or `deep-reasoning` only when the task needs that latency/depth tradeoff.
943
+ The optional `agent_browser_web_search` tool is available when Exa or Brave credentials are visible from startup config or trusted session config and the runtime config has not set `webSearch.enabled` to `false`. It is a separate custom tool, not an `agent_browser` input mode, and does not launch a browser. Prefer it for current/live external web facts and URL discovery; use `agent_browser` for browser interaction, screenshots, authenticated/profile pages, and DOM inspection after you have a target URL. Prefer it over driving public search-engine forms such as Google with browser `job`/`type` flows, which can redirect headless automation to anti-bot or CAPTCHA pages; do not attempt CAPTCHA bypass. Disable scope is explicit: `web-search disable --global` sets the normal user default, `web-search disable --project` disables it for one repo, and a `PI_AGENT_BROWSER_CONFIG` override containing `{ "version": 1, "webSearch": { "enabled": false } }` wins over both for a hard per-run disable. Loaded config may use plaintext, custom env aliases, interpolation literals, malformed-or-late-bound `$` values, and command-backed web-search keys; the resolved secret reaches the provider request while model-facing tool output and status text stay redacted. `web-search set-key`, `set-command`, and `clear` require `--provider`; `set-env` infers Exa/Brave from `EXA_API_KEY` or `BRAVE_API_KEY` unless you pass `--provider`.
944
+
945
+ For Exa, effective search type precedence is per-call `searchType` → `webSearch.defaultSearchType` → `auto`, with regular `contents.highlights: true`. Typical latencies are `instant` ~250 ms, `fast` ~450 ms, `auto` ~1 second, `deep-lite` ~4 seconds, `deep` 4–15 seconds, and `deep-reasoning` 12–40 seconds. Prefer `deep-lite` for research before implementation, `deep` for hard multi-source work, and `deep-reasoning` only for exhaustive or still-thin research. Searches are serialized; do not launch several in parallel.
946
+
947
+ ```json
948
+ {
949
+ "query": "pi-agent-browser-native agent_browser_web_search searchType defaults",
950
+ "searchType": "deep-lite",
951
+ "count": 5
952
+ }
953
+ ```
954
+
955
+ Exa-only options include 1–20 `includeDomains` / `excludeDomains`, a six-value `category`, 1–10 deep-mode `additionalQueries`, and `highlightsDynamic`. The `company` and `people` categories cannot combine with `freshness` or `excludeDomains`; invalid combinations fail before the request. Explicit new Exa-only options also fail if Brave resolves as the provider, while the existing `searchType` field remains ignored by Brave. `highlightsDynamic: true` is a research preview and sends Exa's required beta header. Full page text and structured output schemas remain out of scope.
956
+
957
+ Every Exa request includes a fixed provider instruction to favor primary official sources, requested versions/dates, and distinct results. After normalization, both provider adapters remove later results only when their normalized URLs are exactly equal, retain the first row and provider order, and do not overfetch replacements or guess that distinct paths/query URLs are aliases. `details.duplicatesRemoved` reports removed rows, so returned results may be fewer than `count`. `pageDate` is Exa's estimated `publishedDate` or Brave's `page_age`; Brave may also supply `age`. Neither field proves crawl/retrieval age or a version match. When correctness or version matters, use the page/date clues, constrain one follow-up to the primary domain (`includeDomains` for Exa or `site:` in a Brave query), and read the primary page.
857
958
 
858
959
  Example config:
859
960
 
@@ -863,6 +964,7 @@ Example config:
863
964
  "webSearch": {
864
965
  "enabled": true,
865
966
  "preferredProvider": "exa",
967
+ "defaultSearchType": "deep-lite",
866
968
  "exaApiKey": "$EXA_API_KEY",
867
969
  "braveApiKey": "$BRAVE_API_KEY"
868
970
  },
@@ -882,15 +984,18 @@ Browser default config is conservative: it adds agent guidance for signed-in/acc
882
984
 
883
985
  ### Authentication and session flags
884
986
 
987
+ `agent-browser` 0.35.0 and newer require separate argv tokens for global flag values (for example, `--args <args>` and `--user-agent <ua>`). The explicit exception is `--restore=<key>`, which is supported when an optional restore key could otherwise be confused with a command word. The wrapper rejects other global `--flag=value` forms before normal command dispatch, including when they trail the command. Plain `--help`, `-h`, `--version`, and `-V` inspection preserves exact caller argv because upstream accepts those top-level inspection shapes. Global flags for `batch` belong before `batch` in top-level `args`; row-local equals forms are rejected without the help/version or `--restore=<key>` exceptions.
988
+
885
989
  - `--profile <name|path>`: reuse Chrome profile login state by directory name from `profiles`, or use a persistent custom profile/profile-directory path when upstream accepts it. Environment: `AGENT_BROWSER_PROFILE`.
886
990
  - `--session <name>`: use an isolated session. Environment: `AGENT_BROWSER_SESSION`.
887
- - `--restore [name]`: auto-save/restore cookies, local storage, and session storage; bare `--restore` uses `--session` as the key. Environment: `AGENT_BROWSER_RESTORE`. Wrapper-owned managed sessions set a Git-checkout-generation-stable restore key automatically unless disabled with `PI_AGENT_BROWSER_MANAGED_SESSION_RESTORE=0` or sticky-disabled after an incompatible launch; a successfully spawned suppressed identity reports `details.managedSessionRestoreDisabled`, meaning later plain follow-ups do not inject the wrapper key. Same-policy follow-ups may keep using that live daemon; any later call that requests incompatible policy first inspects the daemon and blocks if it retains a restore key or cannot be inspected. Any upstream config discovered while planning or browser mutation flag/env disables automatic managed restore without reading caller-selected config content. Subprocesses that receive the wrapper restore key and wrapper-owned closes pin a process-private empty `AGENT_BROWSER_CONFIG` (`0400` on POSIX) in the marked secure-temp lifecycle, so config created after planning cannot alter the browser that receives restored auth. Raw batch argv and batch stdin containing nested `connect`/`batch` also disable restore so an attached browser cannot receive wrapper-managed auth state. A user-private immutable ticket-claim lock serializes daemon policy inspection through the receiving spawn and bridges the pre-update v2 lock path; every lock winner re-inspects the live daemon, and abandoned v2 locks fail closed for manual repair. POSIX process identity probes use absolute `/bin/ps` then `/usr/bin/ps` paths. Before incompatible reuse the wrapper inspects the actual daemon and blocks if it retains any restore key, cannot be inspected, or reports restore-disabled policy without current-process provenance. Same-process `session_tree` changes keep that provenance, while reload/restart/resume intentionally do not restore it from transcript rows; close a still-live blocked daemon first, use a fresh wrapper session, or choose a distinct explicit session. Wrapper-owned subprocesses pin their canonical namespace, including the empty default namespace. Upstream restore files under `~/.agent-browser/` are plaintext unless a valid 64-character hex `AGENT_BROWSER_ENCRYPTION_KEY` is set; automatic restore requires a durable Git checkout generation plus an absolute home root, and on POSIX the wrapper canonicalizes and pins `HOME`, requires trusted non-writable owner ancestry plus stable device/inode/birth-time metadata for the checkout and Git-admin directories, enforces mode `0700` without silently repairing unsafe existing directories, and rejects symlinks/non-directories along the exact restore `sessions` path and `.tmp` write area, while Windows requires that key because POSIX mode checks cannot verify profile ACLs. Wrapper-owned close discards caller config/restore globals and preserves the live daemon's existing restore key rather than injecting one derived from a replacement checkout and records a returned old-generation snapshot against that observed wrapper key. A failed fresh command is followed by an exact-identity daemon probe; live or uninspectable starts remain owned for shutdown cleanup. After a wrapper-owned close succeeds, the wrapper persists its returned state path as an atomic record in a lockless convergent per-key ownership directory (`0700`, with `0600` records, on POSIX), retains the two newest proven snapshots for the exact restore key across Pi restarts, self-heals malformed regular records, removes additional proven snapshots older than 30 days, expires stale ownership-proven snapshots and empty manifests from other restore-key generations after 30 days only when a private lineage record proves the same canonical checkout path, and caps young close churn at 256 records per restore key without invoking namespace-wide `state clean`; unrecorded matching files and the current checkout key are untouched. Restore capabilities and key-bearing paths are redacted from output/transcripts; malformed oversized upstream output is discarded instead of persisted as a parse-failure spill. Checkout/storage/managed-session/state-access policy is revalidated after async setup immediately before spawn. Native Windows command-first adaptation moves only valid leading globals, rewrites valued `--restore <name>` as `--restore=<name>`, consumes only exact lowercase boolean literals, and leaves invalid or command-scoped leading input unchanged.
991
+ - `--restore [name]`: auto-save/restore cookies, local storage, and session storage; bare `--restore` uses `--session` as the key. Environment: `AGENT_BROWSER_RESTORE`. Wrapper-owned implicit sessions set a transcript- and checkout-scoped restore key automatically unless disabled with `PI_AGENT_BROWSER_MANAGED_SESSION_RESTORE=0` or suppressed by incompatible caller launch choices. Explicit restore/state/session/config choices pass through unchanged and remain visible in results. Automatic restore validates only its own checkout/storage identity and coordinates same-daemon reuse so wrapper restore pools cannot mix.
888
992
  - `--restore-save <policy>` (`auto`, `always`, or `never`): restore auto-save policy. Environment: `AGENT_BROWSER_RESTORE_SAVE`. Restore-enabled sessions also save periodically while open; `AGENT_BROWSER_AUTOSAVE_INTERVAL_MS` sets the minimum interval in milliseconds (`30000` by default, `0` disables periodic saves but not save-on-close).
889
993
  - `--restore-check-url <glob>`, `--restore-check-text <txt>`, `--restore-check-fn <js>`: validate restored state before auto-save. Environments: `AGENT_BROWSER_RESTORE_CHECK_URL`, `AGENT_BROWSER_RESTORE_CHECK_TEXT`, `AGENT_BROWSER_RESTORE_CHECK_FN`.
890
994
  - `--namespace <name>`: isolate daemon sockets and restore-state directories. Environment: `AGENT_BROWSER_NAMESPACE`. Upstream and the wrapper canonicalize namespace identity to a lowercase sanitized component (for example, `Team Name` becomes `team-name`).
891
995
  - `--session-name <name>`: legacy alias for restore persistence key. Environment: `AGENT_BROWSER_SESSION_NAME`.
892
996
  - `--state <path>`: load saved auth state from JSON. Environment: `AGENT_BROWSER_STATE`.
893
- - `--auto-connect`: connect to a running Chrome to reuse auth state. Environment: `AGENT_BROWSER_AUTO_CONNECT`. Optional booleans use separated tokens (`--auto-connect false`); upstream 0.33.2 does not recognize `--auto-connect=false`, so that token cannot disable an earlier bare `--auto-connect`.
997
+ - `--auto-connect`: connect to a running Chrome to reuse auth state. Environment: `AGENT_BROWSER_AUTO_CONNECT`. Optional booleans use separated tokens (`--auto-connect false`); the wrapper rejects `--auto-connect=false` before dispatch.
998
+ - `--pin-tab`: pin the session to its bound tab. Environment: `AGENT_BROWSER_PIN_TAB`. Sticky per session and not launch-scoped. Commands fail with `tab_gone` instead of falling back when that tab is closed. `--no-pin-tab` disables a previously enabled pin. Optional booleans use separated tokens (`--pin-tab false`).
894
999
  - `--headers <json>`: apply HTTP headers scoped to the opened URL's origin.
895
1000
  - `--init-script <path>`: register a script before first navigation; repeatable. Environment: `AGENT_BROWSER_INIT_SCRIPTS`.
896
1001
  - `--enable <feature>`: enable built-in init scripts such as `react-devtools`; repeatable or comma-separated. Environment: `AGENT_BROWSER_ENABLE`.
@@ -904,14 +1009,20 @@ Browser default config is conservative: it adds agent guidance for signed-in/acc
904
1009
  - `--proxy <server>`: proxy server URL. Environments: `AGENT_BROWSER_PROXY`, `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`.
905
1010
  - `--proxy-bypass <hosts>`: proxy bypass hosts. Environments: `AGENT_BROWSER_PROXY_BYPASS`, `NO_PROXY`.
906
1011
  - `--ignore-https-errors`: ignore HTTPS certificate errors. Environment: `AGENT_BROWSER_IGNORE_HTTPS_ERRORS`.
907
- - `--allow-file-access`: upstream capability, but enabled argv/`AGENT_BROWSER_ALLOW_FILE_ACCESS` forms and file-access-enabling `--args` / `AGENT_BROWSER_ARGS` Chrome switches are rejected by this native wrapper. Local-browser spawns add canonical `--args "" --allow-file-access false` defaults so project/user config cannot re-enable file access; an explicit validated safe CLI `--args` value remains usable. Attached-session follow-ups omit those launch-only defaults. Every spawn removes all caller occurrences before any canonical separated `--allow-file-access false` is added, so unsupported equals forms cannot preserve an earlier enabled flag and config cannot re-enable local filesystem access. Unknown top-level or batch tab/attachment/script/state-load transitions remain blocked for page inspection until `get url` or explicit safe navigation establishes the target. `tab list` and non-content `tab <id>` selection remain available while unknown, but selection stays unverified until `get url`; post-transition summaries (including after arbitrary `eval`) read the live URL before title and stop if the target is a local file page.
1012
+ - `--ca-cert <path>`: trust a PEM bundle or DER certificate in an isolated NSS store for locally launched Linux Chromium. Environment: `AGENT_BROWSER_CA_CERT`. Use `sessionMode: "fresh"`; the wrapper disables automatic managed restore for the CA-enabled session while passing the caller-selected certificate path upstream. Upstream requires `certutil` and rejects profiles, CDP/auto-connect, providers, Lightpanda, `--ignore-https-errors`, macOS, and Windows.
1013
+ - `--no-ca-cert`: clear retained CA trust. Environment: `AGENT_BROWSER_CLEAR_CA_CERT`. Use `sessionMode: "fresh"` for wrapper-managed sessions.
1014
+ - `--allow-file-access`: upstream capability passed through unchanged from argv or `AGENT_BROWSER_ALLOW_FILE_ACCESS`. Raw `--args` / `AGENT_BROWSER_ARGS`, local file navigation, local-page follow-ups, and caller-selected paths remain upstream-owned. The wrapper adds only its fixed compatibility user-agent argument on eligible new managed launches; it does not clear or replace caller launch settings. Ambiguous page-target transitions still require `get url` before later content calls so the agent cannot silently act on the wrong page.
908
1015
  - `--hide-scrollbars <bool>`: explicitly show or hide native scrollbars in headless Chromium screenshots.
909
- - `--headed`: ask upstream to show the browser window. Environment: `AGENT_BROWSER_HEADED`. Use it on the first launch, normally with `sessionMode: "fresh"` when changing an existing managed session; verify visibility with screenshot/tab evidence because the wrapper cannot yet prove the OS window is visible to the user.
1016
+ - `--headed`: ask upstream to show the browser window. Environment: `AGENT_BROWSER_HEADED`. Use it on the first launch, normally with `sessionMode: "fresh"` when changing an existing managed session. Successful first/fresh local wrapper-managed launches can expose `details.browserWindow.visibility: "unverified"` and a login handoff; attached browsers cannot, but still verify actual OS visibility with the user or screenshot/tab evidence.
910
1017
  - `--webgpu`: enable upstream's platform-specific WebGPU launch preset. Environment: `AGENT_BROWSER_WEBGPU`; config: `"webgpu": true`. Use it on a fresh local launch. It is incompatible while enabled with `--cdp`, `--auto-connect`, and provider launches. `AGENT_BROWSER_NO_XVFB=1` disables upstream's automatic Xvfb for displayless headed Linux sessions.
911
- - `--cdp <port>`: connect through Chrome DevTools Protocol. Use it, `--auto-connect`, or `connect <port|url>` once on a named/fresh session, verify with `get url`, then reuse that session without repeating the attach flag. After a successful attachment the wrapper omits local-launch-only `--args` / `--allow-file-access` defaults on follow-ups and cleanup so upstream keeps one CDP connection instead of requesting Chrome permission again. Content-bearing first use is blocked until URL verification; later page reads/interactions live-check the URL because the attached browser can drift externally. `close` clears attachment state.
1018
+ - `--no-webmcp`: disable experimental WebMCP support, which upstream 0.36.0 enables by default for locally managed Chrome. Environment: `AGENT_BROWSER_NO_WEBMCP`; config: `noWebmcp`. Use it on a fresh launch; `--no-webmcp false` explicitly enables the launch feature when config or environment disabled it.
1019
+ - `--cdp <port|url>`: connect through Chrome DevTools Protocol. Use it, `--auto-connect`, or `connect <port|url>` once on a named/fresh session, verify with `get url`, then reuse that session without repeating the attach flag. After a successful attachment the wrapper avoids re-emitting its own compatibility launch argument; caller launch/config/file-access settings remain unchanged. Content-bearing first use is blocked until URL verification; later page reads/interactions live-check the URL because the attached browser can drift externally. `close` clears attachment state.
912
1020
  - `--color-scheme <scheme>`: `dark`, `light`, or `no-preference`. Environment: `AGENT_BROWSER_COLOR_SCHEME`.
913
1021
  - `--download-path <path>`: default browser download directory. Environment: `AGENT_BROWSER_DOWNLOAD_PATH`.
914
1022
  - `--engine <name>`: browser engine, `chrome` by default or `lightpanda`. Environment: `AGENT_BROWSER_ENGINE`.
1023
+
1024
+ On Android/Termux, follow the README setup to install the packaged Linux-musl arm64 upstream binary, install Termux's `which`, and expose its launcher as `$PREFIX/bin/chromium`. Prefer that upstream system-browser discovery over ambient `AGENT_BROWSER_EXECUTABLE_PATH`: it survives isolated `HOME` values, works for ordinary calls and top-level `script`, and preserves the script security boundary that clears ambient launch controls and rejects inner `--executable-path` flags. Wrapper-generated Android managed identities use a compact 80-bit digest so ordinary namespaces and fresh rotations fit upstream's Unix socket path.
1025
+
915
1026
  - `--no-auto-dialog`: disable automatic dismissal of alert/beforeunload dialogs. Environment: `AGENT_BROWSER_NO_AUTO_DIALOG`.
916
1027
  - `--idle-timeout <ms>`: launch-scoped background browser lifecycle setting. The wrapper already sets one stable `AGENT_BROWSER_IDLE_TIMEOUT_MS` for top-level and helper subprocesses. A per-call value must equal that configured value; otherwise the tool rejects it before launch and tells you to restart Pi with `PI_AGENT_BROWSER_IMPLICIT_SESSION_IDLE_TIMEOUT_MS=<ms>`. This prevents upstream from restarting the browser and discarding tabs/refs when later helper calls use a different launch environment.
917
1028
 
@@ -924,7 +1035,7 @@ Browser default config is conservative: it adds agent guidance for signed-in/acc
924
1035
  - `--screenshot-format <fmt>`: `png` or `jpeg`. Environment: `AGENT_BROWSER_SCREENSHOT_FORMAT`.
925
1036
  - `--content-boundaries`: wrap page output in boundary markers. Environment: `AGENT_BROWSER_CONTENT_BOUNDARIES`.
926
1037
  - `--max-output <chars>`: truncate page output to N characters. Environment: `AGENT_BROWSER_MAX_OUTPUT`.
927
- - `--allowed-domains <list>`: restrict browser and `read` traffic to exact or `*.` wildcard domain patterns. Environment: `AGENT_BROWSER_ALLOWED_DOMAINS`. Use a fresh local Chrome context; upstream 0.32.0 rejects containment-unsafe launch modes/state and disables Chromium `RTCPeerConnection` while active. The wrapper also remembers argv-supplied allowed domains for the managed session and fails a successful-looking browser command with `failureCategory: "policy-blocked"` when the final observed `http(s)` URL host is outside that allowlist, including click/navigation escapes after the initial page load.
1038
+ - `--allowed-domains <list>`: restrict browser and `read` traffic to exact or `*.` wildcard domain patterns. Environment: `AGENT_BROWSER_ALLOWED_DOMAINS`. Use a fresh local Chrome context; upstream 0.32.0 owns containment and incompatible-mode rejection and disables Chromium `RTCPeerConnection` while active. The wrapper passes the setting and result through unchanged.
928
1039
  - `--action-policy <path>`: action policy JSON file. Environment: `AGENT_BROWSER_ACTION_POLICY`.
929
1040
  - `--confirm-actions <list>`: action categories requiring confirmation. Environment: `AGENT_BROWSER_CONFIRM_ACTIONS`.
930
1041
  - `--confirm-interactive`: interactive confirmations; auto-denies when stdin is not a TTY. Environment: `AGENT_BROWSER_CONFIRM_INTERACTIVE`.
@@ -947,15 +1058,14 @@ Standalone `agent-browser` looks for `agent-browser.json` in these locations, fr
947
1058
  3. Environment variables, including `AGENT_BROWSER_CONFIG`.
948
1059
  4. CLI flags.
949
1060
 
950
- Use separated `--config <path>` to load a specific config file in standalone upstream; upstream 0.33.2 does not recognize `--config=<path>` as the global config selector. The native wrapper rejects discovered, environment-selected, or explicit upstream config for browser-backed calls without reading it, then pins a process-private empty config for every accepted browser-backed spawn so a file created after planning cannot change the browser. Sessionless local/setup commands keep upstream config behavior. This policy is separate from the Pi-scoped package config under `.pi/config/pi-agent-browser-native/`; pass safe browser settings through native `args`/environment or that package's advisory browser guidance. Boolean flags accept optional `true` or `false` values, such as `--headed false` or `--webgpu false`, to override config. Browser extensions from user and project configs are merged rather than replaced.
1061
+ Use separated `--config <path>` to load a specific upstream config; upstream 0.33.2 does not recognize `--config=<path>` as the global selector. Browser-backed and sessionless native calls preserve `--config`, `AGENT_BROWSER_CONFIG`, passive project/user config, and other upstream environment exactly as supplied. The Pi-scoped package config under `.pi/config/pi-agent-browser-native/` remains separate. Boolean flags accept optional `true` or `false` values, such as `--headed false`, `--webgpu false`, or `--no-webmcp false`, to override config. Browser extensions from user and project configs are merged rather than replaced.
951
1062
 
952
- Other useful environment variables include `AGENT_BROWSER_DEFAULT_TIMEOUT`, `AGENT_BROWSER_AUTOSAVE_INTERVAL_MS`, `AGENT_BROWSER_STREAM_PORT`, `AGENT_BROWSER_STREAM_QUALITY`, `AGENT_BROWSER_STREAM_MAX_WIDTH`, `AGENT_BROWSER_STREAM_MAX_HEIGHT`, `AGENT_BROWSER_IDLE_TIMEOUT_MS`, `AGENT_BROWSER_ENCRYPTION_KEY`, `AGENT_BROWSER_STATE_EXPIRE_DAYS`, `AGENT_BROWSER_IOS_DEVICE`, `AGENT_BROWSER_IOS_UDID`, `AI_GATEWAY_URL`, `AI_GATEWAY_API_KEY`, provider credential names, and AWS credential names when using AgentCore. The upstream child receives the parent environment plus wrapper overrides such as the managed socket directory, clamped default operation timeout, canonical owned-session namespace (including empty default), and Git-checkout-generation-stable `AGENT_BROWSER_RESTORE` for wrapper-owned managed sessions (`buildAgentBrowserProcessEnv` in `extensions/agent-browser/lib/process.ts`, ownership carried by the wrapper's typed process options and call-scoped managed-session context). Model-facing output still redacts recognized secret values.
1063
+ Other useful environment variables include `AGENT_BROWSER_DEFAULT_TIMEOUT`, `AGENT_BROWSER_AUTOSAVE_INTERVAL_MS`, `AGENT_BROWSER_STREAM_PORT`, `AGENT_BROWSER_STREAM_QUALITY`, `AGENT_BROWSER_STREAM_MAX_WIDTH`, `AGENT_BROWSER_STREAM_MAX_HEIGHT`, `AGENT_BROWSER_IDLE_TIMEOUT_MS`, `AGENT_BROWSER_ENCRYPTION_KEY`, `AGENT_BROWSER_STATE_EXPIRE_DAYS`, `AGENT_BROWSER_IOS_DEVICE`, `AGENT_BROWSER_IOS_UDID`, `AI_GATEWAY_URL`, `AI_GATEWAY_API_KEY`, provider credential names, and AWS credential names when using AgentCore. The upstream child receives the parent environment plus wrapper overrides such as the managed socket directory, clamped default operation timeout, canonical owned-session namespace (including empty default), and Pi-transcript- plus Git-checkout-generation-scoped `AGENT_BROWSER_RESTORE` for wrapper-owned managed sessions (`buildAgentBrowserProcessEnv` in `extensions/agent-browser/lib/process.ts`, ownership carried by the wrapper's typed process options and call-scoped managed-session context). Model-facing output still redacts recognized secret values.
953
1064
 
954
1065
  ## Wrapper-specific behavior worth knowing
955
1066
 
956
1067
  - The extension may keep following one implicit managed session across later tool calls.
957
- - Protected `.agent-browser` paths are rejected equally in CLI operands (including dash-prefixed values), raw Chrome args, and path-bearing environment mirrors, including `AGENT_BROWSER_STATE`, `AGENT_BROWSER_PROFILE`, `AGENT_BROWSER_CONFIG`, `AGENT_BROWSER_EXECUTABLE_PATH`, `AGENT_BROWSER_EXTENSIONS`, `AGENT_BROWSER_INIT_SCRIPTS`, `AGENT_BROWSER_ACTION_POLICY`, download/screenshot directories, `AGENT_BROWSER_SKILLS_DIR`, and the wrapper socket directory.
958
- - If launch-scoped flags like `--profile`, `--executable-path`, `--webgpu`, `--restore`, `--restore-save`, restore check flags, `--namespace`, `--session-name`, `--cdp`, `--state`, `--auto-connect`, `--init-script`, `--enable`, `--provider` / `-p`, or provider device flags like `--device` would be ignored because that implicit session is already active, retry with `sessionMode: "fresh"`.
1068
+ - If launch-scoped flags like `--profile`, `--args`, `--user-agent`, `--executable-path`, `--ca-cert`, `--no-ca-cert`, `--webgpu`, `--no-webmcp`, `--restore`, `--restore-save`, restore check flags, `--namespace`, `--session-name`, `--cdp`, `--state`, `--auto-connect`, `--init-script`, `--enable`, `--provider` / `-p`, or provider device flags like `--device` would replace or be ignored by an already-active managed session, retry with `sessionMode: "fresh"`. When the call explicitly names the current managed session, the structured recovery payload removes that `--session` so the fresh rotation can succeed.
959
1069
  - If a `sessionMode: "fresh"` call fails (including upstream failure, timeout, missing binary, or **`qa`** reclassification after a nominally successful batch), read `details.managedSessionOutcome` before assuming where the next default call will go: `preserved` means the prior managed session remains current, while `abandoned` means no managed session became current. When the failure reason is not the fresh launch itself—for example `failureCategory: "qa-failure"`—`status`/`summary` may still describe the managed-session transition while `succeeded` on this object matches the final tool outcome.
960
1070
  <!-- agent-browser-playbook:start wrapper-tab-recovery -->
961
1071
  <!-- Generated from extensions/agent-browser/lib/playbook.ts. Run `npm run docs -- playbook write` to update. -->
@@ -963,9 +1073,10 @@ Other useful environment variables include `AGENT_BROWSER_DEFAULT_TIMEOUT`, `AGE
963
1073
  - After the wrapper observes tab-drift risk for a session (for example open correction, overlapping stale opens, or resumed session state), later active-tab commands best-effort pin that tab inside the same upstream invocation. Routine same-session commands are not preflighted with tab list just because a target tab or ref snapshot is known.
964
1074
  - For sessions with observed tab-drift risk, after a successful command on a known target tab, agent_browser also best-effort restores that intended tab if a restored/background tab steals focus after the command completes. Routine same-session commands skip this post-command tab-list probe.
965
1075
  - If a known session target unexpectedly reports about:blank, agent_browser best-effort re-selects the prior intended target when it still exists; if recovery fails, it records the observed about:blank target and reports exact recovery guidance instead of treating the prior page as active.
1076
+ - If upstream reports tab_gone, the pinned bound tab is gone; use details.nextActions (tab list / tab new) instead of assuming another tab is yours.
966
1077
  <!-- agent-browser-playbook:end wrapper-tab-recovery -->
967
- - Wrapper-spawned commands clamp `AGENT_BROWSER_DEFAULT_TIMEOUT` to the upstream documented 25-second default and use a 35-second child-process watchdog (`PI_AGENT_BROWSER_PROCESS_TIMEOUT_MS` overrides the default 35s budget; top-level `timeoutMs` overrides it per browser CLI call). Explicit `wait <ms>` or `wait --timeout <ms>` calls can exceed that default; when top-level `timeoutMs` is omitted, the wrapper derives a subprocess watchdog from the requested wait duration plus a small grace window. Dialog commands are additionally bounded to 5 seconds (`PI_AGENT_BROWSER_DIALOG_PROCESS_TIMEOUT_MS`), and click/tap/find refs or tokens plus `eval --stdin` snippets that look like alert/confirm/prompt/dialog triggers are bounded to 8 seconds (`PI_AGENT_BROWSER_DIALOG_TRIGGER_PROCESS_TIMEOUT_MS`). When any watchdog fires, `details.timeoutPartialProgress` may include a planned step list with per-step status (including `generatedFrom` labels for wrapper-inserted rows such as `open.loadState`) and a `retry-timeout-step` next action only when the first incomplete step is read-only or idempotent, or `inspect-current-page-after-timeout` when the session is still inspectable but the incomplete step may be mutating and should not be blindly retried. It also includes current page URL from best-effort session `get url`, followed by `get title` only for a verified non-file URL (or a planned URL inferred from the step list when the session cannot answer), an `openedButPostOpenTimedOut` classification only when a live page URL was recovered before a later step hung, and declared artifact paths such as `screenshot`, `pdf`, `download`, or `wait --download` outputs with existence/state checks; the same evidence is appended under `Timeout partial progress` in visible text with URL/path redaction.
968
- - Oversized snapshots and oversized generic outputs may be compacted in tool content, with the full raw output written to a spill file path shown directly in the tool result. Recent artifact metadata is bounded by `PI_AGENT_BROWSER_SESSION_ARTIFACT_MANIFEST_MAX_ENTRIES` (default 100); persisted spill files are separately bounded by `PI_AGENT_BROWSER_SESSION_ARTIFACT_MAX_BYTES` (default 32 MiB).
1078
+ - Wrapper-spawned commands clamp `AGENT_BROWSER_DEFAULT_TIMEOUT` to the upstream documented 25-second default and use a 35-second child-process watchdog (`PI_AGENT_BROWSER_PROCESS_TIMEOUT_MS` overrides the default 35s budget; top-level `timeoutMs` overrides it per browser CLI call). Explicit `wait <ms>`, `wait --timeout <ms>`, and WebMCP `invoke` / `result --timeout <ms>` calls can exceed that default; when top-level `timeoutMs` is omitted, the wrapper derives a subprocess watchdog from the requested command duration plus a small grace window. Batch budgeting reads the same effective source as upstream: raw command strings when present, otherwise stdin rows. Dialog commands are additionally bounded to 5 seconds (`PI_AGENT_BROWSER_DIALOG_PROCESS_TIMEOUT_MS`), and click/tap/find refs or tokens plus `eval --stdin` snippets that look like alert/confirm/prompt/dialog triggers are bounded to 8 seconds (`PI_AGENT_BROWSER_DIALOG_TRIGGER_PROCESS_TIMEOUT_MS`). When any watchdog fires, `details.timeoutPartialProgress` may include a planned step list with per-step status (including `generatedFrom` labels for wrapper-inserted rows such as `open.loadState`) and a `retry-timeout-step` next action only when the first incomplete step is read-only or idempotent, or `inspect-current-page-after-timeout` when the target is already verified but the incomplete step may be mutating and should not be blindly retried. If the target is unknown, standalone snapshots are removed and visible failure text plus `details.nextActions` show `verify-page-target-after-timeout`, including its session-scoped `batch --bail` args and short stdin for fail-fast `get url` then `snapshot -i`; dialog status/accept/dismiss actions remain allowed for blocking-dialog recovery. It also includes current page URL from best-effort session `get url`, followed by `get title` only after a URL is recovered (or a planned URL inferred from the step list when the session cannot answer), an `openedButPostOpenTimedOut` classification only when a live page URL was recovered before a later step hung, and declared artifact paths such as `screenshot`, `pdf`, `download`, or `wait --download` outputs with existence/state checks; the same evidence is appended under `Timeout partial progress` in visible text with URL/path redaction.
1079
+ - Oversized snapshots and oversized generic outputs may be compacted in tool content, with the full redacted output written to a spill file path shown directly in the tool result. Recent artifact metadata is bounded by `PI_AGENT_BROWSER_SESSION_ARTIFACT_MANIFEST_MAX_ENTRIES` (default 100); persisted spill files are separately bounded by `PI_AGENT_BROWSER_SESSION_ARTIFACT_MAX_BYTES` (default 32 MiB).
969
1080
  - The wrapper keeps `--help` and `--version` stateless so they do not consume the implicit managed-session slot.
970
1081
 
971
1082
  ## Generated capability baseline
@@ -973,14 +1084,14 @@ Other useful environment variables include `AGENT_BROWSER_DEFAULT_TIMEOUT`, `AGE
973
1084
  <!-- agent-browser-capability-baseline:start capability-token-baseline -->
974
1085
  <!-- Generated from scripts/agent-browser-capability-baseline.mjs. Run `npm run docs -- command-reference write` to update. Do not edit manually. -->
975
1086
  <details>
976
- <summary>Generated verifier capability baseline for agent-browser 0.33.2</summary>
1087
+ <summary>Generated verifier capability baseline for agent-browser 0.36.0</summary>
977
1088
 
978
1089
  This generated block is review data for maintainers. The human-authored reference sections above remain the readable command guide.
979
1090
 
980
1091
  #### Source evidence
981
1092
  - repository: `vercel-labs/agent-browser`
982
- - upstream HEAD: `93cdda5709e8861c0c26b0b955d8d746e9fda0d7`
983
- - upstream package version: `0.33.2`
1093
+ - upstream HEAD: `eb05921bad874cd2a1b4fa5d1149f1ed26576cae`
1094
+ - upstream package version: `0.36.0`
984
1095
  - inspected: `agent-browser --version`
985
1096
  - inspected: `agent-browser --help`
986
1097
  - inspected: `selected agent-browser <command> --help output`
@@ -990,25 +1101,41 @@ This generated block is review data for maintainers. The human-authored referenc
990
1101
  - inspected: `agent-browser skills list`
991
1102
  - inspected: `agent-browser skills get core --full`
992
1103
  - inspected: `agent-browser skills get derive-client --full`
1104
+ - inspected: `agent-browser skills get webmcp-gen --full`
993
1105
  - inspected: `README.md`
994
1106
  - inspected: `CHANGELOG.md`
995
1107
  - inspected: `agent-browser.schema.json`
1108
+ - inspected: `bin/agent-browser.js`
1109
+ - inspected: `cli/src/ca_bundle.rs`
996
1110
  - inspected: `cli/src/commands.rs`
1111
+ - inspected: `cli/src/mcp.rs`
997
1112
  - inspected: `cli/src/flags.rs`
998
1113
  - inspected: `cli/src/read.rs`
999
1114
  - inspected: `cli/src/doctor/webgpu.rs`
1000
1115
  - inspected: `cli/src/native/actions.rs`
1001
1116
  - inspected: `cli/src/native/a11y/mod.rs`
1002
1117
  - inspected: `cli/src/native/browser.rs`
1118
+ - inspected: `cli/src/native/tab_binding.rs`
1003
1119
  - inspected: `cli/src/native/daemon.rs`
1120
+ - inspected: `cli/src/native/element.rs`
1121
+ - inspected: `cli/src/native/stream/cdp_loop.rs`
1122
+ - inspected: `cli/src/native/stream/dashboard.rs`
1123
+ - inspected: `cli/src/native/test_fixtures/webmcp_frame_probe.html`
1124
+ - inspected: `cli/src/native/test_fixtures/webmcp_probe.html`
1125
+ - inspected: `cli/src/native/webmcp.rs`
1004
1126
  - inspected: `cli/src/output.rs`
1005
1127
  - inspected: `docs/src/app/webgpu/page.mdx`
1128
+ - inspected: `docs/src/app/webmcp/page.mdx`
1006
1129
  - inspected: `docs/src/app/network/page.mdx`
1130
+ - inspected: `docs/src/app/proxy/page.mdx`
1007
1131
  - inspected: `docs/src/app/selectors/page.mdx`
1008
1132
  - inspected: `docs/src/app/skills/page.mdx`
1009
1133
  - inspected: `docs/src/app/commands/page.mdx`
1010
1134
  - inspected: `skill-data/derive-client/SKILL.md`
1011
1135
  - inspected: `skill-data/core/SKILL.md`
1136
+ - inspected: `skill-data/protected-vercel-deployments/SKILL.md`
1137
+ - inspected: `skill-data/webmcp-gen/SKILL.md`
1138
+ - inspected: `test/launcher.test.mjs`
1012
1139
  - inspected: `packages/@agent-browser/eve/README.md`
1013
1140
  - inspected: `packages/@agent-browser/eve/package.json`
1014
1141
  - inspected: `packages/@agent-browser/eve/test/extension.test.mjs`
@@ -1023,6 +1150,8 @@ This generated block is review data for maintainers. The human-authored referenc
1023
1150
  - skills list: `agent-browser skills list`
1024
1151
  - core skill full: `agent-browser skills get core --full`
1025
1152
  - vercel sandbox skill full: `agent-browser skills get vercel-sandbox --full`
1153
+ - protected Vercel deployments skill full: `agent-browser skills get protected-vercel-deployments --full`
1154
+ - WebMCP generation skill full: `agent-browser skills get webmcp-gen --full`
1026
1155
  - open help: `agent-browser open --help`
1027
1156
  - read help: `agent-browser read --help`
1028
1157
  - click help: `agent-browser click --help`
@@ -1076,12 +1205,12 @@ This generated block is review data for maintainers. The human-authored referenc
1076
1205
  - plugin help: `agent-browser plugin --help`
1077
1206
 
1078
1207
  #### Inventory sections
1079
- - Built-in skills: 16 human-doc token(s), 18 upstream token(s)
1208
+ - Built-in skills: 19 human-doc token(s), 24 upstream token(s)
1080
1209
  - Core page, element, navigation, and extraction commands: 82 human-doc token(s), 84 upstream token(s)
1081
- - Sessions, state, tabs, frames, dialogs, and windows: 24 human-doc token(s), 20 upstream token(s)
1082
- - Network, storage, artifacts, diagnostics, and performance: 49 human-doc token(s), 60 upstream token(s)
1083
- - Batch, auth, confirmations, setup, dashboard, devices, and AI commands: 33 human-doc token(s), 37 upstream token(s)
1084
- - Global flags, config, providers, policy, and environment: 142 human-doc token(s), 110 upstream token(s)
1210
+ - Sessions, state, tabs, frames, dialogs, and windows: 28 human-doc token(s), 25 upstream token(s)
1211
+ - Network, storage, artifacts, diagnostics, and performance: 57 human-doc token(s), 67 upstream token(s)
1212
+ - Batch, auth, confirmations, setup, dashboard, devices, and AI commands: 36 human-doc token(s), 40 upstream token(s)
1213
+ - Global flags, config, providers, policy, and environment: 152 human-doc token(s), 119 upstream token(s)
1085
1214
 
1086
1215
  #### Human-authored doc tokens required
1087
1216
  ##### Built-in skills
@@ -1095,8 +1224,11 @@ This generated block is review data for maintainers. The human-authored referenc
1095
1224
  - `skills get slack`
1096
1225
  - `skills get dogfood`
1097
1226
  - `skills get vercel-sandbox`
1227
+ - `skills get protected-vercel-deployments`
1098
1228
  - `skills get agentcore`
1099
1229
  - `skills get derive-client`
1230
+ - `skills get webmcp-gen`
1231
+ - `webmcp.init.js`
1100
1232
  - `@agent-browser/sandbox`
1101
1233
  - `installSystemDependencies: false`
1102
1234
  - `skills path [name]`
@@ -1206,6 +1338,10 @@ This generated block is review data for maintainers. The human-authored referenc
1206
1338
  - `tab new --label <name> [url]`
1207
1339
  - `tab close [target]`
1208
1340
  - `tab <t<N>|label>`
1341
+ - `tab_gone`
1342
+ - `data.targetId`
1343
+ - `data.lastUrl`
1344
+ - `CDP target ids`
1209
1345
  - `frame <selector|main>`
1210
1346
  - `dialog accept [text]`
1211
1347
  - `dialog dismiss`
@@ -1227,6 +1363,14 @@ This generated block is review data for maintainers. The human-authored referenc
1227
1363
  - `cookies set <name> <value> --url <url> --domain <domain> --path <path> --httpOnly --secure --sameSite <Strict|Lax|None> --expires <timestamp>`
1228
1364
  - `cookies set --curl <file>`
1229
1365
  - `storage <local|session>`
1366
+ - `webmcp list`
1367
+ - `webmcp invoke <tool>`
1368
+ - `webmcp invoke <tool> --params <json|@file>`
1369
+ - `webmcp invoke <tool> --frame <frame-id>`
1370
+ - `webmcp invoke <tool> --detach`
1371
+ - `webmcp invoke <tool> --timeout <ms>`
1372
+ - `webmcp result <id>`
1373
+ - `webmcp cancel <id>`
1230
1374
  - `diff snapshot`
1231
1375
  - `diff snapshot --baseline <file> --selector <sel> --compact --depth <n>`
1232
1376
  - `diff screenshot --baseline`
@@ -1279,6 +1423,8 @@ This generated block is review data for maintainers. The human-authored referenc
1279
1423
  - `chat <message>`
1280
1424
  - `dashboard [start]`
1281
1425
  - `dashboard start --port <n>`
1426
+ - `dashboard start --allowed-origins <origins>`
1427
+ - `AGENT_BROWSER_DASHBOARD_ALLOWED_ORIGINS`
1282
1428
  - `dashboard stop`
1283
1429
  - `device list`
1284
1430
  - `install`
@@ -1291,6 +1437,7 @@ This generated block is review data for maintainers. The human-authored referenc
1291
1437
  - `doctor --webgpu --headed`
1292
1438
  - `doctor --json`
1293
1439
  - `mcp`
1440
+ - `mcp --tools core,webmcp`
1294
1441
  - `plugin add <ref>`
1295
1442
  - `plugin [list]`
1296
1443
  - `plugin show <name>`
@@ -1321,6 +1468,9 @@ This generated block is review data for maintainers. The human-authored referenc
1321
1468
  - `AGENT_BROWSER_STATE`
1322
1469
  - `--auto-connect`
1323
1470
  - `AGENT_BROWSER_AUTO_CONNECT`
1471
+ - `--pin-tab`
1472
+ - `--no-pin-tab`
1473
+ - `AGENT_BROWSER_PIN_TAB`
1324
1474
  - `--headers <json>`
1325
1475
  - `--init-script <path>`
1326
1476
  - `AGENT_BROWSER_INIT_SCRIPTS`
@@ -1344,6 +1494,10 @@ This generated block is review data for maintainers. The human-authored referenc
1344
1494
  - `NO_PROXY`
1345
1495
  - `--ignore-https-errors`
1346
1496
  - `AGENT_BROWSER_IGNORE_HTTPS_ERRORS`
1497
+ - `--ca-cert <path>`
1498
+ - `--no-ca-cert`
1499
+ - `AGENT_BROWSER_CA_CERT`
1500
+ - `AGENT_BROWSER_CLEAR_CA_CERT`
1347
1501
  - `--allow-file-access`
1348
1502
  - `AGENT_BROWSER_ALLOW_FILE_ACCESS`
1349
1503
  - `--hide-scrollbars <bool>`
@@ -1351,9 +1505,12 @@ This generated block is review data for maintainers. The human-authored referenc
1351
1505
  - `AGENT_BROWSER_HEADED`
1352
1506
  - `--webgpu`
1353
1507
  - `AGENT_BROWSER_WEBGPU`
1508
+ - `--no-webmcp`
1509
+ - `AGENT_BROWSER_NO_WEBMCP`
1510
+ - `noWebmcp`
1354
1511
  - `AGENT_BROWSER_NO_XVFB`
1355
1512
  - `"webgpu": true`
1356
- - `--cdp <port>`
1513
+ - `--cdp <port|url>`
1357
1514
  - `--color-scheme <scheme>`
1358
1515
  - `AGENT_BROWSER_COLOR_SCHEME`
1359
1516
  - `--download-path <path>`
@@ -1453,10 +1610,16 @@ This generated block is review data for maintainers. The human-authored referenc
1453
1610
  - skills list: `slack`
1454
1611
  - skills list: `dogfood`
1455
1612
  - skills list: `vercel-sandbox`
1613
+ - skills list: `protected-vercel-deployments`
1456
1614
  - skills list: `agentcore`
1457
1615
  - skills list: `derive-client`
1616
+ - skills list: `webmcp-gen`
1617
+ - WebMCP generation skill full: `webmcp.init.js`
1618
+ - WebMCP generation skill full: `agent-browser webmcp invoke <tool> --params @fixture.json`
1458
1619
  - vercel sandbox skill full: `@agent-browser/sandbox`
1459
1620
  - vercel sandbox skill full: `installSystemDependencies: false`
1621
+ - protected Vercel deployments skill full: `x-vercel-trusted-oidc-idp-token`
1622
+ - protected Vercel deployments skill full: `vc project token`
1460
1623
  - core skill full: `agent-browser frame @e3`
1461
1624
  - core skill full: `agent-browser dialog accept`
1462
1625
  - core skill full: `agent-browser --session "$SESSION" --restore open https://app.example.com`
@@ -1565,8 +1728,13 @@ This generated block is review data for maintainers. The human-authored referenc
1565
1728
  - state help: `clean --older-than <days>`
1566
1729
  - tab help: `new [url]`
1567
1730
  - tab help: `new --label <name> [url]`
1568
- - tab help: `close [t<N>|label]`
1731
+ - tab help: `close [t<N>|label|target]`
1569
1732
  - tab help: `Stable tab ids`
1733
+ - tab help: `tab_gone`
1734
+ - tab help: `data.targetId`
1735
+ - tab help: `data.lastUrl`
1736
+ - core skill full: `--pin-tab`
1737
+ - core skill full: `tab_gone`
1570
1738
  - frame help: `frame <selector|main>`
1571
1739
  - dialog help: `dialog <accept|dismiss|status> [text]`
1572
1740
  - window help: `window <operation>`
@@ -1582,6 +1750,13 @@ This generated block is review data for maintainers. The human-authored referenc
1582
1750
  - root help: `cookies [get|set|clear]`
1583
1751
  - root help: `cookies set --curl <file>`
1584
1752
  - root help: `storage <local|session>`
1753
+ - root help: `webmcp list`
1754
+ - root help: `webmcp invoke <tool>`
1755
+ - root help: `--params <json|@file>`
1756
+ - root help: `--frame <frame-id>`
1757
+ - root help: `--detach`
1758
+ - root help: `webmcp result <id>`
1759
+ - root help: `webmcp cancel <id>`
1585
1760
  - root help: `diff snapshot`
1586
1761
  - root help: `diff screenshot --baseline`
1587
1762
  - root help: `trace start`
@@ -1641,6 +1816,9 @@ This generated block is review data for maintainers. The human-authored referenc
1641
1816
  - root help: `deny <id>`
1642
1817
  - root help: `chat <message>`
1643
1818
  - root help: `dashboard start --port <n>`
1819
+ - root help: `dashboard start --allowed-origins <origins>`
1820
+ - dashboard help: `--allowed-origins <origins>`
1821
+ - dashboard help: `AGENT_BROWSER_DASHBOARD_ALLOWED_ORIGINS`
1644
1822
  - device help: `device list`
1645
1823
  - root help: `install --with-deps`
1646
1824
  - install help: `fails if deps fail`
@@ -1695,6 +1873,9 @@ This generated block is review data for maintainers. The human-authored referenc
1695
1873
  - root help: `AGENT_BROWSER_STATE`
1696
1874
  - root help: `--auto-connect`
1697
1875
  - root help: `AGENT_BROWSER_AUTO_CONNECT`
1876
+ - root help: `--pin-tab`
1877
+ - root help: `--no-pin-tab`
1878
+ - root help: `AGENT_BROWSER_PIN_TAB`
1698
1879
  - root help: `--headers <json>`
1699
1880
  - root help: `--init-script <path>`
1700
1881
  - root help: `AGENT_BROWSER_INIT_SCRIPTS`
@@ -1717,6 +1898,10 @@ This generated block is review data for maintainers. The human-authored referenc
1717
1898
  - root help: `NO_PROXY`
1718
1899
  - root help: `--ignore-https-errors`
1719
1900
  - root help: `AGENT_BROWSER_IGNORE_HTTPS_ERRORS`
1901
+ - root help: `--ca-cert <path>`
1902
+ - root help: `--no-ca-cert`
1903
+ - root help: `AGENT_BROWSER_CA_CERT`
1904
+ - root help: `AGENT_BROWSER_CLEAR_CA_CERT`
1720
1905
  - root help: `--allow-file-access`
1721
1906
  - root help: `AGENT_BROWSER_ALLOW_FILE_ACCESS`
1722
1907
  - root help: `--hide-scrollbars <bool>`
@@ -1724,7 +1909,9 @@ This generated block is review data for maintainers. The human-authored referenc
1724
1909
  - root help: `AGENT_BROWSER_HEADED`
1725
1910
  - root help: `--webgpu`
1726
1911
  - root help: `AGENT_BROWSER_WEBGPU`
1727
- - root help: `--cdp <port>`
1912
+ - root help: `--no-webmcp`
1913
+ - root help: `AGENT_BROWSER_NO_WEBMCP`
1914
+ - root help: `--cdp <port|url>`
1728
1915
  - root help: `--color-scheme <scheme>`
1729
1916
  - root help: `AGENT_BROWSER_COLOR_SCHEME`
1730
1917
  - root help: `--download-path <path>`
@@ -1792,7 +1979,7 @@ This generated block is review data for maintainers. The human-authored referenc
1792
1979
  Whenever the upstream `agent-browser` binary version changes in this project:
1793
1980
 
1794
1981
  1. run `agent-browser --version`, `agent-browser --help`, `agent-browser tab --help`, `agent-browser snapshot --help`, and `agent-browser wait --help`
1795
- 2. update the canonical metadata in `scripts/agent-browser-capability-baseline.mjs`
1982
+ 2. update the canonical version in `scripts/agent-browser-target.mjs` and the help/doc inventory in `scripts/agent-browser-capability-baseline.mjs`
1796
1983
  3. update the human-authored command reference sections if command semantics or recommended workflows changed
1797
1984
  4. run `npm run docs -- command-reference write` to regenerate capability baseline blocks; do not manually edit generated blocks
1798
1985
  5. run `npm run verify -- command-reference`