pi-agent-browser-native 0.9.6 → 0.9.8

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 (34) hide show
  1. package/CHANGELOG.md +108 -1
  2. package/README.md +14 -6
  3. package/dist/extensions/agent-browser/index.js +1276 -350
  4. package/dist/packaged/lib/browser-session-conversion.js +157 -21
  5. package/dist/packaged/lib/playbook.js +42 -8
  6. package/dist/packaged/lib/results/snapshot.js +140 -11
  7. package/dist/packaged/lib/runtime.js +58 -10
  8. package/docs/ARCHITECTURE.md +19 -10
  9. package/docs/CODE_QUALITY.md +21 -5
  10. package/docs/COMMAND_REFERENCE.md +154 -38
  11. package/docs/ELECTRON.md +1 -1
  12. package/docs/PERFORMANCE.md +12 -3
  13. package/docs/REFERENCE.md +14 -14
  14. package/docs/RELEASE.md +44 -19
  15. package/docs/REQUIREMENTS.md +6 -0
  16. package/docs/SESSION_STORAGE.md +3 -3
  17. package/docs/SUPPORT_MATRIX.md +25 -23
  18. package/docs/TOOL_CONTRACT.md +37 -14
  19. package/docs/platform-smoke.md +18 -14
  20. package/package.json +6 -3
  21. package/platform-smoke.config.mjs +3 -2
  22. package/scripts/agent-browser-capability-baseline.mjs +16 -2
  23. package/scripts/agent-browser-target.mjs +1 -1
  24. package/scripts/capability-options.mjs +20 -0
  25. package/scripts/capability-samples.mjs +23 -10
  26. package/scripts/platform-smoke/commands.mjs +30 -4
  27. package/scripts/platform-smoke/doctor-support.mjs +11 -2
  28. package/scripts/platform-smoke/doctor-windows.mjs +1 -1
  29. package/scripts/platform-smoke/doctor.mjs +26 -11
  30. package/scripts/platform-smoke/linux-image/Dockerfile +6 -3
  31. package/scripts/platform-smoke/platform-build-windows.ps1 +23 -3
  32. package/scripts/platform-smoke/suite-checks.mjs +11 -1
  33. package/scripts/platform-smoke/targets.mjs +4 -3
  34. package/scripts/platform-smoke.mjs +68 -25
@@ -166,9 +166,11 @@ launch time. See [the proof contract](REFERENCE.md#proof-and-verification).
166
166
  ### Journal and artifact storage
167
167
 
168
168
  Journal projection uses the installed streaming parser's raw tokenizer instead of
169
- building a Node stream pipeline for each record. Fatal incremental UTF-8 decoding,
170
- full JSON validation—including discarded values—and an explicit end-of-input
171
- flush remain required. The parser is still loaded lazily.
169
+ building a Node stream pipeline for each record. Live replay applies the same
170
+ native-or-token selection as its metadata scan to retained-size records; larger
171
+ records still use the tokenizer. Both paths validate UTF-8 and complete JSON,
172
+ including discarded values. The streaming path retains its explicit end-of-input
173
+ flush, and the parser is still loaded lazily.
172
174
 
173
175
  Both offline converters retain a branch projection only until its last source
174
176
  child consumes it. Linear histories no longer retain every historical state map;
@@ -197,6 +199,13 @@ not a cross-call cache. Replacement and unknown-generation checks remain
197
199
  fail-closed; capture still obtains its distinct post-operation generation receipt.
198
200
  Calls with no redundant observation keep their existing probes.
199
201
 
202
+ A call waiting for another Pi process's browser operation no longer starts a
203
+ process-identity query every 10 ms while that holder is confirmed alive. It sleeps
204
+ on the holder's owner-lifetime socket and re-runs normal arbitration when the
205
+ socket closes on release or exit. Unverifiable and still-choosing claims,
206
+ unavailable endpoints (including socket paths over the platform limit) and
207
+ native Windows keep polling. See [execution coordination](ARCHITECTURE.md).
208
+
200
209
  Independent timeout-artifact retry windows now overlap. Each declared path still
201
210
  gets up to three checks, 25 ms apart; results retain native plan order and page
202
211
  inspection starts afterward. A file finishing after **its own** window may remain
package/docs/REFERENCE.md CHANGED
@@ -8,7 +8,7 @@ It is for Pi users who want agents to browse sites, inspect pages, click through
8
8
 
9
9
  ## Pi release qualification
10
10
 
11
- CI qualifies the latest stable official Pi and latest maintained fork `main`, resolving their version/commit once per run and retaining SDK/CLI identity evidence. Locked development dependencies are reproducible build snapshots, not qualification targets; runtime peers remain wildcard. `npm run check:compat` checks the installed candidate SDK/CLI identity, typechecks, runs the existing offline tests (including the native Pi pipeline with a controlled provider and fake browser), and tests a packed runtime-only installation through both the SDK and the actual bundled RPC CLI. It does not substitute a fork SDK while leaving official types or child CLI installed.
11
+ CI qualifies the latest stable official Pi and latest maintained fork `main`, resolving their version/commit once per run and retaining SDK/CLI identity evidence. Locked development dependencies are reproducible build snapshots, not qualification targets; runtime peers remain wildcard. The development snapshot overrides Undici to exact 8.12.3 because official Pi 1.0.2 through 1.4.0 pins exact Undici 8.10.2, which has the high/moderate advisories GHSA-xjj6-f33q-929c, GHSA-4qv8-2p9j-2685 and GHSA-f72v-6w45-q472; remove the override once the official development SDK depends on 8.12.2 or later. npm applies root overrides only where this repository is the npm root project: checkouts and Git-source installs, whose build-time development tree resolves 8.12.3. Published npm-package consumers never receive it, the extension does not import Undici at runtime, and qualified official Pi hosts keep their own Undici 8.10.2. `npm run check:compat` checks the installed candidate SDK/CLI identity, typechecks, runs the existing offline tests (including the native Pi pipeline with a controlled provider and fake browser), and tests a packed runtime-only installation through both the SDK and the actual bundled RPC CLI. It does not substitute a fork SDK while leaving official types or child CLI installed.
12
12
 
13
13
  Run in an empty HOME with a **short** TMPDIR outside your real home. Long temporary paths can exceed macOS's 103-byte Unix socket limit; keep the fixture's socket safety checks intact. Native lifecycle controls, live upstream help sampling, lifecycle dogfood, and platform qualification remain the separate gates documented below. A Pi-only compatibility run uses no live browser profiles, credentials, or agent-browser fork, and does not certify those external integrations.
14
14
 
@@ -96,7 +96,7 @@ The result is optimized for agent work:
96
96
  | Dashboard scroll commands can look successful while nothing moves | Handles standard `scroll <dir> [px]` against the document first (including pages whose smooth-scroll CSS defeats upstream wheel timing), falls back upstream when the document cannot move, and samples viewport/containers around the fallback; explicit CSS-container scrolling uses instant movement so smooth-scroll CSS cannot cause a premature no-movement failure; unchanged positions fail as `upstream-error` with `details.scrollNoop`, visible recovery guidance, and exact snapshot/screenshot checks. Unsupported `scrollintoview text=...` fails before dispatch, including inside effective batch rows, and shows exact native `find text ... hover` and snapshot/ref recovery payloads; help remains native pass-through. | [`docs/TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details), [`docs/COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#core-page-and-element-commands), `test/agent-browser.extension-validation.test.ts` |
97
97
  | Dropdown/combobox clicks can focus or hit native option box-model errors | Adds first-class `select <selector> <value...>` paths through native `args` and `agent_browser_action`; semantic role/name or label select resolves exactly one current visible combobox/listbox ref before action. Custom combobox clicks still detect focused controls with explicit `aria-expanded` state but no visible options and return `details.comboboxFocus` plus exact recovery `nextActions` | [`docs/TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details), [`docs/COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#core-page-and-element-commands), `extensions/agent-browser/lib/input-modes/semantic-action.ts`, `test/agent-browser.extension-input-modes.test.ts`, `test/agent-browser.extension-validation.test.ts` |
98
98
  | Recording workflows fail late when `ffmpeg` is missing or report stale lifecycle state | After successful `record start` / `record restart`, reports `successCategory: "artifact-pending"`, returns an exact `stop-pending-recording` action, warns when older natives report pending output without `ffmpeg`, and conservatively invalidates prior page-scoped `@e…` refs on every executed start attempt and URL-bearing restart to protect older supported natives. This is not evidence of a page change: 0.37 records the active page unless a URL is supplied; FPS-only calls keep the intended tab; an unbounded transcript-backed namespace/session index reserves active destinations across aliases, serializes artifact lifecycle and explicit wait/output writes, persists cross-branch close tombstones, retires every successful close path (including every matching namespace owner for `close --all`), rejects missing/stale restart output, coalesces terminal batch state, keeps only the newest pending path per identity, rejects recording starts after a nested close, folds Unicode path aliases, and retains exact cleanup actions with visible guidance on any later same-session failure | [`docs/TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details), [`docs/COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#diff-debug-and-streaming), `test/agent-browser.extension-validation.test.ts`, `test/agent-browser.presentation-artifacts-batch.test.ts` |
99
- | Upstream CLI drift can silently invalidate wrapper behavior | Publishes a repo-readable command reference, verifies it against the recommended 0.38.1 target, and probes browser-backed calls once per cwd/PATH so stable versions below the 0.35.0 floor fail before browser launch with installed/expected version evidence | `npm run verify` |
99
+ | Upstream CLI drift can silently invalidate wrapper behavior | Publishes a repo-readable command reference, verifies it against the recommended 0.41.0 target, and probes browser-backed calls once per cwd/PATH so stable versions below the 0.35.0 floor fail before browser launch with installed/expected version evidence | `npm run verify` |
100
100
  | Pages can expose structured workflows through experimental WebMCP | Shows native positive WebMCP availability in navigation summaries and passes through `webmcp list`, `invoke`, detached `result` / `cancel`, params/frame/timeout options, and the bundled `webmcp-gen` skill; treats `--no-webmcp` as launch-scoped, keeps pending or unsuccessfully settled targets unverified with an actionable `get url` follow-up, invalidates stale refs after page tools run, and budgets effective raw or stdin batch timeouts | [`docs/COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#webmcp-page-tools), `test/agent-browser.extension-ref-guards.test.ts`, `test/agent-browser.wait-timeouts.test.ts`, `test/agent-browser.real-upstream-contract.test.ts` |
101
101
  | Desktop Electron apps need discovery, CDP attach, and safe teardown | `agent_browser_electron` runs host `list` / isolated `launch` (temp profile, OS-chosen debug port) / `status` / `probe` / `cleanup`, merges `launchId` plus managed `sessionName`, supports `handoff` `snapshot` / `tabs` / `connect`, and surfaces mismatch and post-command health guidance; wrapper cleanup applies only to launches it created | `extensions/agent-browser/lib/electron/discovery.ts`, `launch.ts`, `cleanup.ts`, [`docs/TOOL_CONTRACT.md`](TOOL_CONTRACT.md#agent_browser_electron), [`docs/COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#electron-desktop-apps) |
102
102
  | Agents need bundled `skills` text and local setup/status commands without touching the live session | Treats `skills list/get/path`, local auth/profile/setup commands, `session list`, and local state lifecycle commands as sessionless reads/actions when upstream does not need a live page. Session/state rows and targets remain visible, and supported upstream state/config/path operations pass through unchanged. Browser-backed workflows still receive an implicit session only when the caller did not choose one. | [`docs/COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#built-in-skills), `extensions/agent-browser/lib/command-policy.ts`, `extensions/agent-browser/lib/runtime.ts` |
@@ -119,9 +119,9 @@ Optional external tools unlock the full command surface:
119
119
  | `agent-browser` | All browser automation through this extension | See upstream install docs |
120
120
  | `ffmpeg` | Recording WebM (libvpx) or MP4 (libx264); install before `record start` / `record restart` | `brew install ffmpeg` or `brew install ffmpeg-full` |
121
121
 
122
- Keep both binaries on `PATH`. This package recommends `agent-browser 0.38.1` and accepts stable versions at or above the 0.35.0 floor; browser-backed calls fail fast below that floor while local inspection/setup commands remain available for diagnosis. Native 0.37 validates `ffmpeg`, the output extension and FPS before recording; older supported natives may defer failures until stop. Use `record start <path.webm|path.mp4> [url] [--fps <n>]` (1–60 fps, default 30), then verify the completed file after `record stop`. Native `doctor` checks the recording dependency and encoders.
122
+ Keep both binaries on `PATH`. This package recommends `agent-browser 0.41.0` and accepts stable versions at or above the 0.35.0 floor; browser-backed calls fail fast below that floor while local inspection/setup commands remain available for diagnosis. Native 0.37 validates `ffmpeg`, the output extension and FPS before recording; older supported natives may defer failures until stop. Use `record start <path.webm|path.mp4> [url] [--fps <n>]` (1–60 fps, default 30), then verify the completed file after `record stop`. Native `doctor` checks the recording dependency and encoders.
123
123
 
124
- On 0.38.1, use `snapshot --delta` for native full/unchanged/changed revisions and `snapshot --delta --full` to reset its baseline. Surviving DOM nodes keep their refs, but navigation/replaced nodes still require fresh refs. The wrapper preserves native revisions and refreshes complete refs internally for partial results. `screenshot --if-changed` (or `--threshold 0.01`) skips unchanged images without creating an artifact. `--input-mode instant|smooth|human` controls native session pointer movement; `click ... --human`, `drag ... --human`, and timed `mouse move` remain ordinary `args`. Recordings accept `--cursor` and `--contact-sheet`; the latter produces a timestamped PNG verified after stop. `auth login <name> --no-navigate` fills a prepared login page after upstream checks its origin. See the [command reference](COMMAND_REFERENCE.md#upstream-0381-rebaseline) for examples and limits.
124
+ On 0.38+, use `snapshot --delta` for native full/unchanged/changed revisions and `snapshot --delta --full` to reset its baseline. Surviving DOM nodes keep their refs, but navigation/replaced nodes still require fresh refs. The wrapper preserves native revisions and refreshes complete refs internally for partial results. `screenshot --if-changed` (or `--threshold 0.01`) skips unchanged images without creating an artifact. `--input-mode instant|smooth|human` controls native session pointer movement; `click ... --human`, `drag ... --human`, and timed `mouse move` remain ordinary `args`. Recordings accept `--cursor` and `--contact-sheet`; the latter produces a timestamped PNG verified after stop. `auth login <name> --no-navigate` fills a prepared login page after upstream checks its origin. See the [command reference](COMMAND_REFERENCE.md#upstream-0381-rebaseline) for examples and limits.
125
125
 
126
126
  ### Android / Termux
127
127
 
@@ -203,7 +203,7 @@ npm run doctor
203
203
  The doctor checks:
204
204
 
205
205
  - upstream `agent-browser` exists on `PATH`
206
- - the installed upstream is a stable version at or above the supported 0.35.0 floor; 0.38.1 remains the recommended baseline
206
+ - the installed upstream is a stable version at or above the supported 0.35.0 floor; 0.41.0 remains the recommended baseline
207
207
  - `pi --version` meets the minimum Pi runtime floor for this release; older Pi versions are setup failures
208
208
  - Pi settings do not point at multiple active `pi-agent-browser-native` sources
209
209
 
@@ -554,7 +554,7 @@ Ordinary native config discovery stays at the project or current managed browser
554
554
 
555
555
  ### Shared browser defaults
556
556
 
557
- Ordinary browser calls use one native named browser per **root Pi session**. A parent and its subagents share that browser; unrelated roots get different names and can browse concurrently. `pi-subagents` supplies `PI_SUBAGENT_ROOT_SESSION_ID` through its existing launch records, including detached runs, delegated forks, grandchildren, and revived children. Ordinary Pi new/fork/clone sessions get their own root identity; resuming the same root or changing its cwd keeps its browser name.
557
+ Ordinary browser calls use one native named browser per **root Pi session**. A parent and its subagents share that browser; unrelated roots get different names and can browse concurrently. Current `pi-subagents` launches each child with equal `PI_INTERCOM_ROOT_SESSION_ID` and `PI_INTERCOM_PARENT_SESSION_ID` values naming its main session, including fresh and forked delegated runs; older releases supplied `PI_SUBAGENT_CHILD` with `PI_SUBAGENT_ROOT_SESSION_ID`, which remains supported. Ordinary Pi new/fork/clone sessions get their own root identity; resuming the same root or changing its cwd keeps its browser name.
558
558
 
559
559
  Cooperating updated Pi processes share a cross-process lock keyed by the actual socket context, canonical namespace, and session. It covers a direct call's helpers and action, or an entire code call; different identities can run independently. Coordinate navigation across separate tool calls with existing subagent/intercom tools. This is ordering, not rollback or protection against human navigation, external CLI clients, or older extension versions. Parent or child exit does not close the group browser. Native idle policy applies; explicitly close only your group's browser when the group is finished.
560
560
 
@@ -709,7 +709,7 @@ The opt-in real-upstream suite is separate because it drives a real browser inst
709
709
  npm run verify -- real-upstream
710
710
  ```
711
711
 
712
- That mode sets `PI_AGENT_BROWSER_REAL_UPSTREAM=1` and runs `test/agent-browser.real-upstream-contract.test.ts` against the real `agent-browser` on `PATH` (the stable version must meet the 0.35.0 floor; current command-reference validation targets the recommended 0.38.1 capability baseline), selecting the sessionless plugin probe separately and then all remaining declarations, including explicit native text. It also runs `test/agent-browser.batch-fidelity.test.ts` and `test/agent-browser.overlay-real-upstream.test.ts` with the same opt-in environment. It covers inspection, skills, experimental WebMCP list/invoke/result/cancel plus `--no-webmcp`, and a broad core interaction and navigation matrix on localhost fixtures (including off-viewport click, frame-scoped selector/wait/click behavior, form command fixes, `batch` stdin, and `pushstate`), plus `vitals`, network route/requests/HAR, diff snapshot/screenshot/url, trace/profiler, console/errors/highlight, stream enable/status/disable, `cookies set --curl`, a `react tree` missing-renderer path, and `wait --download` with the on-disk caveat documented in release notes. The harness uses a throwaway temp `HOME` and dedicated socket/screenshot directories so the run does not touch your normal browser profile paths. Browser-opening or credential-dependent families such as `inspect`, `dashboard`, `chat`, provider clouds, and OS clipboard flows stay in fake-upstream or manual validation unless a safe deterministic fixture is added. For prerequisites, isolation details, and troubleshooting, see [`docs/RELEASE.md`](RELEASE.md#real-upstream-contract-validation).
712
+ That mode sets `PI_AGENT_BROWSER_REAL_UPSTREAM=1` and runs `test/agent-browser.real-upstream-contract.test.ts` against the real `agent-browser` on `PATH` (the stable version must meet the 0.35.0 floor; current command-reference validation targets the recommended 0.41.0 capability baseline), selecting the sessionless plugin probe separately and then all remaining declarations, including explicit native text. It also runs `test/agent-browser.batch-fidelity.test.ts` and `test/agent-browser.overlay-real-upstream.test.ts` with the same opt-in environment. It covers inspection, skills, experimental WebMCP list/invoke/result/cancel plus `--no-webmcp`, and a broad core interaction and navigation matrix on localhost fixtures (including off-viewport click, frame-scoped selector/wait/click behavior, form command fixes, `batch` stdin, and `pushstate`), plus `vitals`, network route/requests/HAR, diff snapshot/screenshot/url, trace/profiler, console/errors/highlight, stream enable/status/disable, `cookies set --curl`, a `react tree` missing-renderer path, and `wait --download` with the on-disk caveat documented in release notes. The harness uses a throwaway temp `HOME` and dedicated socket/screenshot directories so the run does not touch your normal browser profile paths. Browser-opening or credential-dependent families such as `inspect`, `dashboard`, `chat`, provider clouds, and OS clipboard flows stay in fake-upstream or manual validation unless a safe deterministic fixture is added. For prerequisites, isolation details, and troubleshooting, see [`docs/RELEASE.md`](RELEASE.md#real-upstream-contract-validation).
713
713
 
714
714
  A deterministic host-only live-browser wrapper smoke is available without an LLM choosing tool calls:
715
715
 
@@ -729,7 +729,7 @@ npm run smoke:platform:doctor
729
729
  npm run verify -- release
730
730
  ```
731
731
 
732
- `npm run verify -- release` includes the default verification gate, packaged Pi smoke coverage, and the release-blocking Crabbox platform matrix (the same matrix `npm run smoke:platform:all` runs standalone). For the full maintainer release flow, follow [`docs/RELEASE.md`](RELEASE.md). The package also has a `prepublishOnly` hook that runs the same release gate and `npm pack --dry-run` during `npm publish`.
732
+ `npm run verify -- release` includes the default verification gate, the configured-source lifecycle harness, packaged Pi smoke coverage, and the release-blocking Crabbox platform matrix (the same matrix `npm run smoke:platform:all` runs standalone). For the full maintainer release flow, follow [`docs/RELEASE.md`](RELEASE.md). The package also has a `prepublishOnly` hook that runs the same release gate and `npm pack --dry-run` during `npm publish`.
733
733
 
734
734
  ## How it works
735
735
 
@@ -742,12 +742,12 @@ npm run verify -- release
742
742
  5. Screenshots, downloads, recordings, traces, profiles, and spill files are normalized as Pi-visible artifacts where possible.
743
743
  6. Generated playbook text in docs and browser instructions stays aligned with `extensions/agent-browser/lib/playbook.ts`.
744
744
 
745
- The upstream browser engine remains [`agent-browser`](https://agent-browser.dev/). This package does not bundle it. The recommended baseline is 0.38.1 and the stable runtime floor is 0.35.0; newer stable versions are accepted without version-specific compatibility shims.
745
+ The upstream browser engine remains [`agent-browser`](https://agent-browser.dev/). This package does not bundle it. The recommended baseline is 0.41.0 and the stable runtime floor is 0.35.0; newer stable versions are accepted without version-specific compatibility shims.
746
746
 
747
747
  ## Current limits
748
748
 
749
749
  - Published pre-1.0 package.
750
- - Recommends upstream `agent-browser` 0.38.1 and accepts stable runtimes at or above 0.35.0.
750
+ - Recommends upstream `agent-browser` 0.41.0 and accepts stable runtimes at or above 0.35.0.
751
751
  - Does not bundle `agent-browser`; users install it separately.
752
752
  - Does not provide a human browser UI inside Pi; the primary UX is agent-invoked tool calls. `--headed` asks upstream to show a browser window, but the wrapper cannot yet prove that the window is visible on the user's desktop.
753
753
  - Localhost means the browser host's loopback, not necessarily the shell/Pi host. If `http://localhost:<port>` or `http://127.0.0.1:<port>` fails with errors such as `ERR_EMPTY_RESPONSE`, use an environment-specific host-reachable HTTP(S) address. A `file://` fixture is supported when upstream browser launch settings allow it; use HTTP(S) only when the browser environment cannot reach the local file.
@@ -757,11 +757,11 @@ The upstream browser engine remains [`agent-browser`](https://agent-browser.dev/
757
757
 
758
758
  ## Automatic npm releases (maintainers)
759
759
 
760
- Follow the [shared release procedure](https://github.com/fitchmultz/.github#automatic-npm-releases): merge a reviewed PR into `main` with an intentional `package.json` version bump and a matching versioned `CHANGELOG.md` section. Automation never bumps versions, overwrites releases, or republishes an existing version. Once configured and enabled, it runs existing compatibility and native lifecycle checks, qualifies one candidate tarball, then publishes it without an approval step.
760
+ The [shared release procedure](https://github.com/fitchmultz/.github#automatic-npm-releases) creates a reviewed patch-version PR after changes merge to `main`, then publishes the same version on npm and GitHub using the exact qualified candidate tarball.
761
761
 
762
- Merging publishes, so before merging check the final PR head (up to date with `main`) and version against [the existing release gates](RELEASE.md#pre-release-checks), including required lifecycle/live-site evidence, artifact checks and all three final reviewer approvals. Apply the documented Windows waiver without claiming a Windows or full composed-gate pass. Merging attests genuine satisfaction of those requirements; it does not create proof. Authenticated, model-backed and paid checks stay outside CI. Automated publication disables npm hooks to publish the already checked bytes; the manual publisher instructions and their gates remain valid.
762
+ Check the final source and candidate against [the existing release gates](RELEASE.md#pre-release-checks), including required lifecycle/live-site evidence and artifact checks. Complete enabled reviews and resolve their findings. Apply the documented Windows waiver without claiming a Windows or full composed-gate pass. Workflow validation is not evidence that publication completed on either service.
763
763
 
764
- Failed/unpublished candidates can retry daily at 12:17 UTC or via manual dispatch of `npm release` on `main`, without another bump. Set repository variable `NPM_RELEASE_ENABLED` to anything other than `true` to stop new release plans; cancel pending runs separately when needed. Workflow validation is not evidence of a completed real OIDC publication.
764
+ Set repository variable `NPM_RELEASE_ENABLED` to anything other than `true` to stop new version and release plans; cancel pending runs separately when needed. Follow the shared procedure to retry an unpublished candidate.
765
765
 
766
766
  ## Local development
767
767
 
@@ -789,7 +789,7 @@ Configured-source lifecycle validation:
789
789
  npm run verify -- lifecycle
790
790
  ```
791
791
 
792
- The harness defaults to Pi model `zai/glm-5.2` and **180000 ms** per-step tmux waits; pass `--model <id>` and/or `--timeout-ms <ms>` after `lifecycle` when you need different settings (see [Configured-source lifecycle validation](RELEASE.md#configured-source-lifecycle-validation) in `docs/RELEASE.md`). It launches the supported Pi runtime with `--approve` and a deterministic `--session-id`, drives `/reload`, closes Pi, relaunches the exact same session, asserts the JSONL header id, and checks managed-session continuity, compiled-entrypoint pickup after process restart, persisted spill reachability, and native returned failure status and JSON preservation.
792
+ The harness defaults to Pi model `zai/glm-5.2` and **180000 ms** per-step tmux waits; pass `--model <id>` and/or `--timeout-ms <ms>` after `lifecycle` (or after `release`, which forwards them only to its lifecycle step) when you need different settings (see [Configured-source lifecycle validation](RELEASE.md#configured-source-lifecycle-validation) in `docs/RELEASE.md`). It launches the supported Pi runtime with `--approve` and a deterministic `--session-id`, drives `/reload`, closes Pi, relaunches the exact same session, asserts the JSONL header id, and checks managed-session continuity, compiled-entrypoint pickup after process restart, persisted spill reachability, and native returned failure status and JSON preservation.
793
793
 
794
794
  Use lifecycle validation when testing `/reload`, exact-session relaunch, `/resume`, managed-session continuity, or persisted artifact behavior. Branch-backed state and `session_tree` cleanup ownership are covered by focused extension harness tests. Maintainers must run the lifecycle harness before every publish; see [Pre-release checks](RELEASE.md#pre-release-checks).
795
795
 
package/docs/RELEASE.md CHANGED
@@ -18,11 +18,21 @@ Related docs:
18
18
 
19
19
  Provide one concrete maintainer workflow for validating repo state, package contents, and install guidance before publishing `pi-agent-browser-native`.
20
20
 
21
+ ## Native Windows: best-effort
22
+
23
+ The owner explicitly decided on 2026-10-22: **“Make native Windows explicitly a best effort.”** This supersedes [#191](https://github.com/fitchmultz/pi-agent-browser-native/issues/191) / PR291's restored blocking policy, not its failure evidence. Native Windows is not a first-class required PR, scheduled-default, or release qualification target. Known process-lock and restored Electron cleanup failures remain unresolved; no runtime repair is claimed.
24
+
25
+ Routine Pi compatibility retains one latest-official-host Windows build/import/process-transport smoke with job-level `continue-on-error: true`. Its failed steps, TAP and artifacts remain failed evidence, not a pass inferred from overall workflow success. It does not run `check:compat`, full unit/serial or consumer suites, build the corrected checker, or invoke models. Broader official/fork native Windows qualification is available only from manual Pi compatibility dispatch with `windows-qualification=true`; those job-level best-effort lanes retain their existing environment self-check, full contracts, Git/npm consumers and failed artifacts. Release callers cannot opt into these deep lanes. Missing or skipped evidence is not passed.
26
+
27
+ Required macOS/Linux, latest official/fork host/API/consumer qualification, Native lifecycle Linux, quality, Node floors, assertion/deadline/generation/ownership/security contracts remain unchanged. Local release/prepublish and default platform doctor/run select configured required macOS/Ubuntu targets only; optional Windows/Parallels setup cannot block that path. Explicit `windows-native` commands remain strict and nonzero on failure. Branch-protection/settings changes are separate and are not made by this PR.
28
+
29
+ Windows contract-test children enable only `NODE_DEBUG=pi-agent-browser-policy` inside the repository-owned `scripts/project.mjs` launcher used by `npm test` and the default/quality verification gates. This assignment happens **after** the pinned qualifier creates its isolated base environment; setting `NODE_DEBUG` or `NODE_OPTIONS` only on the outer workflow would be stripped and is not evidence that diagnostics ran. Build/preparation stages and ordinary runtime consumers do not enable the channel. The `npm test` gate retains complete parallel TAP and single-worker serial TAP stages, ordered and fail-blocking. Failed Windows jobs print at most 400 exact `PI-AGENT-BROWSER-POLICY <pid>:` stderr matches (including TAP-wrapped child stderr), report total/shown/omitted counts, and retain the complete `qualification.log` alongside the unchanged bounded failed-TAP diagnostics. Neither collection nor debug enablement changes coordination behavior, retries, test selection, or budgets.
30
+
21
31
  ## Current 0.6.16 rollout waiver
22
32
 
23
- The owner's 2026-09-21 **“waive windows”** instruction makes Windows qualification nonblocking for this rollout, even with available runners, and supersedes older mandatory-Windows/no-waiver wording below and in platform guidance. Preserve failed diagnostics; do not claim a Windows full-suite pass or continue Windows repair experiments. Known policy-lock/restored Electron failures and bounded repeat results are tracked in [#191](https://github.com/fitchmultz/pi-agent-browser-native/issues/191) and the [current support matrix](SUPPORT_MATRIX.md#current-0616-rollout).
33
+ This heading retains historical links. The owner's 2026-09-21 **“waive windows”** instruction made Windows qualification nonblocking for that rollout, even with available runners. It did not establish a Windows pass. The later [#191](https://github.com/fitchmultz/pi-agent-browser-native/issues/191) restoration replaced that CI exception at the time. The current best-effort support decision above now supersedes that restoration policy; neither decision erases failures. Do not reuse the September waiver as current authority. Known policy-lock/restored Electron failures and bounded repeat results remain recorded in the [support matrix](SUPPORT_MATRIX.md#current-0616-rollout).
24
34
 
25
- Linux/macOS, declared Node floors, official/fork host and consumer-artifact checks, and Native lifecycle Linux remain required. This waiver changes neither runtime nor the composed `release`/`prepublishOnly` scripts: record individually satisfied gates and the explicit Windows waiver, never label the full composition passed.
35
+ Linux/macOS, declared Node floors, official/fork host and consumer-artifact checks, Native lifecycle Linux, and the composed `release`/`prepublishOnly` scripts remain required. Retain all failed attempts. A hosted Windows contract pass is not a native browser dogfood or complete release-matrix pass.
26
36
 
27
37
  Docs/workflow-only changes may reuse prior live/platform evidence when the complete compiled runtime, runtime dependencies and relevant tests are unchanged. Changed published files require a new retained tarball checked by `verify-package.mjs --smoke-pi`, including runtime-only SDK and actual CLI loading. Publish those exact checked bytes without repacking.
28
38
 
@@ -30,7 +40,7 @@ Docs/workflow-only changes may reuse prior live/platform evidence when the compl
30
40
 
31
41
  This contract requires Pi 1.0.0. Do not install or activate it in running pre-1.0 sessions; coordinate the runtime cutover and restart participating agents first. Keep runtime activation separate from isolated checkout/SDK qualification. Preserve auth/profile/state files, explicit artifacts and Pi journals when updating or rolling back; browser mutations are not reversible through a package rollback.
32
42
 
33
- Qualify the exact official and fork host graphs independently, including SDK and actual CLI loading, explicit/defaultTools/loader/initial-resume/tree/reload selections, structured success/failure/redaction and unchanged JSON. Inspect regular and fullscreen native TUI results, including failures and images. Keep the existing 250 ms import/factory and 1,000 ms lock budgets; synthetic research timings are not final-source release evidence or universal performance guarantees. Apply normal release gates and the Windows waiver. Host identity and actual supported APIs, not a version label alone, determine qualification.
43
+ Qualify the exact official and fork host graphs independently, including SDK and actual CLI loading, explicit/defaultTools/loader/initial-resume/tree/reload selections, structured success/failure/redaction and unchanged JSON. Inspect regular and fullscreen native TUI results, including failures and images. Keep the existing 250 ms import/factory and 1,000 ms lock budgets; synthetic research timings are not final-source release evidence or universal performance guarantees. Apply normal required macOS/Linux release gates; Windows is separately labeled best-effort. Host identity and actual supported APIs, not a version label alone, determine qualification.
34
44
 
35
45
  ## 0.7 upgrade and rollback
36
46
 
@@ -46,7 +56,7 @@ The minimum Pi runtime is 1.0.0, matching the native APIs used by the new tool c
46
56
 
47
57
  Qualify official Pi 1.0 and the fork independently with the existing host/package/lifecycle infrastructure. Required evidence for the redesign includes compact schema and additive activation/history, native prompt sections, shared direct/code auth continuity, fresh JavaScript globals, selected real images and conservative geometry, visible handled failures/exact recovery, real cross-process helper/action and whole-cell ordering, cancellation/reaping, and ordered transition replay after interruption/branch changes. Retain native batch and advanced action/QA/Electron/source outcome coverage. Small synthetic timing comparisons are not universal performance claims or sandbox certification.
48
58
 
49
- Existing owner waivers remain authoritative. Windows qualification is waived; report diagnostic failures without claiming a pass or restarting waived repair work. Routine GitHub PR checks exclude Windows; opt-in native manual qualification retains owner-waived Windows diagnostics. These focused checks complement, rather than replace, the local release and publication gates.
59
+ Routine GitHub PR and release-call checks include a nonblocking Windows build/import/process smoke; deep official/fork Windows qualification and its environment self-check are manual-only. Retain every failed attempt, including historical waived diagnostics, without claiming a Windows pass from an aggregate that ignored failures. These focused checks complement, rather than replace, the local release and publication gates.
50
60
 
51
61
  ## Pre-release checks
52
62
 
@@ -76,9 +86,24 @@ npm run verify -- pre-pr
76
86
  1. `npm run verify` for generated playbook drift, TypeScript, unit/fake coverage, command-reference generated-block drift, and live command-reference verification against the targeted upstream on `PATH`
77
87
  2. `npm run verify -- lifecycle`, which launches the configured-source lifecycle harness for `/reload`, exact `--session-id` relaunch, managed-session continuity, persisted spill reachability, and native returned-failure behavior
78
88
  3. `npm run verify -- package-pi`, which first validates package contents via `npm pack --json --dry-run` and then smoke-loads the packed package in Pi isolation
79
- 4. `npm run smoke:platform:doctor` and the full Crabbox matrix from [`platform-smoke.md`](platform-smoke.md): macOS SSH, Ubuntu local-container, and native Windows Parallels targets running fast target-local `platform-build` plus `browser-dogfood-smoke`
89
+ 4. `npm run smoke:platform:doctor` and the required Crabbox matrix from [`platform-smoke.md`](platform-smoke.md): macOS SSH and Ubuntu local-container targets running fast target-local `platform-build` plus `browser-dogfood-smoke`
90
+
91
+ Lifecycle options can follow `release`: `--model <id>`, `--timeout-ms <ms>`, `--verbose`, and `--keep-artifacts` reach only step 2. Other options and invalid lifecycle values fail before any step runs. For example, `npm run verify -- release --model <provider>/<model>` runs the complete gate with the lifecycle prompts on that model. Without options, step 2 keeps the lifecycle defaults.
92
+
93
+ When release automation has already prepared a candidate, supply its retained tarball to the same complete gate:
94
+
95
+ ```bash
96
+ PI_AGENT_BROWSER_RELEASE_TARBALL=/absolute/path/to/candidate.tgz \
97
+ npm run verify -- release --keep-artifacts --verbose
98
+ ```
99
+
100
+ Package verification inspects the supplied archive and its packaged Markdown, checks its name, version, and integrity, and installs a private copy of those same bytes for the isolated Pi smoke. The configured-source lifecycle installs a private copy of the candidate and adds its test-only sentinel to that copy's compiled entrypoint for reload/relaunch checks. The required platform-build suites still pack their target-local checkout, then install the supplied candidate and check its SHA-256 before and after installation on each target. The verifier does not rebuild or delete the supplied file. The caller must compare the candidate with the shared preparation receipt before and after qualification and publish those verified bytes.
101
+
102
+ The reusable `release-qualification.yml` runs the same candidate against the selected official and fork Pi hosts. Default verification, packaged Pi loading, and the macOS/Ubuntu Crabbox suites run without inference. Before model-backed checks, `scripts/release-live-scope.mjs` compares every packed `dist/` file and the module-loading, dependency, engine, and Pi resource declarations with the actual latest npm package. These are the Pi agent runtime inputs. Version, docs, workflow, verification-harness, and standalone CLI changes alone reuse the published agent runtime's live evidence. CLI scripts remain covered by default verification and packaged CLI probes, not model-backed browser sessions. The retained scope receipt identifies both tarballs and records changed runtime paths; an unchanged runtime records `not_required`, not a new live pass. A baseline lookup or extraction failure stops qualification without making model calls.
103
+
104
+ When the packed Pi agent runtime changes, the selected-host job runs lifecycle checks and `scripts/verify-live-sites.mjs`: an interactive Pi session visits CERN and React documentation, navigates an observed ref, verifies a screenshot delivered to a vision model, reloads, and closes its owned browser. These necessary hosted calls use only direct `zai/glm-5.3-flash`, with `ZAI_API_KEY` from the main-only `release` environment. The key is required only for this branch. The macOS SSH and Ubuntu container Crabbox jobs run both required suites on separate native runners, each checking the candidate identity before and after. Windows remains best-effort.
80
105
 
81
- When using the documented, maintainer-approved [local macOS alternative](platform-smoke.md#alternate-native-transports), run and inspect that target-local suite separately alongside the remaining release checks. The default composed gate is unchanged; alternate evidence must not be labeled a passing Crabbox matrix.
106
+ When using the documented, maintainer-approved [local macOS alternative](platform-smoke.md#alternate-native-transports), run and inspect that target-local suite separately alongside the remaining release checks. The default composition still requires macOS/Ubuntu; alternate evidence must not be labeled a passing Crabbox matrix.
82
107
 
83
108
  `npm publish` runs npm’s `prepublishOnly` script from `package.json`, which executes the same `npm run verify -- release` gate and then `npm pack --dry-run`. That concatenated gate is everything in the default `npm run verify` step (generated playbook drift, clean `dist/` build, TypeScript, the unit/fake suite, generated command-reference blocks, and live upstream command-reference sampling against the targeted `agent-browser` on `PATH`), the configured-source lifecycle harness, the packaged Pi smoke in `package-pi`, and the release-blocking Crabbox platform matrix. Using `npm publish --ignore-scripts` skips that contract intentionally.
84
109
 
@@ -110,7 +135,7 @@ The Crabbox gate is only green when suite assertions and artifact manifests unde
110
135
 
111
136
  The deterministic dogfood mode clean-builds the compiled package, uses the extension harness and real `agent-browser` on `PATH` against a deterministic loopback HTTP fixture, then verifies persistent browser code aggregation, flat advanced QA/actions, native batch, screenshot artifact verification, and explicit session close. Use `npm run verify -- dogfood --keep-artifacts` or `--artifact-dir <path>` only while debugging, then delete retained screenshots. This smoke complements, but does not replace, human-readable interactive transcript evidence.
112
137
 
113
- Every release also requires interactive `tmux`-driven Pi dogfood with the native `agent_browser` tool against real sites. For extension-focused release smokes, use `pi --approve --no-extensions --no-skills -e .` from the trusted checkout before publish so auto-loaded dogfood/QA skills cannot replace the bounded smoke workflow; omit `--approve` only when the smoke is explicitly testing Pi's Project Trust prompt. Run separate skill-enabled dogfood only when validating skill routing or report-generation behavior. Drive prompts with `tmux send-keys`, exercise at least one simple static site and one real documentation/product site, include advanced QA, code, or native batch when those surfaces changed, close every opened browser session, remove screenshots/temp artifacts, and record the outcome in the release notes or support-matrix evidence. Do not paste raw multi-line prompts into a tmux Pi pane: plain newlines submit separate queued user messages. For scripted smoke driving, collapse prompt files to one line before sending (`PROMPT=$(tr '\n' ' ' < /tmp/smoke-prompt.md); tmux send-keys -t "$SESSION":0.0 -l "$PROMPT"; tmux send-keys -t "$SESSION":0.0 Enter`). For manual multi-line editing, use Pi's external editor shortcut (`Ctrl+G`) or configure tmux extended keys so Pi can receive `Shift+Enter` for newlines; see the installed Pi `docs/tmux.md` guidance. Automated localhost, fake-upstream, and deterministic dogfood gates do not replace this human-readable live-site transcript evidence. When code changes, add a persisted-session `agent_browser_code` pass that aggregates at least two real pages, exercises a conditional branch, compares selected output with an ordinary-call baseline, verifies selected screenshot bytes reach the model, and checks browser/auth continuity on a later direct/code call with fresh JS globals. Review ordered custom transition entries and interrupted/replayed state, not only the outer result. Exercise handled failures, timeout/cancellation, whole-cell ordering, and child reaping; close only test-owned browsers afterward and retain Pi transcripts. Never use `--no-session` for code dogfood. When `agent_browser_web_search` or package config changed, add one key-free smoke proving the optional tool is absent without config, one fake/unit-backed smoke in the default suite, and one opt-in live Exa or Brave Search check with a real key while confirming the key does not appear in transcripts, stdout/stderr, config status, PR text, or artifacts. When `electron.*` surfaces, attached-session diagnostics, or `qa.attached` changed, add a local Electron pass against a disposable fixture app, never the operator's installed desktop apps such as Slack or Obsidian: wrapper launches open real app windows on the operator's desktop even with isolated profiles. Install the stock `electron` npm package into a temp directory (run its `install.js` if npm skipped the binary download) next to a minimal app whose hidden window (`new BrowserWindow({ show: false })`, plus `app.setActivationPolicy('prohibited')` and `app.dock?.hide()` on macOS) loads a known page so nothing appears on the operator's desktop, then run `electron.list` (discovery only) → `electron.launch` with `executablePath` set to that package's Electron binary and `appArgs` set to the fixture app directory (expect isolated profile behavior) → `snapshot -i` or `electron.probe` / `qa.attached` → `electron.cleanup` with the returned `launchId`, verifying status/mismatch guidance if you simulate a dead renderer or stale refs. Delete the fixture afterwards. For dense-dashboard stress coverage, use the [public Grafana stress checklist](#public-grafana-stress-checklist) below; it is a maintainer workflow, not bundled product skill or recipe runtime.
138
+ Releases that change the Pi agent runtime also require interactive `tmux`-driven Pi dogfood with the native `agent_browser` tool against real sites. For extension-focused release smokes, use `pi --approve --no-extensions --no-skills -e .` from the trusted checkout before publish so auto-loaded dogfood/QA skills cannot replace the bounded smoke workflow; omit `--approve` only when the smoke is explicitly testing Pi's Project Trust prompt. Run separate skill-enabled dogfood only when validating skill routing or report-generation behavior. Drive prompts with `tmux send-keys`, exercise at least one simple static site and one real documentation/product site, include advanced QA, code, or native batch when those surfaces changed, close every opened browser session, remove screenshots/temp artifacts, and record the outcome in the release notes or support-matrix evidence. Do not paste raw multi-line prompts into a tmux Pi pane: plain newlines submit separate queued user messages. For scripted smoke driving, collapse prompt files to one line before sending (`PROMPT=$(tr '\n' ' ' < /tmp/smoke-prompt.md); tmux send-keys -t "$SESSION":0.0 -l "$PROMPT"; tmux send-keys -t "$SESSION":0.0 Enter`). For manual multi-line editing, use Pi's external editor shortcut (`Ctrl+G`) or configure tmux extended keys so Pi can receive `Shift+Enter` for newlines; see the installed Pi `docs/tmux.md` guidance. Automated localhost, fake-upstream, and deterministic dogfood gates do not replace this human-readable live-site transcript evidence. When code changes, add a persisted-session `agent_browser_code` pass that aggregates at least two real pages, exercises a conditional branch, compares selected output with an ordinary-call baseline, verifies selected screenshot bytes reach the model, and checks browser/auth continuity on a later direct/code call with fresh JS globals. Review ordered custom transition entries and interrupted/replayed state, not only the outer result. Exercise handled failures, timeout/cancellation, whole-cell ordering, and child reaping; close only test-owned browsers afterward and retain Pi transcripts. Never use `--no-session` for code dogfood. When `agent_browser_web_search` or package config changed, add one key-free smoke proving the optional tool is absent without config, one fake/unit-backed smoke in the default suite, and one opt-in live Exa or Brave Search check with a real key while confirming the key does not appear in transcripts, stdout/stderr, config status, PR text, or artifacts. When `electron.*` surfaces, attached-session diagnostics, or `qa.attached` changed, add a local Electron pass against a disposable fixture app, never the operator's installed desktop apps such as Slack or Obsidian: wrapper launches open real app windows on the operator's desktop even with isolated profiles. Install the stock `electron` npm package into a temp directory (run its `install.js` if npm skipped the binary download) next to a minimal app whose hidden window (`new BrowserWindow({ show: false })`, plus `app.setActivationPolicy('prohibited')` and `app.dock?.hide()` on macOS) loads a known page so nothing appears on the operator's desktop, then run `electron.list` (discovery only) → `electron.launch` with `executablePath` set to that package's Electron binary and `appArgs` set to the fixture app directory (expect isolated profile behavior) → `snapshot -i` or `electron.probe` / `qa.attached` → `electron.cleanup` with the returned `launchId`, verifying status/mismatch guidance if you simulate a dead renderer or stale refs. Delete the fixture afterwards. For dense-dashboard stress coverage, use the [public Grafana stress checklist](#public-grafana-stress-checklist) below; it is a maintainer workflow, not bundled product skill or recipe runtime.
114
139
 
115
140
  When reviewing saved session JSONL after a failed smoke or QA reclassification, expect browser tool rows to carry `isError: true` whenever `details.resultCategory` is `failure`. The model-visible observation must also report failure. Canonical JSON stays parseable and unchanged. Final public results return `isError` directly, with a prose failure notice outside explicit JSON, so Pi's transcript matches the wrapper contract ([`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details)). Preserve a normal Pi session directory for those checks; avoiding `--no-session` keeps this evidence intact ([`AGENTS.md`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/AGENTS.md) preferred validation workflow).
116
141
 
@@ -252,7 +277,7 @@ Run the automated harness for deterministic configured-source lifecycle regressi
252
277
  npm run verify -- lifecycle
253
278
  ```
254
279
 
255
- The harness creates an isolated `PI_CODING_AGENT_DIR`, writes settings with exactly one temporary configured package source, runs `pi` in `tmux` with `--approve`, default model **`zai/glm-5.2`**, and a deterministic `--session-id`, puts a deterministic fake `agent-browser` first on `PATH`, starts an explicit `sessionMode: "fresh"` managed browser, drives `/reload`, closes Pi, and relaunches with the same exact session id instead of typing `/resume`. It also asserts the JSONL session header id, same-page managed-session continuity, compiled JS code pickup after full process relaunch, persisted spill reachability, and native returned `isError` and JSON-preservation semantics for a QA reclassification. Per-step tmux waits default to **180000 ms** (three minutes) in [`scripts/verify-lifecycle.mjs`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/scripts/verify-lifecycle.mjs) (`DEFAULT_TIMEOUT_MS`); override with `--timeout-ms <ms>` when slower models or cold starts need more headroom. Override the model when needed:
280
+ The harness creates an isolated `PI_CODING_AGENT_DIR`, writes settings with exactly one temporary configured package source, runs `pi` on its own `tmux` server with `--approve`, default model **`zai/glm-5.2`**, and a deterministic `--session-id`, so Pi inherits the verify process environment (the isolated agent directory stores no credentials; export the selected model's provider credentials before running the harness), puts a deterministic fake `agent-browser` first on `PATH`, starts an explicit `sessionMode: "fresh"` managed browser, drives `/reload`, closes Pi, and relaunches with the same exact session id instead of typing `/resume`. It also asserts the JSONL session header id, same-page managed-session continuity, compiled JS code pickup after full process relaunch, persisted spill reachability, and native returned `isError` and JSON-preservation semantics for a QA reclassification. Per-step tmux waits default to **180000 ms** (three minutes) in [`scripts/verify-lifecycle.mjs`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/scripts/verify-lifecycle.mjs) (`DEFAULT_TIMEOUT_MS`); override with `--timeout-ms <ms>` when slower models or cold starts need more headroom. Override the model when needed:
256
281
 
257
282
  ```bash
258
283
  npm run verify -- lifecycle --model openai-codex/gpt-5.5:minimal
@@ -279,7 +304,7 @@ These show up often in cloud dev boxes and scripted smokes; they are maintainer
279
304
  | **`pi -p` / print mode** | Non-interactive `pi -p` may hang or emit no stdout for long real-browser smokes without a TTY. | Use **tmux**-driven interactive `pi` for release evidence and checkout smokes; reserve `-p` for short, non-browser checks. |
280
305
  | **Real-browser cleanup** | `real-upstream`, Sauce Demo, and live-site runs can leave defunct Chrome/`agent-browser` children if a session aborts mid-flow. | Close only test-owned browsers via `agent_browser` / `agent-browser` `close`, stop this run's tmux sessions, and remove its disposable screenshots/HARs. Preserve unrelated resources and retained evidence. |
281
306
  | **Automated prompt driving** | Grepping tmux pane text for words that also appear in the **user** prompt (`PASS`, `FAIL`, `checkout overview`, `Smoke result:`) can false-complete before the agent finishes. | Wait for pane idle (no `Working…`), `agent_browser close` / `Artifact lifecycle`, or JSONL tool results—not instruction phrases copied from the prompt. |
282
- | **Lifecycle verify flags** | `npm run verify -- lifecycle --model` or `--timeout-ms` without the next argv token fails fast with a usage error—the `project.mjs` facade validates passthrough the same way as `scripts/verify-lifecycle.mjs`. | Always pair flags with values (`--model openai-codex/gpt-5.5:minimal`, `--timeout-ms 600000`) or omit `--model` / `--timeout-ms` to keep the harness defaults (`zai/glm-5.2`, **180000 ms** per-step waits). |
307
+ | **Lifecycle verify flags** | `npm run verify -- lifecycle` or `release` exits with a usage error before any step runs when `--model` or `--timeout-ms` lacks a value or the timeout is not a positive integer; the facade uses `scripts/verify-lifecycle.mjs`'s parser. | Always pair flags with values (`--model openai-codex/gpt-5.5:minimal`, `--timeout-ms 600000`) or omit `--model` / `--timeout-ms` to keep the harness defaults (`zai/glm-5.2`, **180000 ms** per-step waits). |
283
308
 
284
309
  Manual validation remains useful for release confidence and installed-package checks:
285
310
 
@@ -290,7 +315,7 @@ Manual validation remains useful for release confidence and installed-package ch
290
315
 
291
316
  ### Real upstream contract validation
292
317
 
293
- The default `npm test` and `npm run verify` paths use deterministic tests and fake binaries in two stages: `tsx --test "test/**/!(*.serial).test.ts"` at Node's default file concurrency, then `tsx --test --test-concurrency=1 "test/**/*.serial.test.ts"` for strict timing budgets and shared policy-collector fixtures. The browser harness isolates each process's socket root; build/pack fixtures use disposable source trees so parallel consumers retain immutable checkout `dist/`. For a focused single-file rerun, use `npx tsx --test test/<file>.test.ts`; `npm test -- test/<file>.test.ts` still runs the package script's full glob. When a change touches upstream command planning, result presentation, managed-session behavior, or the canonical capability baseline, also run the opt-in real-upstream contract suite:
318
+ The default `npm test` and `npm run verify` paths use deterministic tests and fake binaries in two stages: `tsx --test "test/**/!(*.serial).test.ts"` at Node's default file concurrency, then `tsx --test --test-concurrency=1 "test/**/*.serial.test.ts"` for strict timing budgets and shared policy-collector fixtures. The browser harness isolates each process's socket root; build/pack fixtures use disposable source trees so parallel consumers retain immutable checkout `dist/`. For a focused single-file rerun, use `npx tsx --test test/<file>.test.ts`; `npm test` rejects extra paths and options so the complete gate cannot silently become a filtered run. When a change touches upstream command planning, result presentation, managed-session behavior, or the canonical capability baseline, also run the opt-in real-upstream contract suite:
294
319
 
295
320
  ```bash
296
321
  npm run verify -- real-upstream
@@ -300,9 +325,9 @@ That npm script sets `PI_AGENT_BROWSER_REAL_UPSTREAM=1`, runs the sessionless pl
300
325
 
301
326
  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:
302
327
 
303
- - **Inspection and skills (stateless JSON):** `--version`, `--help`, `snapshot --help`, `skills list`, `skills get … --full` (including `webmcp-gen` on the 0.38.1 target), `skills path …` (no managed `sessionName` / `usedImplicitSession`).
328
+ - **Inspection and skills (stateless JSON):** `--version`, `--help`, `snapshot --help`, `skills list`, `skills get … --full` (including `webmcp-gen` on the 0.41.0 target), `skills path …` (no managed `sessionName` / `usedImplicitSession`).
304
329
  - **Native 0.38 observation/recording:** full/unchanged delta snapshots, persistent refs, partial batch ref follow-ups, conditional screenshot suppression, sticky pointer mode and timed mouse movement, cursor recording and verified contact-sheet output. These options are skipped when explicitly validating the older stable floor.
305
- - **WebMCP target contract:** on the 0.38.1 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.
330
+ - **WebMCP target contract:** on the 0.41.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.
306
331
  - **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.
307
332
  - **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.
308
333
  - **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`.
@@ -310,7 +335,7 @@ This suite requires the installed stable `agent-browser --version` to meet the m
310
335
  - **Confirmation continuity:** the focused `contract suite matches confirmation launch policy surviving native nextActions` case follows exact confirm/deny actions without policy argv, checks a useful compound audit across resume followed immediately by title/body reads without a repairing URL getter, retains the native daemon PID on bare getters, and preserves an active recording and destination sentinel after denying restart. The nested recording-restart/navigation subcase requires the pinned native recording-policy patch; stock 0.38.1 skips only that subcase. With that patched binary first on `PATH`, run `PI_AGENT_BROWSER_REAL_UPSTREAM=1 PI_AGENT_BROWSER_NATIVE_COMPOUND_POLICY=1 node --import tsx --test --test-force-exit --test-name-pattern 'confirmation launch policy' test/agent-browser.real-upstream-contract.test.ts`. Both variables are test selectors, not runtime configuration. Focused read-confirmation, cold-resume, session-page-state and managed-daemon-policy owners additionally cover exact generic/native-read provenance, forged/foreign controls, completed click/tab and failed-inner action reconciliation, confirmed-close replay, definite unestablished policy requests and pending cold helper exposure. Qualify actual SDK resume plus immediate title/body follow-ups without a repairing getter; helpers must not replace the original native pending slot.
311
336
  - **Cold first-read continuity:** the focused `contract suite matches cold URL reopen after quit` case starts an explicit `sessionMode: "fresh"` managed browser, 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.
312
337
  - **Failure shape:** `react tree` on a page opened with `--enable react-devtools` but without a React app (expects a clear missing-renderer error with session-bound `details`).
313
- - **Async download:** `open` on the `/download` fixture, anchor-triggered export, then `wait --download <path>` metadata and wrapper artifact reporting for the requested path.
338
+ - **Async download:** `open` on the `/download` fixture, anchor-triggered export, then `wait --download <path>` with version-specific assertions: native 0.39.4+ must save the exact bytes with verified wrapper artifacts, while supported 0.35.0–0.39.3 natives only report the requested path and must fail closed as `artifact-missing`. The batch operand owner also covers `--download` / `-d` after interleaved timeout flags. Missing-file failures remain covered independently by the artifact-presentation owner.
314
339
 
315
340
  The default unit suite also runs `agentBrowserExtension passes through core command coverage fallback matrix` in [`test/agent-browser.extension-passthrough-native-commands.test.ts`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/test/agent-browser.extension-passthrough-native-commands.test.ts): a fake upstream records argv so explicit `--session connector connect 9222`, plus `download` with a selector and path, `get url`, `snapshot --compact`, and `tab new` / `tab t1` / `tab close` on implicit managed sessions, still prove `--json` and session ordering without a browser. A second fake-upstream matrix in [`test/agent-browser.extension-passthrough-debug-providers.test.ts`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/test/agent-browser.extension-passthrough-debug-providers.test.ts) (`agentBrowserExtension passes through non-core network debug diff stream dashboard and chat families`) pins representative `network`, `diff`, `trace` / `profiler` / `record`, `console` / `errors` / `highlight` / `inspect` / `clipboard`, `stream`, `dashboard`, and `chat` JSON shapes plus redacted `details.data` and argv echoes without a browser. Its `agentBrowserExtension passes through provider workflows` matrix asserts provider `open` argv shapes still receive `--json` plus implicit `--session` and provider credential env vars are forwarded into the fake upstream log, while `agentBrowserExtension keeps skills inspection flows stateless and useful` in the native-commands file keeps read-only `skills get …` stateless (no managed session fields). Extend those matrices when adding passthrough coverage that should stay out of the slow real-upstream loop.
316
341
 
@@ -332,13 +357,13 @@ node --test test/agent-browser.native-lifecycle.test.mjs
332
357
 
333
358
  #### Routine GitHub PR checks
334
359
 
335
- [`.github/workflows/pi-compatibility.yml`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/.github/workflows/pi-compatibility.yml) runs on PRs to `main`, manual dispatch, and release workflow calls. It resolves the latest stable official Pi version and latest maintained fork `main` commit once, or accepts those exact identities from the enclosing release run. Independent required Ubuntu jobs qualify each selected host's complete installed dependency graph on Node 24.21.0. Each runs `check:compat` once: host identity, typecheck, the full offline suite, and packed SDK/CLI loading. A parallel macOS Node 24.21.0 job typechecks and checks the packed Pi load against the same latest official graph without repeating the full suite. The host selector uses the immutable, reviewed `fitchmultz/.github` automation scripts; that automation pin is not a Pi qualification target. Locked development snapshots and the support floor are not validation lanes, and neither host is skipped based on a floor comparison.
360
+ [`.github/workflows/pi-compatibility.yml`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/.github/workflows/pi-compatibility.yml) runs on PRs to `main`, manual dispatch, and release workflow calls. It resolves the latest stable official Pi version and latest maintained fork `main` commit once, or accepts those exact identities from the enclosing release run. Independent required Ubuntu jobs qualify each selected host's complete installed dependency graph on Node 24.21.0. Each runs `check:compat` once: host identity, typecheck, the full offline suite, and packed SDK/CLI loading. A parallel macOS Node 24.21.0 job typechecks and checks the packed Pi load against the same latest official graph without repeating the full suite. One job-level nonblocking `windows-latest` lane builds/imports the compiled extension and runs the existing process-transport test on the resolved official host. It has a 15-minute job bound and a 10-minute smoke-step bound; there is no checker build or full contract/consumer campaign. A single Ubuntu fork-package build still supplies verified artifacts to required Linux and explicitly selected deep Windows qualification. The host selector uses the immutable, reviewed `fitchmultz/.github` automation scripts; that automation pin is not a Pi qualification target. Locked development snapshots and the support floor are not validation lanes, and neither host is skipped based on a floor comparison.
336
361
 
337
- For native startup and consumer qualification, dispatch Pi compatibility with `native-qualification=true`. This runs the repository's entry in the pinned shared `fleet.json`, instead of repeating the routine package jobs: official/fork hosts on latest Node 24.x across `ubuntu-latest`, `macos-latest`, and diagnostic `windows-latest`. `official-version` and `fork-ref` optionally select exact hosts; blank values resolve current stable/main once. The source is the dispatch commit. Required Linux/macOS lanes run the full contracts, including all three fresh startup samples below 250 ms and actual Git/npm SDK/CLI consumers; Windows remains diagnostic under the owner waiver.
362
+ For native startup and consumer qualification, dispatch Pi compatibility with `native-qualification=true`. This runs the repository's entry in the pinned shared `fleet.json` for official/fork hosts on latest Node 24.x across `ubuntu-latest` and `macos-latest`, instead of repeating the routine package jobs. `waived-platforms: false` excludes the shared workflow's Windows diagnostics. To select this repository's separate best-effort full Windows matrix, explicitly set `windows-qualification=true` on manual dispatch; otherwise deep Windows lanes are not run. `official-version` and `fork-ref` optionally select exact hosts; blank values resolve current stable/main once. The source is the dispatch commit. The native qualification lanes retain full contracts and actual Git/npm SDK/CLI consumers; the separately labeled routine Windows smoke does not. On-demand full Windows enables Git long paths on its disposable runner so isolated checker-source/submodule checkouts are not cut off at MAX_PATH. Repository attributes keep reviewed checker patches in canonical LF form even with native Git CRLF conversion; patch application is not relaxed. It additionally requires the pinned native process-identity environment self-check before contract dispatch, preserving its existing PID/start-time and timing assertions.
338
363
 
339
- [`.github/workflows/native-lifecycle.yml`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/.github/workflows/native-lifecycle.yml) runs the separate **Native lifecycle Linux** gate through [`scripts/ci-native-lifecycle.sh`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/scripts/ci-native-lifecycle.sh). It independently checks out the PR head, selects the latest official graph using its once-resolved version (or the exact version supplied by the enclosing release run), builds the compiled extension on Node **24.21.0**, and runs portable native SDK lifecycle checks against isolated loopback browser fixtures. It replaces the fork-only checkpoint gate and requires all 12 checks to pass with no failure, cancellation or skip. It does not repeat the official full suite. Sources use a private `/tmp` root, sanitized environment, non-root execution, and a loopback-only network namespace. Only official host metadata preparation receives the job's read-only GitHub token; setup unsets it before extension build and browser installation. Lifecycle verification receives no token and uses no personal profile, personal credentials, or model calls.
364
+ [`.github/workflows/native-lifecycle.yml`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/.github/workflows/native-lifecycle.yml) runs the separate **Native lifecycle Linux** gate through [`scripts/ci-native-lifecycle.sh`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/scripts/ci-native-lifecycle.sh). It independently checks out the PR head, selects the latest official graph using its once-resolved version (or the exact version supplied by the enclosing release run), builds the compiled extension on Node **24.21.0**, and runs portable native SDK lifecycle checks against isolated loopback browser fixtures. It replaces the fork-only checkpoint gate and requires all 13 checks to pass with no failure, cancellation or skip. It does not repeat the official full suite. Sources use a private `/tmp` root, sanitized environment, non-root execution, and a loopback-only network namespace. Only official host metadata preparation receives the job's read-only GitHub token; setup unsets it before extension build and browser installation. Lifecycle verification receives no token and uses no personal profile, personal credentials, or model calls.
340
365
 
341
- Routine checks write setup, provenance, command-reference, and native TAP results to the job log and upload short-lived evidence: `official-host`, `fork-host`, and `macos-host` contain exact selected host receipts; `native-lifecycle` contains the host receipt, native TAP results and lifecycle transcripts. Each routine artifact is retained for three days, with no persistent caches. Native manual qualification uses the shared workflow's npm and fork-package caches; its fork-host artifact is retained for seven days and per-lane qualification evidence for fourteen days. The checks cover their exact source, host, and synthetic browser paths; they do not replace release/manual-publication gates, real-site authentication, or full personal-workspace restore qualification.
366
+ Routine checks write setup, provenance, command-reference, and native TAP results to the job log and upload short-lived evidence: `official-host`, `fork-host`, and `macos-host` contain exact selected host receipts; `native-lifecycle` contains the host receipt, native TAP results and lifecycle transcripts. Each routine Linux/macOS artifact is retained for three days, with no persistent caches. Windows smoke retains `windows-best-effort-smoke` for fourteen days with source/host/tool inputs, the selected host receipt when reached, and the complete smoke log. A failed or incomplete smoke is not full Windows qualification. Explicit deep Windows retains `windows-qualification-official` and `windows-qualification-fork` for fourteen days, including exact input receipts, environment TAP, complete qualification logs, and the shared qualifier's provenance, package hashes and SDK/CLI probes when reached. Uploads run even after failure. The Windows console retains the final 1,000 qualification lines and, on failure, separately prints all failed TAP test names plus the first 1,600 lines of their diagnostics, with an explicit truncation notice when needed; complete diagnostics remain in `qualification.log`. An absent qualification receipt or skipped contract is not a pass. The resolved fork-package artifact is retained for seven days. Native manual qualification uses the shared workflow's npm and fork-package caches; its fork-host artifact is retained for seven days and per-lane qualification evidence for fourteen days. The checks cover their exact source, host, and synthetic browser paths; they do not replace release/manual-publication gates, real-site authentication, or full personal-workspace restore qualification.
342
367
 
343
368
  ### Native Linux socket-root regression
344
369
 
@@ -359,7 +384,7 @@ For a root-check change, run the identical final test against both the pre-fix a
359
384
  - **Missing or extra `details` / `data` keys:** Update `test/fixtures/agent-browser-real-output-shapes.json` in the same change as the wrapper or presentation code that shifts those keys.
360
385
  - **Timeouts:** The broad matrix has a 180-second bound; the focused cold-reopen, click-mutation, and plugin cases each have a 60-second bound. Repeated timeouts usually mean a hung browser, blocked loopback, or an environment preventing headful/headless launch—check upstream logs and local security tooling before loosening timeouts.
361
386
 
362
- The upstream `agent-browser` `wait --download <path>` saveAs persistence limitation is tracked at [vercel-labs/agent-browser#1300](https://github.com/vercel-labs/agent-browser/issues/1300); until it is fixed, release validation must treat `details.savedFilePath` as upstream-reported metadata and use `details.artifacts[].exists` as the filesystem truth (the contract asserts the requested path is absent on disk while upstream still reports success). If the suite fails because JSON/detail keys drifted, update the wrapper behavior or refresh `test/fixtures/agent-browser-real-output-shapes.json` together with the presentation work that consumes those shapes.
387
+ Native 0.39.4 fixes already-completed downloads and requested-path persistence ([upstream change](https://github.com/vercel-labs/agent-browser/releases/tag/v0.39.4)); the recommended 0.41.0 contract requires the fixture's actual bytes at the requested destination and verified wrapper artifacts. Older supported natives (0.35.0–0.39.3) report the requested path without moving the file, so the same contract requires the wrapper's fail-closed `artifact-missing` result there. Native only moves downloads from a browser it launched, not attached/remote CDP paths. `details.savedFilePath` alone remains metadata: require `details.artifactVerification` and `details.artifacts[].exists`, and retain the artifact-presentation tests that fail reported-but-missing outputs. This fixture refresh is not a wrapper runtime download fix. If the suite fails because JSON/detail keys drifted, update the wrapper behavior or refresh `test/fixtures/agent-browser-real-output-shapes.json` together with the presentation work that consumes those shapes.
363
388
 
364
389
  Example smoke prompt:
365
390
 
@@ -410,7 +435,7 @@ Before publishing:
410
435
  - run `npm run verify -- real-upstream` for upstream runtime, result-presentation, or managed-session changes
411
436
  - confirm both local-checkout modes still work for pre-release validation: isolated `pi --approve --no-extensions -e .` smoke testing for general trusted checkout loading (add `--no-skills` for extension-focused bounded smokes; omit `--approve` only to test the trust prompt) and configured-source lifecycle validation
412
437
  - complete interactive `tmux` live-site extension smoke with `pi --approve --no-extensions --no-skills -e .` and the native `agent_browser` tool (at least one simple static site and one real documentation/product site; include advanced QA, code, or native batch when those surfaces changed; use the [public Grafana stress checklist](#public-grafana-stress-checklist) when dashboard/diagnostic/artifact behavior changed; close sessions and remove screenshots/temp artifacts; record evidence). Run separate skill-enabled dogfood only when validating skill routing/report-generation behavior—see [Pre-release checks](#pre-release-checks); automated gates are not a substitute
413
- - satisfy the approved release checks and current owner waivers; record individual platform evidence and never label a Windows-inclusive composition passed when Windows was waived
438
+ - satisfy the approved release checks and current owner waivers; record individual platform evidence and never label best-effort, failed, or not-run Windows evidence passed from the required non-Windows aggregate
414
439
  - run `npm run verify -- lifecycle` for configured-source `/reload`, exact `--session-id` relaunch, managed-session continuity, persisted-spill, and Pi failure-patch regression coverage (required before publish; see [Pre-release checks](#pre-release-checks))
415
440
  - confirm [`SUPPORT_MATRIX.md`](SUPPORT_MATRIX.md) still maps every current baseline inventory section to docs, runtime handling, tests, and validation status
416
441
  - manually exercise real-browser `/reload` and full restart plus exact `--session-id` relaunch or `/resume` continuity when release risk warrants browser-level confidence beyond the fake upstream harness
@@ -13,6 +13,12 @@ Related docs:
13
13
 
14
14
  Define the product requirements and constraints for `pi-agent-browser-native`.
15
15
 
16
+ ## Runtime requirements
17
+
18
+ - Node.js 24.21.0 or newer.
19
+ - Pi 1.0.0 or newer.
20
+ - A separate stable `agent-browser` installation, version 0.35.0 or newer, available on `PATH`.
21
+
16
22
  ## Product requirements
17
23
 
18
24
  ### Dependency model
@@ -14,7 +14,7 @@ A saved URL or map cannot prove the native browser survived. Reuse checks native
14
14
 
15
15
  ## Reading and retention
16
16
 
17
- Replay locates the journal through Pi's public session file, UUID and selected leaf. It captures that leaf before asynchronous reads and uses the same boundary for file and public native ancestry validation, so concurrent appends cannot change the branch being replayed. It token-validates complete newline-terminated records with unpacked discarded strings, projects envelopes, follows ancestry, and reads only winning snapshot bodies. An incomplete live tail remains uncommitted. Public `getEntry()` supplies structural ancestry checks on both supported hosts. Capture-local admission validates ancestry through the root, then reuses that append-only prefix after indexed endpoint identity/parent checks. New suffixes still reject missing/cyclic ancestry and unrelated branches; session/generation changes invalidate admission. Behind-host mutation of an old ancestor without native reseed/generation change is outside this append-only contract. Durable replay/append proofs remain independent: prefix reuse does not replace publication receipts or trust an unpublished selected leaf. No writable manager or private core storage is used.
17
+ Replay locates the journal through Pi's public session file, UUID and selected leaf. It captures that leaf before asynchronous reads and uses the same boundary for file and public native ancestry validation, so concurrent appends cannot change the branch being replayed. It validates complete newline-terminated records. A record up to 1 MiB with nesting within 1024 levels and at most 64 Ki structural bytes (`{`, `[`, `,` or `:` outside strings) uses native JSON, which briefly holds that record's text and parsed value, a few MiB at most. Larger or denser records and any native rejection use the token projector with unpacked discarded strings, fed in the same 64 KiB chunks as file reads, so both paths accept the same records and report the same first error. A cold restore frames and validates the whole journal. Subsequent restores on the same native manager retain only complete-record structural metadata: an unchanged file reuses that index, and an append scans from the last complete record, including any previously incomplete tail. Locator/header-object changes, rotation, truncation, same-size timestamp changes and failed reads or replay discard the index and use the full validating scanner. The index follows Pi's documented append-only entry contract; native reseeding replaces its header object even when the UUID stays the same. External prefix rewrites must be reopened through Pi rather than disguised as appends to its live journal. This is not an adversarial file-integrity guarantee. Each restore still projects selected envelopes, follows ancestry and rereads winning snapshot bodies; it never caches refs or browser outcomes. An incomplete live tail remains uncommitted. Public `getEntry()` supplies structural ancestry checks on both supported hosts. Capture-local admission validates ancestry through the root, then reuses that append-only prefix after indexed endpoint identity/parent checks. New suffixes still reject missing/cyclic ancestry and unrelated branches; session/generation changes invalidate admission. Behind-host mutation of an old ancestor without native reseed/generation change is outside this append-only contract. Durable replay/append proofs remain independent: prefix reuse does not replace publication receipts or trust an unpublished selected leaf. No writable manager or private core storage is used.
18
18
 
19
19
  Official Pi 1.0.0 eagerly loads its own native journal before extension startup. This extension reduces browser write duplication and bounds extension recovery on that host; complete heap-independent host loading requires adoption of the native core repair. A caller-requested individual snapshot/result still must fit its consumer's memory. This is not an unlimited model-context or single-value API.
20
20
 
@@ -57,9 +57,9 @@ Select the converted locator explicitly through the native session/worker owner.
57
57
 
58
58
  ## Verification
59
59
 
60
- Focused storage tests exercise incident-sized refs, small-event growth, begin/finish append faults with actual dispatch counts, interruption, branch projections and native generation replacement. Existing tab/ref, confirmation, recording, artifact and lifecycle suites retain their behavior checks.
60
+ Focused storage tests exercise incident-sized refs, small-event growth, a dense record's per-record heap reserve under a capped heap, begin/finish append faults with actual dispatch counts, interruption, branch projections and native generation replacement. Existing tab/ref, confirmation, recording, artifact and lifecycle suites retain their behavior checks.
61
61
 
62
- After `npm run build`, the opt-in model-free proof runs a journal above 1 GiB, including an ignored individual string above Node's string ceiling, repeated legacy maps, and 4,000 distinct session identities, through conversion and selected replay under a constrained V8 heap:
62
+ After `npm run build`, the opt-in model-free proof runs a journal above 1 GiB, including an ignored individual string above Node's string ceiling, repeated legacy maps, dense records at the 1 MiB native-parse boundary, and 4,000 distinct session identities, through conversion and selected replay under a constrained V8 heap:
63
63
 
64
64
  ```sh
65
65
  node --max-old-space-size=128 test/helpers/large-browser-journal.mjs