pi-agent-browser-native 0.6.9 → 0.6.11

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 (54) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +62 -19
  3. package/dist/extensions/agent-browser/index.js +424 -451
  4. package/dist/extensions/agent-browser/lib/argv-descriptor.js +6 -7
  5. package/dist/extensions/agent-browser/lib/argv-grammar.js +7 -1
  6. package/dist/extensions/agent-browser/lib/batch-lifecycle.js +4 -8
  7. package/dist/extensions/agent-browser/lib/command-policy.js +41 -2
  8. package/dist/extensions/agent-browser/lib/command-taxonomy.js +15 -2
  9. package/dist/extensions/agent-browser/lib/input-modes/params.js +1 -1
  10. package/dist/extensions/agent-browser/lib/input-modes/script.js +3 -2
  11. package/dist/extensions/agent-browser/lib/managed-session-restore.js +42 -12
  12. package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +3 -5
  13. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +6 -14
  14. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +14 -25
  15. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +12 -6
  16. package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +1 -0
  17. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +3 -2
  18. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +38 -31
  19. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +60 -20
  20. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery.js +161 -0
  21. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +5 -5
  22. package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +2 -4
  23. package/dist/extensions/agent-browser/lib/orchestration/native-session-defaults.js +68 -0
  24. package/dist/extensions/agent-browser/lib/orchestration/output-file.js +41 -6
  25. package/dist/extensions/agent-browser/lib/page-target-validation.js +9 -5
  26. package/dist/extensions/agent-browser/lib/playbook.js +13 -12
  27. package/dist/extensions/agent-browser/lib/process-environment.js +26 -8
  28. package/dist/extensions/agent-browser/lib/process.js +8 -5
  29. package/dist/extensions/agent-browser/lib/read-confirmation.js +59 -0
  30. package/dist/extensions/agent-browser/lib/recording-reservations.js +11 -1
  31. package/dist/extensions/agent-browser/lib/results/action-recommendations.js +8 -0
  32. package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +6 -5
  33. package/dist/extensions/agent-browser/lib/results/categories.js +4 -2
  34. package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +76 -57
  35. package/dist/extensions/agent-browser/lib/results/presentation/batch.js +19 -8
  36. package/dist/extensions/agent-browser/lib/results/presentation/common.js +5 -25
  37. package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +40 -38
  38. package/dist/extensions/agent-browser/lib/results/presentation/errors.js +1 -0
  39. package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +3 -3
  40. package/dist/extensions/agent-browser/lib/results/presentation.js +38 -9
  41. package/dist/extensions/agent-browser/lib/results/recording.js +50 -0
  42. package/dist/extensions/agent-browser/lib/runtime.js +72 -20
  43. package/dist/extensions/agent-browser/lib/session-page-state.js +24 -8
  44. package/dist/extensions/agent-browser/lib/temp.js +4 -0
  45. package/dist/scripts/agent-browser-target.mjs +1 -1
  46. package/docs/ARCHITECTURE.md +29 -12
  47. package/docs/COMMAND_REFERENCE.md +67 -31
  48. package/docs/RELEASE.md +6 -4
  49. package/docs/SUPPORT_MATRIX.md +24 -16
  50. package/docs/TOOL_CONTRACT.md +82 -28
  51. package/package.json +1 -1
  52. package/scripts/agent-browser-capability-baseline.mjs +10 -3
  53. package/scripts/agent-browser-target.mjs +1 -1
  54. package/scripts/prepare.mjs +2 -4
@@ -16,19 +16,30 @@ This project intentionally blocks normal `agent-browser` bash usage in most agen
16
16
 
17
17
  After updating `pi-agent-browser-native`, fully quit and restart Pi before using the updated tools. `/reload` can retain previously loaded compiled JavaScript even after `dist/` is rebuilt, so it is not a reliable way to pick up package updates.
18
18
 
19
+ SDK hosts can supply an awaited [`beforeExecute` callback](TOOL_CONTRACT.md#host-execution-hook) to save host state before ordinary or script-inner browser dispatch. This is a factory option, not a tool argument; normal installations do not need it.
20
+
19
21
  ## Upstream baseline
20
22
 
21
23
  <!-- agent-browser-capability-baseline:start upstream-baseline -->
22
24
  <!-- Generated from scripts/agent-browser-capability-baseline.mjs. Run `npm run docs -- command-reference write` to update. Do not edit manually. -->
23
- 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.
25
+ This reference is baselined to the locally installed `agent-browser 0.37.0` command/help surface, audited against vercel-labs/agent-browser@471ab3852b47b98847f1d9c855c272bb62d0d50b. 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.
24
26
 
25
27
  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.
26
28
 
27
29
  <!-- agent-browser-capability-baseline:end upstream-baseline -->
28
30
 
31
+ ### Upstream 0.37.0 rebaseline
32
+
33
+ The recommended release keeps the stable 0.35.0 floor and no upper version cap.
34
+
35
+ - `record start` / `record restart` accept command-local `--fps <n>` before, between or after path/URL operands (1–60, default 30). WebM uses VP8/libvpx; MP4 uses H.264/libx264. Other extensions are handed to ffmpeg; extensionless paths are rejected. Native startup validates the path, rate and ffmpeg availability.
36
+ - Recording uses the current active page without replacing its DOM/JavaScript state unless a URL is supplied. The wrapper still conservatively requires a fresh snapshot after dispatched starts and URL-bearing restarts to protect older supported natives; this is not evidence that a page changed. FPS alone neither chooses another tab nor makes a restart invalidate refs.
37
+ - Successful navigation may advertise page-provided WebMCP tools. The wrapper shows the native positive hint and retains `data.webmcp`; absent, unavailable or empty results add no hint.
38
+ - Native `tab new` and `click --new-tab` apply session user agent, headers, HTTP credentials, init scripts, routes and emulation before the first document loads. The wrapper adds no tab-setup engine.
39
+
29
40
  ### Upstream 0.36.0 rebaseline
30
41
 
31
- The recommended 0.36.0 release adds experimental page-provided WebMCP tools while preserving the stable 0.35.0 runtime floor.
42
+ The 0.36.0 release adds experimental page-provided WebMCP tools while preserving the stable 0.35.0 runtime floor.
32
43
 
33
44
  - `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.
34
45
  - 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.
@@ -204,10 +215,11 @@ Tool parameters (use exactly one of `script`, `args`, `semanticAction`, `job`, `
204
215
  - `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.
205
216
  - `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`.
206
217
  - `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.
207
- - `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`.
218
+ - `outputPath`: optional wrapper-owned local file sink for successful results and recording receipts, including failed, pending, timed-out or recovered stops. Recording exports preserve an envelope with original attempt status and native receipt/verification (`details.outputFile.source: "recording-receipt"`); unrelated failed extractions remain unwritten. 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`.
208
219
  - `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.
209
220
  - `sessionMode`:
210
- - `"auto"` reuses the extension-managed session when possible.
221
+ - Native configured `session` / `AGENT_BROWSER_SESSION` defaults select a caller-owned shared browser for ordinary calls, just like explicit `--session`, without requiring repeated flags. Such a selection wins over both modes and is not closed on Pi quit. See [shared browser defaults](../README.md#shared-browser-defaults).
222
+ - `"auto"` reuses the extension-managed session when no native session is selected.
211
223
  - `"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.
212
224
  - 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.
213
225
 
@@ -223,7 +235,7 @@ Use `script` when a loop, an optional page branch, or multi-page aggregation wou
223
235
 
224
236
  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.
225
237
 
226
- 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.
238
+ 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, pass `--config`, 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 and uses an empty temporary native config to bypass HOME/project profile defaults before the wrapper reapplies its 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.
227
239
 
228
240
  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.
229
241
 
@@ -352,9 +364,9 @@ Successful `snapshot -i` results can also surface `Possible overlay blockers` wh
352
364
  { "args": ["eval", "--stdin"], "stdin": "document.title" }
353
365
  ```
354
366
 
355
- 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.
367
+ 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 does not allocate or replace a managed browser for an explicit URL read or all-read batch. It skips page verification, tab/ref changes and timeout page probes; malformed read arguments go to native validation without falling back to a DOM preflight. Caller config and flags remain native-owned. `Read execution` reports source, CLI start and native launch evidence without treating the HTTP read as proof of shared-browser liveness. Use `session info` for that. Native no-browser-effects behavior requires the companion upstream fix; older supported binaries do not guarantee it merely because the wrapper skips helpers. 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.
356
368
 
357
- When you already know several visible refs or selectors, extract them in one `batch` call instead of many serial getter calls:
369
+ When you already know several visible refs or selectors, extract them in one `batch` call instead of many serial getter calls. When a prior snapshot and session are available and the same-page freshness checks apply, ref-consuming calls add one extra `snapshot -i` preflight per top-level call or batch. Batching shares that probe across rows; it does not remove it:
358
370
 
359
371
  ```json
360
372
  { "args": ["batch"], "stdin": "[[\"get\",\"text\",\"@e64\"],[\"get\",\"text\",\"@e65\"],[\"get\",\"text\",\"@e66\"]]" }
@@ -539,11 +551,11 @@ Prefer `download <selector> <path>` when the target element itself is the downlo
539
551
 
540
552
  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.
541
553
 
542
- Wrapper result rendering is metadata-first for saved files. Image MIME types come from a bounded header read for PNG, JPEG, GIF and WebP, never from a filename suffix; missing, unreadable, unknown or truncated headers omit `mediaType`. This identifies a format, not full image validity. Inline screenshots use the same byte check and existing size limit, so a PNG saved as `.webm` still attaches as `image/png`; other artifact kinds are not auto-inlined. 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:
554
+ Wrapper result rendering is metadata-first for saved files. Image MIME types come from a bounded header read for PNG, JPEG, GIF and WebP, never from a filename suffix; missing, unreadable, unknown or truncated headers omit `mediaType`. This identifies a format, not full image validity. Inline screenshots use the same byte check and existing size limit, so a PNG saved as `.webm` still attaches as `image/png`; other artifact kinds are not auto-inlined. 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`. Outer CLI artifact parsing removes upstream global flags, so direct forms such as `record --json start <path>` and `pdf --quiet <path>` retain their native destinations. Native batch rows do not run that cleanup: `pdf --quick ignored.pdf` writes to the literal path `--quick`, and `download #link --quiet ignored.bin` writes to `--quiet`. Preflight, directory preparation, presentation, and timeout evidence use those same operands, not the ignored trailing tokens. 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 `wait --download --timeout 30000 capture.csv`), still participates in active-recording reservation preflight; the path is the next retained operand after the first timeout pair is removed; unsupported `--download=<path>` fails with split-argument guidance:
543
555
  - 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
544
- - 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
545
- - `record start <path>` and `record restart <path>` report `successCategory: "artifact-pending"` and that output will be written on `record stop`; dispatched `record start` and URL-bearing `record restart` attempts append one `Page state:` warning on success or failure, advising a fresh snapshot because in-page DOM and JavaScript state may not carry over; explicit `--json` puts that warning in `warnings`. Only reached batch rows qualify, not preflight failures, missing binaries, help calls or unconfirmed planned rows — 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.
546
- - `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
556
+ - downloads, PDFs, `wait --download` files, `state save` state files, diff screenshot output images, traces, CPU profiles, completed video recordings from `record stop`, and path-bearing HAR captures return concise saved-path summaries plus structured `details.artifacts` metadata without inlining large files
557
+ - `record start <path>` and `record restart <path>` report `successCategory: "artifact-pending"` and that output will be written on `record stop`; dispatched `record start` and URL-bearing `record restart` attempts append one `Page state:` warning on success or failure, describing conservative ref invalidation rather than an observed page change; explicit `--json` puts that warning in `warnings`. Only reached batch rows qualify, not preflight failures, missing binaries, help calls or unconfirmed planned rows — 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`, to protect older supported natives that can swap 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 restart without a URL, including FPS-only options, 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` returns a native `previousRecording`, that receipt's outcome and capture window control the previous artifact's verification; a legacy file without a terminal native receipt remains unverified, not 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 `No recording in progress` stop failure checks the matching native receipt once and preserves checked file metadata instead of assuming the path is missing; a later successful batch recording row opens its new pending path normally. Recovery offers an exact status query, and a stop only when the matching take is still current and pending. The target remains unverified until recording stops. Native 0.37 checks `ffmpeg` before starting; older supported natives may defer failure. If a successful start/restart reports pending output without `ffmpeg`, the wrapper appends `Recording dependency warning: ffmpeg not found on PATH` and `details.recordingDependencyWarning`; stop, check the result, then install the dependency before starting a new recording.
558
+ - `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 retires an unfinalized recording as `close-abandoned`, uses `missing` only after a filesystem check proves absence (otherwise unverified), 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
547
559
 
548
560
  `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.
549
561
 
@@ -555,6 +567,19 @@ For annotated screenshots in `batch`, put `--annotate` in top-level args instead
555
567
  { "args": ["--annotate", "batch"], "stdin": "[[\"screenshot\",\"/tmp/page.png\"]]" }
556
568
  ```
557
569
 
570
+ #### Recording quality and receipts
571
+
572
+ ```json
573
+ { "args": ["record", "start", "captures/demo.webm", "--fps", "30"] }
574
+ { "args": ["record", "stop"], "outputPath": "captures/demo-receipt.json" }
575
+ ```
576
+
577
+ Inspect `details.artifacts[].recording`: native capture start/end and first/last frame timestamps, wall duration, captured-frame rate, received frames, encoded/written/held/dropped/skipped counts, and separate output duration/FPS. Received frames are not pixel-unique. Repeated/static or late/final-only frames cannot establish smoothness. Missing metrics stay unknown; nominal FPS and `frames / fps` are not wall-clock capture evidence.
578
+
579
+ A stop timeout or `No recording in progress` result triggers one two-second native `session info` query, not another stop. `details.recordingRecovery` keeps the original failed attempt and requires matching session/namespace, recording ID/path (or an effective planned start window), terminal native encoder success and a verified file before recovering success. Same-path older receipts cannot verify a newer take. A timed-out batch may yield a verified recording while other steps remain unproven; unrelated failed-step repair actions remain available. Failed or unverified receipts still export safely to a distinct `outputPath`, with error/attempt provenance and parseable JSON. Follow the returned status/stop actions, not blind mutation retries or longer timeouts.
580
+
581
+ Detailed receipt/live-browser fields and browser-independent native read/confirm handling require companion upstream support not yet present in the current recommended release. Older supported versions remain usable with unknown metrics. Native receipt lookup lasts only while that daemon retains its memory; transcript metadata is not post-exit native recovery. See [the full receipt contract](TOOL_CONTRACT.md#recording-receipts-and-recovery).
582
+
558
583
  #### Artifact retention and dogfood-heavy QA runs
559
584
 
560
585
  The wrapper keeps a bounded, metadata-only `details.artifactManifest` of recent artifacts so long sessions do not grow unbounded. The default recent window is 100 entries and can be raised for screenshot/video-heavy QA sessions with `PI_AGENT_BROWSER_SESSION_ARTIFACT_MANIFEST_MAX_ENTRIES=<count>`.
@@ -563,7 +588,7 @@ This manifest cap controls what appears in `details.artifactManifest` and in sum
563
588
 
564
589
  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.
565
590
 
566
- 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.
591
+ 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 for longer retention, or set `PI_AGENT_BROWSER_SESSION_ARTIFACT_MAX_BYTES=0` to disable automatic eviction of persistent spill files. Zero leaves existing files in place as new spills are written; it does not recover files already evicted or change temporary subprocess spill cleanup.
567
592
 
568
593
  ### Switch from an already-active implicit session to a fresh profiled or alternate-browser launch
569
594
 
@@ -608,7 +633,9 @@ If the result says `Pending confirmation id: c_8f3a1234`, choose one follow-up:
608
633
  { "args": ["deny", "c_8f3a1234"] }
609
634
  ```
610
635
 
611
- 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.
636
+ For a policy-required explicit URL read, use the returned actions: they name the actual native namespace/session, including `default`, and this routing survives resume/branch replay. The wrapper skips page helpers on matching confirm/deny only when the native read response also advertises `capabilities.readRequiresConfirmation: true`, which includes strict native ID matching. Legacy read prompts retain correct routing but normal page checks; DOM or page-content-shaped prompts never gain the exemption. Explicit caller identities and script isolation still win.
637
+
638
+ Confirmation context may be redacted when it contains credentials, tokens, cookies, or auth-bearing URLs. Replacements are marked `[REDACTED]` (URL-encoded in parsed URLs); ordinary technical phrases such as `bearer token` and `bearer authentication` stay intact outside credential fields and headers. URL scrubbing covers `code`, SAMLRequest, SAMLResponse, RelayState, `authorization_session_id`, and auth-context `state` / `nonce` while retaining ordinary non-auth query values and the spelling of URLs needing no redaction. Visible text, structured details, persisted spills, and `outputPath` exports use the same redaction; exact internal page-target URLs remain available to browser state logic. Use the id exactly as printed.
612
639
 
613
640
  ### Use stateful browser-context commands safely
614
641
 
@@ -726,7 +753,7 @@ Comboboxes vary by app. For native `<select>` controls, prefer raw `select <sele
726
753
  | `state rename <old-name> <new-name>` | Rename a saved state file. |
727
754
  | `state clear [session-name] [--all]` | Clear saved states for one name or all names; `state clear -a` is the upstream short alias for clearing all names. |
728
755
  | `session id --scope worktree --prefix <name>` | Generate a stable session id for agent/worktree-scoped browser state. |
729
- | `session info --json` | Inspect daemon, launch, and restore status for a session. |
756
+ | `session info --json` | One read-only preflight: daemon activity/PID versus native browser liveness, Chrome PID, exact profile, tabs and launched/attached ownership, plus separate Pi cleanup ownership. Missing native fields remain unknown; no browser launch or tab changes. |
730
757
  | `state clean --older-than <days>` | Delete expired saved-state files. |
731
758
  | `frame <selector|main>` | Switch iframe context by selector/ref/name/URL, or return to the main frame. |
732
759
  | `dialog accept [text]` | Accept an alert, confirm, or prompt dialog, optionally supplying prompt text. |
@@ -767,7 +794,7 @@ Privacy note: `cookies get` can expose real profile cookies. Do not run it again
767
794
 
768
795
  ### WebMCP page tools
769
796
 
770
- 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.
797
+ 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. On 0.37, successful navigation with native `webmcp.available: true` and a positive tool count shows a `webmcp list` hint; the raw object stays in `details.data`. No hint is added for absent, unavailable or empty metadata.
771
798
 
772
799
  | Command | Purpose |
773
800
  | --- | --- |
@@ -840,9 +867,9 @@ Current upstream still does not parse `wait <selector> --state hidden` / `wait <
840
867
  | `diff url <u1> <u2>` | Navigate to both pages and compare them, leaving the second destination active. The wrapper observes the final URL, including redirects to `about:blank`, and invalidates old refs without recovering the old tab; direct and reached batch rows use the same rule. If the URL cannot be observed, run `get url` before taking a fresh snapshot. Use `diff url <u1> <u2> --screenshot --wait-until <strategy> --selector <sel> --compact --depth <n>` when you need screenshot comparison, navigation wait control, or scoped/compact snapshot comparison. |
841
868
  | `trace start`, `trace stop [path]` | Record a Chrome DevTools trace. |
842
869
  | `profiler start|stop [path]` | Record a Chrome DevTools profile. |
843
- | `record start <path> [url]` | Start WebM video recording; output is written on `record stop`. Requires `ffmpeg` on `PATH` for the final encode. |
844
- | `record stop` | Stop and save video. If this fails with `ffmpeg not found`, install `ffmpeg` / `ffmpeg-full` and rerun the recording. |
845
- | `record restart <path> [url]` | Stop any current recording and start a new WebM recording. |
870
+ | `record start <path> [url]` | Record the active page; an optional URL navigates first. Use `.webm` or `.mp4` and optional `--fps <n>` (1–60, default 30); native validates startup and requires `ffmpeg` on `PATH`. Verify output after `record stop`. |
871
+ | `record stop` | Finalize video and inspect its native receipt plus wrapper file verification. A failed or recovered stop retains original attempt evidence; use a distinct top-level `outputPath` to save its receipt. |
872
+ | `record restart <path> [url]` | Stop any current recording and start a new video. Supports the same formats and `--fps` option; without a URL it keeps the page and refs. |
846
873
  | `console [--clear]` | View or clear console logs. |
847
874
  | `errors [--clear]` | View or clear page errors. |
848
875
  | `highlight <sel>` | Highlight an element. |
@@ -863,7 +890,7 @@ Current upstream still does not parse `wait <selector> --state hidden` / `wait <
863
890
 
864
891
  Recording destinations are reserved within one Pi process, not across processes. Use unique paths for concurrent Pi processes: different explicit sessions can overwrite one file even when both `record stop` results are verified. Upstream’s same-session `record start` guard does not reserve the filename across other sessions.
865
892
 
866
- When these diagnostic commands are invoked through the native `agent_browser` tool, structured console, page-error, React, Web Vitals, and SPA outputs render as compact summaries when possible, with large outputs previewed and spilled instead of dumped into context. Large outputs are previewed with a `Full output path:` spill file instead of dumping the entire payload into context. Artifact-producing commands such as `network har stop`, `diff screenshot`, `trace stop`, `profiler stop`, and `record stop` report `details.artifacts[]` plus `details.artifactVerification`; `record start` / `record restart` are reported as pending until `record stop` completes. For video workflows, keep `ffmpeg` on `PATH` first; on macOS with Homebrew, `brew install ffmpeg` or `brew install ffmpeg-full` is sufficient. Successful `record start` / `record restart` results warn early with `details.recordingDependencyWarning` when the wrapper cannot find `ffmpeg`, so fix PATH before `record stop` instead of discovering the missing encoder after the capture. The README install section keeps the concise external-dependency list for maximal extension use.
893
+ When these diagnostic commands are invoked through the native `agent_browser` tool, structured console, page-error, React, Web Vitals, and SPA outputs render as compact summaries when possible, with large outputs previewed and spilled instead of dumped into context. Large outputs are previewed with a `Full output path:` spill file instead of dumping the entire payload into context. Artifact-producing commands such as `network har stop`, `diff screenshot`, `trace stop`, `profiler stop`, and `record stop` report `details.artifacts[]` plus `details.artifactVerification`; `record start` / `record restart` are reported as pending until `record stop` completes. For video workflows, keep `ffmpeg` on `PATH` first; on macOS with Homebrew, `brew install ffmpeg` or `brew install ffmpeg-full` is sufficient. Native 0.37 checks `ffmpeg` before capture and native `doctor` checks its encoders. Older supported natives may report pending output first; `details.recordingDependencyWarning` marks that output unverified, not recoverable merely by installing ffmpeg before stop. The README install section keeps the concise external-dependency list for maximal extension use.
867
894
 
868
895
  Long-running or lifecycle commands should be explicitly paired with cleanup calls: `stream enable` → `stream disable`, `dashboard start` → `dashboard stop`, `trace start` → `trace stop`, `profiler start` → `profiler stop`, and `record start` → `record stop`. The wrapper keeps each subprocess bounded by its normal timeout; it does not keep an interactive `chat` REPL open, so prefer `chat <message>` with `--model` or `AI_GATEWAY_MODEL` for single-shot AI use.
869
896
 
@@ -997,7 +1024,7 @@ Browser default config is conservative: it adds agent guidance for signed-in/acc
997
1024
  `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.
998
1025
 
999
1026
  - `--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`.
1000
- - `--session <name>`: use an isolated session. Environment: `AGENT_BROWSER_SESSION`.
1027
+ - `--session <name>`: use an isolated session. Environment: `AGENT_BROWSER_SESSION`. Native session names may begin with a hyphen; they remain values, not extra flags, including when selected through config or environment.
1001
1028
  - `--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.
1002
1029
  - `--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).
1003
1030
  - `--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`.
@@ -1034,7 +1061,7 @@ Browser default config is conservative: it adds agent guidance for signed-in/acc
1034
1061
  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.
1035
1062
 
1036
1063
  - `--no-auto-dialog`: disable automatic dismissal of alert/beforeunload dialogs. Environment: `AGENT_BROWSER_NO_AUTO_DIALOG`.
1037
- - `--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.
1064
+ - `--idle-timeout <ms>`: native background browser lifecycle setting (also accepts `10s`, `3m`, `1h`). Caller-owned sessions retain native idle policy; an explicit flag is carried to every helper in that call. Keep it consistent between calls to avoid a native daemon restart. Only wrapper-owned sessions receive the implicit timeout and numeric mismatch check against `PI_AGENT_BROWSER_IMPLICIT_SESSION_IDLE_TIMEOUT_MS`.
1038
1065
 
1039
1066
  ### Output, provider, policy, and AI flags
1040
1067
 
@@ -1068,6 +1095,8 @@ Standalone `agent-browser` looks for `agent-browser.json` in these locations, fr
1068
1095
  3. Environment variables, including `AGENT_BROWSER_CONFIG`.
1069
1096
  4. CLI flags.
1070
1097
 
1098
+ Native `session` and `namespace` defaults are honored by ordinary tool calls before implicit-session generation; `sessionName` is only a legacy restore key. Per-call flags override environment, which overrides project/user JSON. `--config` or `AGENT_BROWSER_CONFIG` selects one file instead of merging the discovered files; per-call config also reaches helper subprocesses. Caller-owned native `AGENT_BROWSER_SOCKET_DIR` is honored unless the wrapper-specific socket override is set. Script alone bypasses these defaults with an empty temporary config.
1099
+
1071
1100
  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.
1072
1101
 
1073
1102
  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.
@@ -1080,14 +1109,14 @@ Other useful environment variables include `AGENT_BROWSER_DEFAULT_TIMEOUT`, `AGE
1080
1109
  <!-- agent-browser-playbook:start wrapper-tab-recovery -->
1081
1110
  <!-- Generated from extensions/agent-browser/lib/playbook.ts. Run `npm run docs -- playbook write` to update. -->
1082
1111
  - After open/goto/navigate calls with --profile, --restore, --session-name, or --state, agent_browser best-effort re-selects the tab whose URL matches the returned page when restored tabs steal focus during launch or reconnect.
1083
- - After confirmed shutdown of an automatically restored managed session, the wrapper retains its complete recorded URL, including the fragment, until the first current-page operation (including get url and reload). Non-page calls such as tab list or read <url> may start a daemon without fulfilling that reopen. The wrapper uses native open once, verifies the observed tab, and discards old refs/frame scope; it does not restore unsaved forms, JavaScript memory, or history. Explicit navigation, caller-owned/attached sessions, and restore-disabled sessions are not auto-reopened.
1112
+ - After confirmed shutdown of an automatically restored managed session, the wrapper retains its complete recorded URL, including the fragment, until the first current-page operation (including get url and reload). Non-page calls such as tab list may start a daemon without fulfilling that reopen; explicit URL reads leave the managed browser and pending reopen untouched. The wrapper uses native open once, verifies the observed tab, and discards old refs/frame scope; it does not restore unsaved forms, JavaScript memory, or history. Explicit navigation, caller-owned/attached sessions, and restore-disabled sessions are not auto-reopened.
1084
1113
  - For a still-live browser after tab drift or resume, the wrapper verifies/selects the intended tab before ref/semantic helpers and page commands; failed selection stops the call without navigating. Local commands, read <url>, URL a11y/vitals, diff url, window new, and explicit tab/navigation/connection/state recovery do not require the prior tab. Batch checks follow effective rows past non-page prefixes and stop at explicit context changes, preserving caller argv/stdin and continue-on-error behavior. Same-tab reselection is avoided because it clears refs. Use exact batch --bail for fail-fast, not --bail=<value>. Routine same-session calls skip tab-list preflights.
1085
1114
  - 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.
1086
1115
  - 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.
1087
1116
  - 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.
1088
1117
  <!-- agent-browser-playbook:end wrapper-tab-recovery -->
1089
- - 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.
1090
- - 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).
1118
+ - 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 and timeout recovery read 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`). A `session info` timeout returns only an exact-session `retry-session-info` status action, without page probes, liveness claims, or changes to existing page/ref state. When a browser-operation 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 with a one-row native batch (`args: ["batch"]` plus `stdin`) 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.
1119
+ - 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 have a separate `PI_AGENT_BROWSER_SESSION_ARTIFACT_MAX_BYTES` budget (default 32 MiB; `0` disables automatic eviction).
1091
1120
  - The wrapper keeps `--help` and `--version` stateless so they do not consume the implicit managed-session slot.
1092
1121
 
1093
1122
  ## Generated capability baseline
@@ -1095,14 +1124,14 @@ Other useful environment variables include `AGENT_BROWSER_DEFAULT_TIMEOUT`, `AGE
1095
1124
  <!-- agent-browser-capability-baseline:start capability-token-baseline -->
1096
1125
  <!-- Generated from scripts/agent-browser-capability-baseline.mjs. Run `npm run docs -- command-reference write` to update. Do not edit manually. -->
1097
1126
  <details>
1098
- <summary>Generated verifier capability baseline for agent-browser 0.36.0</summary>
1127
+ <summary>Generated verifier capability baseline for agent-browser 0.37.0</summary>
1099
1128
 
1100
1129
  This generated block is review data for maintainers. The human-authored reference sections above remain the readable command guide.
1101
1130
 
1102
1131
  #### Source evidence
1103
1132
  - repository: `vercel-labs/agent-browser`
1104
- - upstream HEAD: `eb05921bad874cd2a1b4fa5d1149f1ed26576cae`
1105
- - upstream package version: `0.36.0`
1133
+ - upstream HEAD: `471ab3852b47b98847f1d9c855c272bb62d0d50b`
1134
+ - upstream package version: `0.37.0`
1106
1135
  - inspected: `agent-browser --version`
1107
1136
  - inspected: `agent-browser --help`
1108
1137
  - inspected: `selected agent-browser <command> --help output`
@@ -1122,6 +1151,7 @@ This generated block is review data for maintainers. The human-authored referenc
1122
1151
  - inspected: `cli/src/mcp.rs`
1123
1152
  - inspected: `cli/src/flags.rs`
1124
1153
  - inspected: `cli/src/read.rs`
1154
+ - inspected: `cli/src/doctor/ffmpeg.rs`
1125
1155
  - inspected: `cli/src/doctor/webgpu.rs`
1126
1156
  - inspected: `cli/src/native/actions.rs`
1127
1157
  - inspected: `cli/src/native/a11y/mod.rs`
@@ -1129,6 +1159,7 @@ This generated block is review data for maintainers. The human-authored referenc
1129
1159
  - inspected: `cli/src/native/tab_binding.rs`
1130
1160
  - inspected: `cli/src/native/daemon.rs`
1131
1161
  - inspected: `cli/src/native/element.rs`
1162
+ - inspected: `cli/src/native/recording.rs`
1132
1163
  - inspected: `cli/src/native/stream/cdp_loop.rs`
1133
1164
  - inspected: `cli/src/native/stream/dashboard.rs`
1134
1165
  - inspected: `cli/src/native/test_fixtures/webmcp_frame_probe.html`
@@ -1144,6 +1175,7 @@ This generated block is review data for maintainers. The human-authored referenc
1144
1175
  - inspected: `docs/src/app/commands/page.mdx`
1145
1176
  - inspected: `skill-data/derive-client/SKILL.md`
1146
1177
  - inspected: `skill-data/core/SKILL.md`
1178
+ - inspected: `skill-data/core/references/video-recording.md`
1147
1179
  - inspected: `skill-data/protected-vercel-deployments/SKILL.md`
1148
1180
  - inspected: `skill-data/webmcp-gen/SKILL.md`
1149
1181
  - inspected: `test/launcher.test.mjs`
@@ -1217,9 +1249,9 @@ This generated block is review data for maintainers. The human-authored referenc
1217
1249
 
1218
1250
  #### Inventory sections
1219
1251
  - Built-in skills: 19 human-doc token(s), 24 upstream token(s)
1220
- - Core page, element, navigation, and extraction commands: 82 human-doc token(s), 84 upstream token(s)
1221
- - Sessions, state, tabs, frames, dialogs, and windows: 28 human-doc token(s), 25 upstream token(s)
1222
- - Network, storage, artifacts, diagnostics, and performance: 57 human-doc token(s), 67 upstream token(s)
1252
+ - Core page, element, navigation, and extraction commands: 82 human-doc token(s), 85 upstream token(s)
1253
+ - Sessions, state, tabs, frames, dialogs, and windows: 28 human-doc token(s), 26 upstream token(s)
1254
+ - Network, storage, artifacts, diagnostics, and performance: 58 human-doc token(s), 68 upstream token(s)
1223
1255
  - Batch, auth, confirmations, setup, dashboard, devices, and AI commands: 36 human-doc token(s), 40 upstream token(s)
1224
1256
  - Global flags, config, providers, policy, and environment: 152 human-doc token(s), 119 upstream token(s)
1225
1257
 
@@ -1393,6 +1425,7 @@ This generated block is review data for maintainers. The human-authored referenc
1393
1425
  - `profiler start|stop [path]`
1394
1426
  - `record start <path> [url]`
1395
1427
  - `record restart <path> [url]`
1428
+ - `--fps <n>`
1396
1429
  - `record stop`
1397
1430
  - `console [--clear]`
1398
1431
  - `errors [--clear]`
@@ -1640,6 +1673,7 @@ This generated block is review data for maintainers. The human-authored referenc
1640
1673
  ##### Core page, element, navigation, and extraction commands
1641
1674
  - open help: `open [url]`
1642
1675
  - open help: `aliases still require a URL.`
1676
+ - open help: `agent-browser webmcp list`
1643
1677
  - root help: `open <url>`
1644
1678
  - root help: `read [url]`
1645
1679
  - read help: `read [url]`
@@ -1741,6 +1775,7 @@ This generated block is review data for maintainers. The human-authored referenc
1741
1775
  - tab help: `new --label <name> [url]`
1742
1776
  - tab help: `close [t<N>|label|target]`
1743
1777
  - tab help: `Stable tab ids`
1778
+ - tab help: `overrides before their first document loads.`
1744
1779
  - tab help: `tab_gone`
1745
1780
  - tab help: `data.targetId`
1746
1781
  - tab help: `data.lastUrl`
@@ -1815,7 +1850,8 @@ This generated block is review data for maintainers. The human-authored referenc
1815
1850
  - trace help: `trace start`
1816
1851
  - trace help: `trace stop [path]`
1817
1852
  - profiler help: `--categories <list>`
1818
- - record help: `record restart <path.webm> [url]`
1853
+ - record help: `record restart <path.webm|path.mp4> [url] [--fps <n>]`
1854
+ - record help: `--fps <n>`
1819
1855
  - console help: `--clear`
1820
1856
  - errors help: `--clear`
1821
1857
 
package/docs/RELEASE.md CHANGED
@@ -108,7 +108,7 @@ Minimum pass:
108
108
  3. Exercise one dashboard scroll path. If page-level `scroll` does not move visible content, confirm `details.scrollNoop` / next actions or equivalent guidance points to snapshot/screenshot verification and nested-scroll recovery.
109
109
  4. Exercise one explicit combobox-targeted action such as a role/name `semanticAction` on a dashboard variable. If it only focuses the field, confirm `details.comboboxFocus` / next actions point to `snapshot -i`, `press ArrowDown`, and `press Enter` when the closed-state evidence qualifies.
110
110
  5. Capture at least one screenshot artifact and verify `details.artifactVerification` before using the file.
111
- 6. If `ffmpeg` is on `PATH`, run a short `record start` / visible interaction / `record stop` cycle and verify the WebM artifact. If `ffmpeg` is absent, confirm `details.recordingDependencyWarning` appears after `record start` and stop before relying on recording evidence.
111
+ 6. If `ffmpeg` is on `PATH`, run `record start` / visible interaction / `record stop` and verify the video artifact. Native 0.37 checks ffmpeg before start; older natives may instead return pending output plus `details.recordingDependencyWarning`. Neither is usable recording evidence. Short/cold 0.37 captures have failed on Ubuntu while explicit 12-second fixture captures encoded successfully; record capture duration and every failed attempt, and never treat an empty file as a captured frame.
112
112
  7. Inspect `network requests`, `console`, and `errors` summaries. Treat Grafana Play-side noise such as analytics/Sentry requests, public-demo 403s, and console errors as site noise unless the wrapper leaks secrets, hides actionable failed rows, misclassifies artifacts, or suggests unsafe follow-ups.
113
113
  8. Close the browser session and delete temporary screenshots, HARs, recordings, and scratch reports after extracting any release evidence.
114
114
 
@@ -267,8 +267,10 @@ That npm script sets `PI_AGENT_BROWSER_REAL_UPSTREAM=1` for the test process. To
267
267
 
268
268
  This suite requires the installed stable `agent-browser --version` to meet the minimum in `scripts/agent-browser-target.mjs`; the output-shape fixture and command-reference verifier remain aligned to the current recommended baseline. It serves fixture pages from localhost and checks stable `details`/`data` keys via `test/fixtures/agent-browser-real-output-shapes.json`. Coverage groups:
269
269
 
270
- - **Inspection and skills (stateless JSON):** `--version`, `--help`, `snapshot --help`, `skills list`, `skills get … --full` (including `webmcp-gen` on the 0.36.0 target), `skills path …` (no managed `sessionName` / `usedImplicitSession`).
271
- - **WebMCP target contract:** on the 0.36.0 target, `webmcp list`, `invoke` with params/frame selection, detached `result` / `cancel`, ref invalidation after page tools, and a separate fresh launch with `--no-webmcp` returning an empty list.
270
+ - **Inspection and skills (stateless JSON):** `--version`, `--help`, `snapshot --help`, `skills list`, `skills get … --full` (including `webmcp-gen` on the 0.37.0 target), `skills path …` (no managed `sessionName` / `usedImplicitSession`).
271
+ - **WebMCP target contract:** on the 0.37.0 target, `webmcp list`, `invoke` with params/frame selection, detached `result` / `cancel`, ref invalidation after page tools, and a separate fresh launch with `--no-webmcp` returning an empty list.
272
+ - **Navigation metadata and native tab setup:** plain pages stay quiet; a page with tools retains positive native `data.webmcp` and shows the `webmcp list` hint. New tabs inherit configured headers before their first request, and clearing headers removes them on the next tab. No wrapper inheritance code is involved.
273
+ - **Recording FPS paths and pinning:** the opt-in `test/agent-browser.batch-fidelity.test.ts` native case checks direct/raw/stdin preflight before dispatch, actual start/restart destinations and pinned targets with leading `--fps`, conservative start-ref protection, FPS-only restart continuity, and valid 12-fps WebM output after explicitly logged 12-second fixture captures. Run it with `PI_AGENT_BROWSER_REAL_UPSTREAM=1`; it requires native 0.37 or newer. Keep focused older-native controls for fresh-page starts and the start-then-ref batch latch when changing that policy.
272
274
  - **Managed session core and safe diagnostic matrix:** fresh `open` on the contract fixture, then implicit reuse across `eval --stdin`, `snapshot -i`, interaction commands (`click`, `dblclick`, `fill`, `type`, `type --clear --delay`, `focus`, `keyboard` with `type` / `inserttext`, `press`, `hover`, `check`, `uncheck`, `select`, failed `select` no-match, `upload`, `drag`, `mouse`, `scroll`, off-viewport click, `scrollintoview`, `wait` on selectors in the main frame and a selected iframe), extraction (`get` variants, `is` variants, `find label … fill` via native `<label>`, `aria-label`, and `aria-labelledby`, inline `eval`), file outputs (`screenshot`, `pdf`), navigation (`back`, `forward`, `reload`, `tab list`, another `open` to the same fixture), `batch` stdin, `pushstate`, `vitals … --json`, network route/requests/HAR, diff snapshot/screenshot/url, trace/profiler, console/errors/highlight, stream enable/status/disable, and `cookies set --curl`.
273
275
  - **Managed restore correctness and persistence:** while the restore-enabled managed daemon is active, assert raw argument and stdin batches containing nested `connect` fail before upstream spawn; a new empty-transcript harness must also reject incompatible reuse of that live same-name daemon. Seed a cookie plus localStorage/sessionStorage, close the first managed browser while a conflicting parent namespace is set, verify the default-namespace daemon actually closed, create a new extension harness with the same cwd, reopen the fixture, and assert all three values restore before closing the second browser. On POSIX, separate isolated real-browser launches assert automatic restore stays disabled and no snapshot is written through either a symlinked `sessions` directory or a file symlink in `sessions/.tmp`; a relative `HOME`, untrusted writable HOME ancestry, and a non-Git cwd must fail closed. Verify a checkout rename preserves its generation identity but starts a fresh composite restore key (fail-closed, because the cwd-derived managed-session base name changes), a copied or path-replacement checkout gets a new key, and changing the Git-generation marker between planning and spawn prevents agent-browser from starting. Run two same-identity harnesses concurrently so a compatible launch publishes its daemon policy before a waiting incompatible launch re-inspects and fails without reaching its main spawn; also fail a fresh non-batch command after daemon creation and verify shutdown closes the retained identity.
274
276
  - **Cold first-read continuity:** the focused `contract suite matches cold URL reopen after quit` case runs actual quit cleanup, waits for the exact old daemon to exit, reloads the saved branch, and requests `snapshot -i` before any explicit navigation. Empty storage and origin storage must both reach their remembered non-root URL, report fresh refs in the main frame, and retain storage without pretending to retain unsaved forms or JavaScript memory. Separate deterministic cold-resume/boundary tests cover first `get url` and history commands, non-page daemon-starting calls and batch prefixes, hash routes, pending-state transcript replay, live missing tabs versus explicit URL destinations, close retirement, and caller-owned/attached/restore-disabled boundaries. Those fake-upstream checks do not replace native-browser or real Pi lifecycle qualification of the complete candidate.
@@ -285,7 +287,7 @@ For a root-check change, run the identical final test against both the pre-fix a
285
287
 
286
288
  ### Real upstream suite mechanics, isolation, and troubleshooting
287
289
 
288
- - **Focused and broad cases:** `test/agent-browser.real-upstream-contract.test.ts` keeps the broad command matrix in one 180-second case and separate 60-second cold-reopen, duplicate-name click-mutation, and sessionless-plugin cases. The `real-upstream` facade's `contract suite matches` selection includes the broad matrix, cold reopen, and click mutation. The click case uses two native DOM buttons to prove a stale duplicate ordinal cannot contradict trusted target events, while exact XPath probes still detect missing events and native clicks remain dispatch-only evidence.
290
+ - **Focused and broad cases:** `test/agent-browser.real-upstream-contract.test.ts` keeps the broad command matrix in one 180-second case and separate 60-second cold-reopen, duplicate-name click-mutation, navigation-availability/tab-setup, and sessionless-plugin cases. The `real-upstream` facade's `contract suite matches` selection includes the broad matrix, cold reopen, click mutation, and navigation setup. The click case uses two native DOM buttons to prove a stale duplicate ordinal cannot contradict trusted target events, while exact XPath probes still detect missing events and native clicks remain dispatch-only evidence.
289
291
  - **Output-shape locking:** Expected `details` / `data` keys per step live in `test/fixtures/agent-browser-real-output-shapes.json`, keyed by logical groups (`version`, `rootHelp`, `commandHelp`, `skillsList`, `skillsGetFull`, `skillsPath`, `open`, `eval`, `snapshot`, `coreCommand`, `coreSubcommand`, `coreFileArtifact`, `batch`, `pushstate`, `vitals`, `networkRoute`, `nonCoreStatus`, `nonCoreArtifact`, `diffScreenshotArtifact`, `streamControl`, `streamStatus`, `cookiesCurl`, `reactMissingRenderer`, `waitDownload`). Keep `targetVersion` in that file aligned with `scripts/agent-browser-capability-baseline.mjs`, and extend entries whenever the suite starts asserting on new presentation fields.
290
292
  - **Isolation:** The harness allocates a throwaway directory under the system temp folder, points `HOME`, `AGENT_BROWSER_SOCKET_DIR`, and `AGENT_BROWSER_SCREENSHOT_DIR` at that tree, serves HTML fixtures from loopback (`startAgentBrowserContractFixtureServer` in `test/helpers/agent-browser-harness.ts`), and closes the managed session before deleting the temp tree. The main matrix does not reuse your normal profile or socket locations.
291
293
  - **React DevTools branch:** After the core matrix, the suite performs another `open` with `--enable react-devtools` and `sessionMode: "fresh"`, then expects `react tree` to fail with a missing-renderer style error on the same non-React contract page. The following download fixture + `wait --download` assertions run against whichever managed session is current after that fresh `open` (typically the React DevTools session), not the original pre-matrix session name.