pi-agent-browser-native 0.8.3 → 0.9.1

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 (48) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +12 -11
  3. package/dist/extensions/agent-browser/index.js +96 -320
  4. package/dist/extensions/agent-browser/lib/argv-descriptor.js +1 -1
  5. package/dist/extensions/agent-browser/lib/argv-grammar.js +3 -3
  6. package/dist/extensions/agent-browser/lib/browser-journal.js +33 -12
  7. package/dist/extensions/agent-browser/lib/browser-transcript.js +1 -1
  8. package/dist/extensions/agent-browser/lib/command-taxonomy.js +0 -3
  9. package/dist/extensions/agent-browser/lib/config-policy.js +0 -13
  10. package/dist/extensions/agent-browser/lib/config.js +3 -48
  11. package/dist/extensions/agent-browser/lib/electron/launch.js +4 -4
  12. package/dist/extensions/agent-browser/lib/execution-cwd.js +0 -16
  13. package/dist/extensions/agent-browser/lib/input-modes/params.js +2 -3
  14. package/dist/extensions/agent-browser/lib/input-modes/script.js +28 -6
  15. package/dist/extensions/agent-browser/lib/input-modes/types.js +2 -2
  16. package/dist/extensions/agent-browser/lib/managed-session-restore.js +1 -4
  17. package/dist/extensions/agent-browser/lib/native-output.js +46 -0
  18. package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +0 -9
  19. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-merge.js +22 -0
  20. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +1 -1
  21. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +2 -2
  22. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +1 -1
  23. package/dist/extensions/agent-browser/lib/orchestration/execution-queue.js +86 -0
  24. package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +31 -17
  25. package/dist/extensions/agent-browser/lib/process.js +0 -3
  26. package/dist/extensions/agent-browser/lib/prompt-policy.js +16 -12
  27. package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +2 -2
  28. package/dist/extensions/agent-browser/lib/results/network-routes.js +1 -1
  29. package/dist/extensions/agent-browser/lib/results/network.js +1 -1
  30. package/dist/extensions/agent-browser/lib/results/presentation/batch.js +1 -1
  31. package/dist/extensions/agent-browser/lib/results/presentation/content.js +4 -0
  32. package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +1 -1
  33. package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +15 -8
  34. package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +2 -2
  35. package/dist/extensions/agent-browser/lib/results/selector-recovery.js +1 -1
  36. package/dist/extensions/agent-browser/lib/runtime.js +4 -2
  37. package/dist/extensions/agent-browser/lib/session-page-state.js +1 -1
  38. package/dist/extensions/agent-browser/lib/tool-surface.js +39 -11
  39. package/dist/extensions/agent-browser/lib/web-search.js +100 -79
  40. package/docs/ARCHITECTURE.md +17 -19
  41. package/docs/COMMAND_REFERENCE.md +6 -2
  42. package/docs/RELEASE.md +26 -20
  43. package/docs/REQUIREMENTS.md +5 -5
  44. package/docs/SESSION_STORAGE.md +4 -4
  45. package/docs/SUPPORT_MATRIX.md +15 -13
  46. package/docs/TOOL_CONTRACT.md +12 -8
  47. package/package.json +6 -6
  48. package/scripts/doctor.mjs +12 -4
package/docs/RELEASE.md CHANGED
@@ -21,10 +21,16 @@ Provide one concrete maintainer workflow for validating repo state, package cont
21
21
 
22
22
  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).
23
23
 
24
- Linux/macOS, declared Node floors, official/fork host and consumer-artifact checks, and Native checkpoint Linux remain required. All three final reviewers (reviewer-gpt, reviewer-ponytail, reviewer-claude) must approve before merge, release or activation. 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.
24
+ Linux/macOS, declared Node floors, official/fork host and consumer-artifact checks, and Native lifecycle Linux remain required. All three final reviewers (reviewer-gpt, reviewer-ponytail, reviewer-claude) must approve before merge, release or activation. 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.
25
25
 
26
26
  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.
27
27
 
28
+ ## Pi 1.0 upgrade and qualification
29
+
30
+ 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.
31
+
32
+ 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.
33
+
28
34
  ## 0.7 upgrade and rollback
29
35
 
30
36
  The 0.7 tool contract is breaking: direct argv stays compact, `script` moves to `agent_browser_code.code` with a persistent browser, the job DSL is replaced by native batch/code, and five advanced tools use flat schemas after native activation. Publish with the [migration map](TOOL_CONTRACT.md#07-migration), not a parallel legacy public route. Preserve saved auth, explicit files, and Pi journals. Existing strict pre-0.7 isolated-script leases are only read for cleanup.
@@ -35,9 +41,9 @@ Rollback is package-level: select the exact previously installed 0.6 release wit
35
41
 
36
42
  ### Changed-path qualification
37
43
 
38
- The minimum Pi runtime is 0.87.0, matching the native APIs used by the new tool contract. Wildcard peers remain host-owned dependency declarations, not support for older runtimes.
44
+ The minimum Pi runtime is 1.0.0, matching the native APIs used by the new tool contract. Wildcard peers remain host-owned dependency declarations, not support for older runtimes.
39
45
 
40
- Qualify official Pi 0.87 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.
46
+ 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.
41
47
 
42
48
  Existing owner waivers remain authoritative. Windows qualification is waived; report diagnostic failures without claiming a pass or restarting waived repair work. Routine GitHub Actions now runs on PRs to `main` and manual dispatch, with no Windows CI job. These focused checks complement, rather than replace, the local release and publication gates.
43
49
 
@@ -67,7 +73,7 @@ npm run verify -- pre-pr
67
73
  `npm run verify -- release` runs:
68
74
 
69
75
  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`
70
- 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 Pi failure-patch behavior
76
+ 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
71
77
  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
72
78
  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`
73
79
 
@@ -105,9 +111,9 @@ The deterministic dogfood mode clean-builds the compiled package, uses the exten
105
111
 
106
112
  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: `electron.list` → `electron.launch` (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. 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.
107
113
 
108
- 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; Pi's error patch must not append prose to it. The extension applies that patch on the `tool_result` path 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).
114
+ 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).
109
115
 
110
- The configured-source lifecycle regression harness is required before release because it launches an interactive Pi 0.87.0+ process under `tmux` with `--approve` and validates `/reload`, full relaunch with the same exact `--session-id`, managed-session continuity, persisted artifacts, compiled-entrypoint pickup after process restart, and Pi failure-patch behavior. Branch-backed `session_tree` rehydration and cleanup ownership are validated by focused extension harness tests:
116
+ The configured-source lifecycle regression harness is required before release because it launches an interactive Pi 1.0.0+ process under `tmux` with `--approve` and validates `/reload`, full relaunch with the same exact `--session-id`, managed-session continuity, persisted artifacts, compiled-entrypoint pickup after process restart, and native returned-failure behavior. Branch-backed `session_tree` rehydration and cleanup ownership are validated by focused extension harness tests:
111
117
 
112
118
  ```bash
113
119
  npm run verify -- lifecycle
@@ -233,7 +239,7 @@ Before publishing, validate both local-checkout modes without mixing their assum
233
239
 
234
240
  For expanded-surface validation, the smoke prompt should cover native tool invocation rather than shelling out to `agent-browser`: `--version`, `--help`, `skills list`, `skills get core --full`, `open` with `sessionMode: "fresh"`, `snapshot -i`, `click`, flat `agent_browser_action` after enabling `action` (including unique accessible select and explicit session routing), `eval --stdin`, `batch` via stdin, `agent_browser_code`, advanced QA, and experimental source/network tools after loader activation, `screenshot <path>`, explicit `--session … open` plus `--session … close`, `network requests`, `console` / `errors`, `diff snapshot`, `stream status` plus `stream disable`, `dashboard start` plus `dashboard stop`, and `chat <message>` (credential failure is acceptable evidence of wrapper pass-through when `AI_GATEWAY_API_KEY` is intentionally unset). Clean up any opened browser session with `close`, remove temporary files, and kill the tmux session before ending validation.
235
241
 
236
- This checklist assumes a real `agent-browser` on `PATH`. It complements, but does not overlap, `npm run verify -- lifecycle`: that harness swaps in a fake upstream binary and focuses on `/reload`, exact `--session-id` relaunch, managed-session continuity, spill-path persistence, and Pi `tool_result` failure-patch semantics (`scripts/verify-lifecycle.mjs`), not the full command matrix above.
242
+ This checklist assumes a real `agent-browser` on `PATH`. It complements, but does not overlap, `npm run verify -- lifecycle`: that harness swaps in a fake upstream binary and focuses on `/reload`, exact `--session-id` relaunch, managed-session continuity, spill-path persistence, and native returned `isError` and JSON-preservation semantics (`scripts/verify-lifecycle.mjs`), not the full command matrix above.
237
243
 
238
244
  When a smoke or dogfood run fails after `sessionMode: "fresh"` (missing binary, timeout, upstream error, or **`qa`** preset reclassification), read `details.managedSessionOutcome` before assuming which managed session the next default `sessionMode: "auto"` call will follow; the same struct can appear without the extra `Managed session outcome: …` prose line on `"auto"` failures. Field-level semantics and append ordering relative to other diagnostic tails are documented in [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details) and the session-mode notes in [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md).
239
245
 
@@ -245,7 +251,7 @@ Run the automated harness for deterministic configured-source lifecycle regressi
245
251
  npm run verify -- lifecycle
246
252
  ```
247
253
 
248
- 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 real Pi `tool_result` failure-patch 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:
254
+ 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:
249
255
 
250
256
  ```bash
251
257
  npm run verify -- lifecycle --model openai-codex/gpt-5.5:minimal
@@ -268,7 +274,7 @@ These show up often in cloud dev boxes and scripted smokes; they are maintainer
268
274
  | Topic | What to watch for | Mitigation |
269
275
  | --- | --- | --- |
270
276
  | **Pi CLI vs repo devDependencies** | Global `pi` older than the minimum Pi runtime floor for the release can change TUI behavior, `/reload`, package installs, and tool routing during lifecycle or checkout smokes. | Run `npm run doctor` and align `pi` with the current audited baseline before release gates (`pi update` or install the matching version). The published peer range stays wildcard per Pi package docs, and the doctor enforces the minimum Pi runtime floor before package validation. |
271
- | **npm lockfile (`packageManager`)** | `package.json` pins **npm@12.1.0** for the Node 24.21.0 runtime baseline. Older npm versions can rewrite optional-platform metadata in `package-lock.json`; private registry proxies can also leak organization URLs into `resolved` entries. | Prefer `npx -y npm@12.1.0 install` when refreshing the lockfile; do not commit unrelated lockfile churn or WorkOS/private-registry URLs. |
277
+ | **npm lockfile (`packageManager`)** | `package.json` pins **npm@12.2.0** for the Node 24.21.0 runtime baseline. Older npm versions can rewrite optional-platform metadata in `package-lock.json`; private registry proxies can also leak organization URLs into `resolved` entries. | Prefer `npx -y npm@12.2.0 install` when refreshing the lockfile; do not commit unrelated lockfile churn or WorkOS/private-registry URLs. |
272
278
  | **`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. |
273
279
  | **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 via `agent_browser` / `agent-browser` `close`, kill stray tmux sessions, and remove temp screenshots/HARs under `/tmp` or your chosen artifact dirs. |
274
280
  | **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. |
@@ -306,29 +312,29 @@ This suite requires the installed stable `agent-browser --version` to meet the m
306
312
 
307
313
  The default unit suite also runs `agentBrowserExtension passes through core command coverage fallback matrix` in [`test/agent-browser.extension-passthrough-validation.test.ts`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/test/agent-browser.extension-passthrough-validation.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 that file (`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. A third matrix (`agentBrowserExtension passes through provider and specialized skill workflows`) asserts provider `open` argv shapes still receive `--json` plus implicit `--session` while read-only `skills get …` stays stateless (no managed session fields) and provider credential env vars are forwarded into the fake upstream log. Extend those matrices when adding passthrough coverage that should stay out of the slow real-upstream loop.
308
314
 
309
- ### Native checkpoint qualification
315
+ ### Native lifecycle qualification
310
316
 
311
- `test/agent-browser.checkpoint-native.test.mjs` is an opt-in, model-free test for a Pi SDK exposing `acquireCheckpoint` with native failed-journal repair/flush (qualified against core `c401cada69172dfd683e6d569b2cd9e5a45b4fcd`). It loads the compiled extension through native resource discovery, dispatches real tools through an awaited native command, and records real results with SessionManager. It checks idle/release/reload, live root and managed browsers (including a stable ambient socket override without a Pi override), off-branch state, detached and native-owned code calls, recording, failed journal appends/cleanup leases, routes, trace, caller-owned CDP attachment, and native checkpoint selection/entries plus root restore after replacing checkout/state directories with fresh inodes. No provider or fake readiness classifier is used.
317
+ [`test/agent-browser.native-lifecycle.test.mjs`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/test/agent-browser.native-lifecycle.test.mjs) is the model-free portable SDK lifecycle gate. It loads the compiled extension through real native resource discovery and executes browser tools against loopback fixtures. Qualify official and fork Pi 1.0 graphs independently: no removed fork-only APIs are required. It covers branch/reload continuity, detached and queued code cancellation/ordering, managed cleanup, caller-owned attachment and off-branch routing, failed journal-begin refusal during recording, and root save/reopen across fresh checkout/state-directory inodes. This is lifecycle evidence, not serialization of live page JavaScript, forms or recordings.
312
318
 
313
- Run as a non-root user in an isolated environment with stock `agent-browser`, Chrome for Testing and ffmpeg. Clear inherited credentials/configuration; do not use a personal browser. The test creates its own HOME/socket directory, copies only the supplied browser binary directory, serves a loopback synthetic page, explicitly closes its sessions, and removes its fixtures. `PI_CHECKPOINT_TEST_BROWSER_DIR` must name a binary installation directory such as `.../.agent-browser/browsers/chrome-<version>`, never a browser profile.
319
+ Run non-root with an isolated HOME/socket root and stock `agent-browser`, Chrome for Testing and ffmpeg, without personal profiles or inherited credentials/configuration. The browser directory must contain binaries, never a personal profile.
314
320
 
315
321
  ```bash
316
322
  npm run build
317
- PI_CHECKPOINT_TEST_REQUIRED=1 \
318
- PI_CHECKPOINT_TEST_SDK=/path/to/native/pi-coding-agent/dist/index.js \
319
- PI_CHECKPOINT_TEST_BROWSER_DIR=/path/to/browsers/chrome-<version> \
320
- node --test test/agent-browser.checkpoint-native.test.mjs
323
+ PI_NATIVE_LIFECYCLE_REQUIRED=1 \
324
+ PI_NATIVE_LIFECYCLE_SDK='/path/to/pi-coding-agent/dist/index.js' \
325
+ PI_NATIVE_LIFECYCLE_BROWSER_DIR='/path/to/browsers/chrome-<version>' \
326
+ node --test test/agent-browser.native-lifecycle.test.mjs
321
327
  ```
322
328
 
323
- `PI_CHECKPOINT_TEST_EXTENSION` can select a separate baseline checkout. With `PI_CHECKPOINT_TEST_BASELINE_RESTORE=1`, only its existing root-restore path runs and every receipt must retain the old shutdown blocker; this is not positive sleep qualification. The SDK selector is test-only; it does not change package peers or activate an extension. This gate is separate from the default 0.84 unit fixtures and release/platform/model-based gates. Qualification is for ordinary native save-on-close and explicit URL reopen, not a live browser snapshot. Journal fault injection checks that ongoing native I/O errors reject acquisition and preserve prior bytes/accepted entries. Permission repair must recover through core capture without repeating the failed append; recording retry and cleanup leases remain extension-owned. The test also checks exact repaired entries/selection in a separate-process strict cold restore and rejection of a mismatched artifact. After explicit close it observes native daemon exit before asserting idle readiness; an acknowledgement alone is not proof of inactivity. The abnormal-restart regression kills only its exact SDK fixture PID after ordinary branch navigation, then reopens the real journal in a fresh SDK process. It verifies that the off-branch wrapper-created daemon blocks capture without acquiring cleanup ownership, and that explicit managed-looking names and a nonowned namespace retain ambient routing. Same-namespace/same-name controls check distinct live daemons in owned and ambient socket roots, continued blocking after closing only the caller, ambient-only blocking after closing the historical daemon, and positive readiness after both are explicitly closed. All browser ownership evidence comes from executed native tools, never injected ownership records.
329
+ `PI_NATIVE_LIFECYCLE_EXTENSION` selects a separate compiled checkout; `PI_NATIVE_LIFECYCLE_ARTIFACT_DIR` selects retained transcript evidence. These are test selectors, not runtime package config. Retain exact host/source identity, native tool receipts and cleanup proof. Local SDK qualification complements, rather than replaces, the configured-source tmux harness, live-site smoke and platform gates.
324
330
 
325
331
  #### Routine GitHub PR checks
326
332
 
327
- [`.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` and manual dispatch. Independent Ubuntu jobs qualify the locked official Pi graph and the maintained fork's current `main` as a complete installed 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 checks the packed Pi load without repeating the full suite. When the candidate official version differs from the supported Pi floor, that macOS job also selects the actual floor graph for a focused type/package smoke. The host selector uses the pinned `fitchmultz/.github` automation scripts without changing them. There are no cross-job host artifacts or persistent caches.
333
+ [`.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` and manual dispatch. Independent Ubuntu jobs qualify the locked official Pi graph and the maintained fork's current `main` as a complete installed 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 checks the packed Pi load without repeating the full suite. When the candidate official version differs from the supported Pi floor, that macOS job also selects the actual floor graph for a focused type/package smoke. The host selector uses the pinned `fitchmultz/.github` automation scripts without changing them. There are no cross-job host artifacts or persistent caches. The official lane always qualifies the locked official graph; the fork lane first compares the fork's `main` Pi version against the supported Pi floor, and while the fork is below that floor it skips the fork build/qualification and emits a truthful unattempted-below-floor receipt in the job summary instead of failing or resurrecting dropped fork APIs. The full supported-fork qualification path runs unchanged once the fork reaches the floor.
328
334
 
329
- [`.github/workflows/native-checkpoint.yml`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/.github/workflows/native-checkpoint.yml) independently checks out the PR head and runs on the same PR/manual triggers. Its CI-only [`ci-native-checkpoint.sh`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/scripts/ci-native-checkpoint.sh) builds the maintained fork's current `main` and compiled extension on Node **24.21.0**, installs stock **agent-browser 0.38.1** and Chrome for Testing, checks generated playbook and live command-reference drift, then requires **13 passed, zero failed/cancelled/skipped/todo** real-browser checkpoints. 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. No personal profile, credentials, or model calls are involved.
335
+ [`.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, 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 passing checks with no unexpected 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. No personal profile, credentials, or model calls are involved.
330
336
 
331
- Each fork workflow resolves `main` once at checkout and uses that exact commit for its build and provenance checks. CI writes setup, provenance, command-reference, and native TAP results to the job log instead of uploading artifacts. 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 sleep/resume qualification.
337
+ The fork compatibility workflow resolves `main` once at checkout and uses that exact commit for its build and provenance checks; the native lifecycle gate instead uses the locked official Pi graph installed by `npm ci`. CI writes setup, provenance, command-reference, and native TAP results to the job log instead of uploading artifacts. 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.
332
338
 
333
339
  ### Native Linux socket-root regression
334
340
 
@@ -47,7 +47,7 @@ Define the product requirements and constraints for `pi-agent-browser-native`.
47
47
  ### Install priority
48
48
 
49
49
  - Prioritize the package install path first.
50
- - User-facing install docs should lead with `pi install npm:pi-agent-browser-native`; ephemeral package trials and validation should use `pi --no-extensions -e npm:pi-agent-browser-native[@<version>]` so configured checkout or global sources cannot duplicate `agent_browser`, adding `--approve` in Pi 0.84.0+ automation when the current project is intentionally trusted.
50
+ - User-facing install docs should lead with `pi install npm:pi-agent-browser-native`; ephemeral package trials and validation should use `pi --no-extensions -e npm:pi-agent-browser-native[@<version>]` so configured checkout or global sources cannot duplicate `agent_browser`, adding `--approve` in automation when the current project is intentionally trusted.
51
51
  - User-facing install docs should also include the GitHub source path `pi install https://github.com/fitchmultz/pi-agent-browser-native`.
52
52
  - Provide a read-only package-level doctor command that checks upstream `agent-browser` PATH/version and duplicate Pi package/checkout sources before first use. It must not mutate Pi settings and must remain distinct from upstream `agent-browser doctor`.
53
53
  - Keep the current local-checkout path documented as the practical pre-release and development flow.
@@ -66,12 +66,12 @@ Define the product requirements and constraints for `pi-agent-browser-native`.
66
66
 
67
67
  - Keep the always-on interface compact: `agent_browser { args, stdin?, outputPath?, timeoutMs?, sessionMode? }`, strict-JSON `agent_browser_code { code, session?, namespace?, timeoutMs?, outputPath? }`, and `agent_browser_tools { enable? }`.
68
68
  - Preserve the complete native command surface through one CLI executor. Native batch handles fixed sequences; code handles branches/loops/aggregation. Remove the redundant public job DSL and old isolated-script execution instead of carrying parallel legacy runtimes.
69
- - Register advanced action, QA, Electron, UI-source, and network-source tools once, initially inactive. Enable additively through Pi's native tool selection/history without removing unrelated tools. Use flat schemas and return executable next actions naming the actual tool.
69
+ - Register advanced action, QA, Electron, UI-source, and network-source tools once with native `defaultActive: false`. Enable additively through Pi's native tool selection/history without removing unrelated tools. Preserve explicit/defaultTools selections, loader activation, initial resume, tree navigation and reload; retain only the additive fallback needed for official Pi 1.0 initial resume. Use flat schemas and return executable next actions naming the actual tool.
70
70
  - Preserve unique visible accessible dropdown selection, semantic/ref recovery, truthful QA verdicts (including ambiguous error-buffer residue), attached diagnostic preservation/defaults, Electron process/profile ownership, and bounded source scans. Raw diagnostic-read success is not a QA verdict, and source hints remain candidates rather than authoritative blame.
71
71
  - Code runs in a fresh permissioned Node child with no host APIs/imports, null-prototype task globals, JSON-only bounded IPC, serial native calls, and explicit JSON/image output. Keep current source/output/call/deadline limits. Browser/authentication persists under existing native ownership and configuration; JavaScript variables do not. Allow ordinary native commands including batch/auth/profile/state/connect/close, but prevent changes to the fixed parent-selected identity and namespace-wide close within a cell.
72
72
  - Hold a cooperating-process execution lock keyed by actual socket context, canonical namespace, and session across direct helper/action work or the entire code cell. Use ordered multi-identity acquisition for replacement/cleanup and a namespace barrier for direct close-all. This does not coordinate humans, third-party clients, or older versions, guarantee atomic browser actions, or provide rollback.
73
73
  - Persist one canonical begin/finish event format for direct/code/host work through native Pi custom entries and a shared reducer. Define full captures once, preserve exact targets/native identity, and persist artifact-row changes rather than unchanged views. Interrupted outcomes remain unknown until inspection; failed begin blocks dispatch and failed finish stops dependent work without mutation retry. Require actual journal publication before browser dispatch. Legacy browser/lease decoders belong only to validated offline stopped-copy conversion; preserve original bytes, all ancestry and owner UUIDs. A fork must never acquire its parent's cleanup rights. Bound extension replay with token projection and winning definitions on both hosts, while disclosing stock official Pi's eager native loader and individual-value memory ceilings; see [`SESSION_STORAGE.md`](SESSION_STORAGE.md).
74
- - Use one canonical model-visible observation for JSON/prose/code with success/data/error, exact recovery, artifact receipts, and image observations. Details is audit/replay metadata, not the sole source of actionable failures. Inner calls avoid full model rendering/spills/image encoding. Bound outer output and name a complete redacted observation spill rather than truncating executable payloads.
74
+ - Use one canonical model-visible observation for JSON/prose/code with success/data/error, exact recovery, artifact receipts, and image observations. Native `outputSchema`/`structuredContent` under the Browser tool namespace expose that same bounded redacted projection, not raw internal details. Loader inventory and normalized search data keep their existing shapes. Details is audit/replay metadata, not the sole source of actionable failures. Return canonical native `isError` without a result-repair hook; preserve prose notices and explicit JSON. Inner calls avoid full model rendering/spills/image encoding. Bound outer output and name a complete redacted observation spill rather than truncating executable payloads.
75
75
  - Attach only verified real images; code selects current-cell image handles explicitly. Report pixel dimensions and CSS viewport/DPR/crop/scroll/frame evidence conservatively. Unknown geometry remains unknown; neither full-page nor element captures are assumed viewport coordinates. Do not inject model-specific image-detail/provider payload changes.
76
76
  - Direct upstream capability remains available: explicit sessions, state/restore paths, profiles, config, file access, launch arguments, environment, local pages, output paths, and close arguments pass through under ordinary native semantics. Keep all session/state rows visible. Wrapper validation concerns input shape, lifecycle integrity, and truthful evidence, not authorization of resources.
77
77
  - Native download owns clicking and saving, including loopback, Blob exports, and redirects. Create artifact directories before dispatch and verify saved files; output-data writes must not alias browser artifacts. Pending recording is not saved video.
@@ -94,7 +94,7 @@ Define the product requirements and constraints for `pi-agent-browser-native`.
94
94
  - The primary confidence path is a real `pi` session driven in `tmux`.
95
95
  - For quick local checkout smoke validation, launch `pi --approve --no-extensions -e .` from the repository root so only the checkout copy loads; do not rely on Pi settings or `/reload` semantics in this isolated mode.
96
96
  - For hot-reload validation, configure exactly one active source for this extension in Pi settings and launch plain `pi`; validate `/reload` there because it exercises auto-discovered/configured resources.
97
- - Maintain a tmux-driven configured-source lifecycle harness (`npm run verify -- lifecycle`; required before release per `docs/RELEASE.md`) that isolates Pi settings, uses exactly one configured source, exercises `/reload`, full restart plus exact `--session-id` relaunch, and asserts managed-session continuity, persisted artifact survival, and real Pi `tool_result` failure-patch semantics. It remains outside the default `npm run verify` sequence, but it is embedded in `npm run verify -- release` so `prepublishOnly` enforces it before publish unless scripts are intentionally skipped. The harness defaults Pi to model `zai/glm-5.2` (`scripts/verify-lifecycle.mjs`); pass `--model <id>` after `lifecycle` when a different model is required. Keep `docs/RELEASE.md` accurate about the harness behavior, cleanup, transcript retention, and limitations.
97
+ - Maintain a tmux-driven configured-source lifecycle harness (`npm run verify -- lifecycle`; required before release per `docs/RELEASE.md`) that isolates Pi settings, uses exactly one configured source, exercises `/reload`, full restart plus exact `--session-id` relaunch, and asserts managed-session continuity, persisted artifact survival, and native returned `isError`, visible prose failure notices and unchanged parseable JSON. It remains outside the default `npm run verify` sequence, but it is embedded in `npm run verify -- release` so `prepublishOnly` enforces it before publish unless scripts are intentionally skipped. The harness defaults Pi to model `zai/glm-5.2` (`scripts/verify-lifecycle.mjs`); pass `--model <id>` after `lifecycle` when a different model is required. Keep `docs/RELEASE.md` accurate about the harness behavior, cleanup, transcript retention, and limitations.
98
98
  - Validate a full `pi` restart with exact `--session-id` relaunch or `/resume` when changes touch managed-session continuity, reload behavior, or persisted artifact paths. Validate branch-backed state changes with the focused `session_tree` harness tests.
99
99
  - Prefer full `pi` restart over `/reload` when validating extension changes beyond a quick reload smoke check.
100
100
  - Use `/resume` or an explicit session id/path when needed after restart.
@@ -119,7 +119,7 @@ The design should comfortably support workflows such as:
119
119
  ## Implications for the implementation
120
120
 
121
121
  - Package-manifest behavior matters more than repo-local development wiring.
122
- - The extension uses native Pi tool registration/activation and named prompt sections rather than replacing the full system prompt. Qualify official Pi 0.87 and the fork independently; fork checkpoint hooks stay optional and hosted provider orchestration is not required.
122
+ - The extension uses native Pi tool registration/activation and named prompt sections rather than replacing the full system prompt. Require Pi 1.0.0 and qualify official and fork hosts independently. Retain the instruction-group collector when supported and identical full native prompt-section fallback otherwise; hosted provider orchestration is not required.
123
123
  - The wrapper should stay thin, with upstream `agent-browser` remaining the source of truth for command semantics.
124
124
  - Successful and failed tool outcomes should surface bounded machine-readable fields on Pi-facing `details` (`resultCategory`, `successCategory`, `failureCategory`, optional structured `nextActions`, optional `pageChangeSummary` with explicit observed-vs-dispatched evidence and per-step summaries on `batch`, optional `artifactVerification` with the same shape on successful `batchSteps[]` rows, optional `outputFile`, optional `timeoutPartialProgress`) so agents can branch without parsing prose; browser-bearing `nextActions` must preserve a known session identity so recovery cannot inspect an unrelated implicit session; stateful commands (`auth`, `cookies`, `storage`, `dialog`, `frame`, `state`) plus other structured diagnostics (for example `network`, `diff`, `trace`, `stream`, `dashboard`, `chat`) and `batch` should redact secret-bearing payloads in model-facing `details.data`, including the compact per-step `batch` roll-up on the parent result (full per-step payloads live on `batchSteps[]`). Dialog/prompt-related timeouts should be bounded with recovery `nextActions`; non-dialog timeouts should prefer best-effort per-step progress and retry payloads when a plan is available; no-op scrolls should expose no-movement state instead of only an upstream success boolean; explicit page/container scroll helpers should expose before/after movement evidence. The contract lives in [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details), enums and classifier precedence live in `extensions/agent-browser/lib/results/categories.ts` and `contracts.ts`, and presentation-time summaries, redaction, network request follow-ups, and artifact verification rollups are assembled in `extensions/agent-browser/lib/results/presentation.ts` (`buildPageChangeSummary`, command taxonomy predicates from `command-taxonomy.ts`, `redactPresentationData`, `buildArtifactVerificationSummary`, `buildBatchPresentation`).
125
125
  - User-facing docs belong in `README.md` and the canonical published files under `docs/`.
@@ -14,15 +14,15 @@ 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 optional 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. Optional public metadata APIs and `getEntry()` provide structural ancestry and selected snapshot access on the maintained fork. 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 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.
18
18
 
19
- Official Pi 0.99.2 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.
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
 
21
21
  Artifact events persist row upserts/removals in journal order. The internal recent view defaults to 100 rows; it is separate from cumulative journal size and the independent recording reservation/tombstone journal. Artifact upserts are credential-redacted before persistence. Tool `details.artifactManifest` contains only changed or referenced receipts for that invocation, including evictions observed during that call. Retention summaries and close cleanup guidance can describe the internal recent view without copying it into every result.
22
22
 
23
- Required replay snapshots stay in retained journal ancestry, outside observation-spill eviction. Caller-selected files remain caller-owned. Redacted persistent spills retain their existing byte budget; process-private files retain their existing cleanup. A receipt does not make external bytes immutable or include them in an export/checkpoint. Preserve referenced files in the matching archive layout when needed.
23
+ Required replay snapshots stay in retained journal ancestry, outside observation-spill eviction. Caller-selected files remain caller-owned. Redacted persistent spills retain their existing byte budget; process-private files retain their existing cleanup. A receipt does not make external bytes immutable or include them in an export. Preserve referenced files in the matching archive layout when needed.
24
24
 
25
- Tree changes join code execution through its complete observation finalization before restoring branch-visible state. Interrupted results retain complete caller observations in process-private spills without publishing their artifact state onto the newly selected branch. Tree changes do not roll back the real browser; process-owned cleanup and recording facts remain separate. An ordinary fork has a new native Pi UUID and cannot acquire its parent's managed/Electron/script cleanup rights. Wrapper-owned begins retain their selected socket root and owner UUID even if the launch finish is lost; restart can inspect or clean that original identity without declaring the launch successful. Owned follow-ups, code and cleanup keep that root when process defaults change; unrelated caller sessions retain native routing. Optional checkpoints refuse live or unverified resources and never close browsers to manufacture readiness.
25
+ Startup and tree changes serialize branch restore with managed/artifact work, reusing one captured replay for state and cleanup-lease recovery. Launch configuration is folded once per session during that replay. Tree changes join code execution through its complete observation finalization before restoring branch-visible state. Interrupted results retain complete caller observations in process-private spills without publishing their artifact state onto the newly selected branch. Tree changes do not roll back the real browser; process-owned cleanup and recording facts remain separate. An ordinary fork has a new native Pi UUID and cannot acquire its parent's managed/Electron/script cleanup rights. Wrapper-owned begins retain their selected socket root and owner UUID even if the launch finish is lost; restart can inspect or clean that original identity without declaring the launch successful. Owned follow-ups, code and cleanup keep that root when process defaults change; unrelated caller sessions retain native routing.
26
26
 
27
27
  ## Converting a retained legacy journal
28
28
 
@@ -26,9 +26,9 @@ When upstream ships a new `agent-browser` or the inventory changes:
26
26
  4. Update the **Baseline checklist by inventory section** table below so each `CAPABILITY_BASELINE.inventorySections[].id` row still points at the right docs, code, tests, and status notes.
27
27
  5. Re-run the gates in **Verification evidence** on a machine that matches release expectations (`pi`, `tmux`, model config for lifecycle) and replace the dated status cells with fresh outcomes.
28
28
 
29
- ## 0.7 browser contract
29
+ ## Current browser contract
30
30
 
31
- The compact direct/code/loader surface replaces public multimode inputs while retaining native commands and advanced outcomes. This section describes the implementation contract; dated 0.6 evidence below does not qualify new code.
31
+ The compact direct/code/loader surface replaces public multimode inputs while retaining native commands and advanced outcomes. This section describes the implementation contract; dated evidence below does not qualify new Pi 1.0 code.
32
32
 
33
33
  | Area | Contract and verification target |
34
34
  | --- | --- |
@@ -38,11 +38,12 @@ The compact direct/code/loader surface replaces public multimode inputs while re
38
38
  | RQ-0068 recipes | No recipe registry, persistent JavaScript, second driver, or interpreter dependency. |
39
39
  | RQ-0096 Electron | Flat lifecycle tool preserves app/process/profile ownership and cancellation; native browser/code operations reuse its returned session. |
40
40
  | RQ-0142 code | Fresh permissioned Node child over persistent parent-selected browser; explicit JSON/current-cell image output, visible failures/counts, ordinary auth/config/environment, ordered Pi intent/completion transitions, child cancellation/reaping, no legacy public execution. |
41
+ | Hotpath boundaries | Unrelated tools/harmless Bash return before prompt policy. Latest raw user intent is seeded on start/tree, updated by `message_end` and refreshed after native content replacement. Captured admission uses a validated append-only prefix; one queued replay restores branch/lease state and folds per-session launch settings once. Per-row renderer memoization skips unchanged formatting. No broad config/trust/history cache, new wait/timer or budget increase. |
41
42
  | Shared ordering | Actual socket/namespace/session lock spans helper/action or entire cell; sorted identity sets for replacement/cleanup and namespace barrier for direct close-all. Requires every participating Pi to run the updated package; no human/third-party/older-version guarantee or transaction. |
42
- | Observation and geometry | Canonical bounded JSON/prose/code observations expose exact recovery and receipts; complete observation spills preserve large output. Image dimensions/CSS viewport/DPR/crop/scroll/frame evidence is measured or explicitly unknown; no viewport-coordinate assumptions for full-page/element images. |
43
- | Pi integration | Native additive activation/history on independently qualified official Pi 0.87 and fork; public `pi:instruction-groups` registration supplies one full `browser` instruction source. Managed hosts own deferred delivery; unmanaged/stock hosts receive identical full eager guidance even for generic prompts. No permission widening or legacy discovery metadata. `test/agent-browser.discovery.test.ts` covers full-text parity, dynamic ownership, and startup/late registration; tool-surface tests preserve host selections, with pipeline coverage in `test/agent-browser.pi-pipeline.test.ts`. Optional checkpoint hooks, no provider payload/image-detail overrides. |
43
+ | Observation and geometry | Canonical bounded JSON/prose/code/native `structuredContent` observations expose exact recovery and receipts, with native namespace/output-schema metadata and canonical returned `isError`; complete observation spills preserve large output. Image dimensions/CSS viewport/DPR/crop/scroll/frame evidence is measured or explicitly unknown; no viewport-coordinate assumptions for full-page/element images. |
44
+ | Pi integration | Pi 1.0 floor with independently qualified official/fork graphs. Five advanced direct tools use native `defaultActive: false`; a narrow additive initial-resume fallback preserves available transcript selections without overriding explicit/defaultTools/filtered host selection. Loader/tree/reload retain native history; public `pi:instruction-groups` registration supplies one full `browser` instruction source. Managed hosts own deferred delivery; unmanaged/stock hosts receive identical full eager guidance even for generic prompts. No permission widening or legacy discovery metadata. `test/agent-browser.discovery.test.ts` covers full-text parity, dynamic ownership, and startup/late registration; tool-surface tests preserve host selections, with pipeline coverage in `test/agent-browser.pi-pipeline.test.ts`. No checkpoint or fork metadata/revision APIs, provider payload edits or image-detail overrides. |
44
45
 
45
- See [migration](TOOL_CONTRACT.md#07-migration), [canonical observations](TOOL_CONTRACT.md#canonical-observation), and [release qualification/rollback](RELEASE.md#07-upgrade-and-rollback). Routine GitHub Actions runs official/fork Linux compatibility, a macOS packed-Pi smoke, and native Linux checkpoints on PRs to `main`; Windows CI is excluded. Release/platform evidence and review remain separate from these focused checks.
46
+ See [migration](TOOL_CONTRACT.md#07-migration), [canonical observations](TOOL_CONTRACT.md#canonical-observation), and [release qualification/rollback](RELEASE.md#07-upgrade-and-rollback). Routine GitHub Actions runs official/fork Linux compatibility, a macOS packed-Pi smoke, and Native lifecycle Linux qualification on PRs to `main`; Windows CI is excluded. Release/platform evidence and review remain separate from these focused checks.
46
47
 
47
48
  ## Audit result
48
49
 
@@ -90,7 +91,7 @@ Current summary:
90
91
  | RQ-0153 | Browser storage retains native JSONL authority, once-stored ancestral ref definitions, small correlated begin/finish events, explicit uncertainty/reuse and native-generation validation, invocation-only artifact receipts and ordered row changes. Failed persistence never retries effects; ordinary forks retain facts without acquiring parent cleanup rights. Read-only token replay and stopped separate-copy conversion preserve all ancestry, explicit observations and original audit bytes. | [`docs/SESSION_STORAGE.md`](SESSION_STORAGE.md), `lib/browser-transcript.ts`, `lib/browser-journal.ts`, `lib/browser-session-conversion.ts`, `test/agent-browser.storage-growth.test.ts`, `test/agent-browser.storage-recovery.test.ts`, existing script/ref/confirmation/Electron lifecycle tests |
91
92
  | RQ-0152 | Agent feedback closes recovery and evidence gaps without a new runtime layer: unknown-target timeouts return a visibly executable `get url` → `snapshot -i` fail-fast action while dialog recovery remains allowed; successful tab creation/selection/close, including dispatched batch rows, live-verifies URL/fresh titles and retains new, selected, and post-close blank tabs; compacted direct or batched `outputPath` writes use only full command-redacted live wrapper spills and fail rather than save metadata; explicit URL reads/all-read batches avoid browser helpers and managed replacement, while proven native read confirmations preserve exact session routing and capability-gated browser independence; single session-info preflights distinguish daemon/browser/native/Pi ownership; native recording receipts expose capture versus encoded measurements and survive failure/timeout exports, with bounded identity-matched recovery and no file-only success; direct or batched first/fresh local headed launches expose an unverified `browserWindow` handoff while attachments do not; snapshot spills and SAML/OAuth URL values are redacted at model/persistence boundaries; unsupported direct/batch `scrollintoview text=...` fails before upstream false success with visible native recovery payloads while help passes through; and web search sends Exa primary/version guidance, removes exact normalized-URL duplicates without overfetch, and labels provider page dates without claiming crawl/version proof. | [`docs/TOOL_CONTRACT.md`](TOOL_CONTRACT.md), [`docs/COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md), [`docs/ARCHITECTURE.md`](ARCHITECTURE.md), `test/agent-browser.extension-errors-artifacts.test.ts`, `test/agent-browser.extension-tabs.test.ts`, `test/agent-browser.extension-validation.test.ts`, `test/agent-browser.page-target-validation.test.ts`, `test/agent-browser.runtime.test.ts`, `test/agent-browser.snapshot-presentation.test.ts`, `test/agent-browser.web-search.test.ts`, `test/agent-browser.real-upstream-contract.test.ts` |
92
93
 
93
- Browser journal storage (RQ-0153) uses one canonical small event/reducer, once-stored complete captures and journal-ordered artifact changes. `test/agent-browser.storage-growth.test.ts` protects the incident-sized map and ordinary-code growth; `test/agent-browser.storage-recovery.test.ts` covers actual append-fault dispatch counts, concurrent publication during captured-branch replay, unpublished selected-leaf refusal, unknown prefixes, same-URL generation replacement, branch conversion and strict token validation. Existing tab/ref, read-confirmation, recording, artifact and Electron lifecycle suites retain their contracts. The opt-in `test/helpers/large-browser-journal.mjs` exercises a >1 GiB original with a giant ignored value under a constrained V8 heap; it reports actual RSS separately. Official and fork load/restart qualification remains independent, and stock official 0.99.2's native eager loader is not repaired by the extension alone. Conversion is offline and source-retaining; see [`SESSION_STORAGE.md`](SESSION_STORAGE.md).
94
+ Browser journal storage (RQ-0153) uses one canonical small event/reducer, once-stored complete captures and journal-ordered artifact changes. `test/agent-browser.storage-growth.test.ts` protects the incident-sized map and ordinary-code growth; `test/agent-browser.storage-recovery.test.ts` covers actual append-fault dispatch counts, concurrent publication during captured-branch replay, unpublished selected-leaf refusal, unknown prefixes, same-URL generation replacement, branch conversion and strict token validation. Existing tab/ref, read-confirmation, recording, artifact and Electron lifecycle suites retain their contracts. The opt-in `test/helpers/large-browser-journal.mjs` exercises a >1 GiB original with a giant ignored value under a constrained V8 heap; it reports actual RSS separately. Official and fork load/restart qualification remains independent, and stock official 1.0.0's native eager loader is not repaired by the extension alone. Conversion is offline and source-retaining; see [`SESSION_STORAGE.md`](SESSION_STORAGE.md).
94
95
 
95
96
  QA truthfulness (#121, RQ-0145) is covered by the registered-tool controls in `test/agent-browser.extension-input-modes.test.ts` and the strict `contract suite matches QA non-pass after same-URL error-buffer rollover` case in `test/agent-browser.real-upstream-contract.test.ts`. The real fixture fills the native error FIFO with identical rows, then verifies that a new document actually throws again at the same URL and that QA is always non-pass. Matched rows fail as an unverified check, not an application-error assertion. Empty/cleared and explicit `checkErrors: false` controls preserve valid passes; the wrapper does not fix upstream `errors --clear` or accept a warning-only pass as resolution.
96
97
 
@@ -98,7 +99,7 @@ Browser evidence (RQ-0152) is covered by `test/agent-browser.browser-evidence.te
98
99
 
99
100
  Contributor fixes #133/#152 remove unused prompt suffix entries without changing runtime guidance and diagnose bare `--no-sandbox` only in the command slot or navigation option positions. Native `--args` values and literal operands remain intact; batch checks use raw effective rows without treating row-local `--args` as a launch setting. `test/agent-browser.chromium-args.test.ts` covers pre-dispatch rejection, literal/flag-value controls, inspection, raw/stdin batch precedence and dispatcher outcomes. Existing prompt/grammar checks remain; source checks do not replace native-product gates.
100
101
 
101
- Electron diagnostics (RQ-0096, #128) keep list timeout rejection truthful, label explicit-ID cleaned records as historical without changing active selection or actions, and measure the tracked profile path with native `lstat` (`present` / ENOENT-only `absent` / `unknown`). Existing Electron discovery/lifecycle tests cover current liveness independently of cleanup history, native path errors and dangling symlinks, transcript replay, and unchanged cleanup ownership. Failed-startup diagnostics include redacted last-4096-byte stdout/stderr tails in visible text and structured details, using private profile-local regular files. Regression tests cover exact tails, empty output, capture/spawn errors and closed native file handles; a real spawned fixture with injected kill denial proves live output through temp cleanup, retained logs through native host-exit behavior, and persistence failure reporting. Tracked-child cleanup regressions require actual exit before profile removal and immediate executable deletion. Restored-PID cleanup uses native process command-line evidence on Windows and POSIX; real-process regressions verify matching profiles with spaces/Unicode, refusal of unrelated or mismatched profiles, and shutdown after transcript restoration. The shared daemon policy verifies a restored Electron attachment's live browser endpoint and named upstream `get cdp-url` before ordinary calls, status, or probe reuse; `test/agent-browser.extension-ref-guards.test.ts` covers successful reuse and repeated rejection of replaced app, connection, and namespace identities without weakening generic restore-disabled rules. These checks do not replace native-app, Pi lifecycle, package, or live-site gates.
102
+ Electron diagnostics (RQ-0096, #128) keep list timeout rejection truthful, label explicit-ID cleaned records as historical without changing active selection or actions, and measure the tracked profile path with native `lstat` (`present` / ENOENT-only `absent` / `unknown`). Focused Electron discovery, host-lifecycle, and branch-ownership tests cover current liveness independently of cleanup history, native path errors and dangling symlinks, transcript replay, and unchanged cleanup ownership. Failed-startup diagnostics include redacted last-4096-byte stdout/stderr tails in visible text and structured details, using private profile-local regular files. Regression tests cover exact tails, empty output, capture/spawn errors and closed native file handles; a real spawned fixture with injected kill denial proves live output through temp cleanup, retained logs through native host-exit behavior, and persistence failure reporting. Tracked-child cleanup regressions require actual exit before profile removal and immediate executable deletion. Restored-PID cleanup uses native process command-line evidence on Windows and POSIX; real-process regressions verify matching profiles with spaces/Unicode, refusal of unrelated or mismatched profiles, and shutdown after transcript restoration. The shared daemon policy verifies a restored Electron attachment's live browser endpoint and named upstream `get cdp-url` before ordinary calls, status, or probe reuse; `test/agent-browser.extension-electron-branch-ownership.test.ts` covers successful reuse and repeated rejection of replaced app, connection, and namespace identities without weakening generic restore-disabled rules. These checks do not replace native-app, Pi lifecycle, package, or live-site gates.
102
103
 
103
104
  Artifact diagnostics (#124/#127) use a shared pre-dispatch mkdir-error boundary, preserve raw batch argv/precedence, recommend absolute raw artifact paths, recognize image headers rather than filename MIME guesses, retain known requested/reported paths, and warn once about conservative ref invalidation after dispatched recording starts and URL-bearing restarts, on success or failure, without claiming an observed page change. `test/agent-browser.artifact-diagnostics.test.ts` covers registered filesystem failures, real image bytes and misleading suffixes, the inline bound, native macOS path aliases, recording/ref continuity and unreached-row negatives; `test/agent-browser.presentation-artifacts-batch.test.ts` retains artifact/persistence coverage. These source regressions do not qualify daemon-cwd differences or affected-filesystem timestamp behavior (#118), or replace native/Pi/package/live-site gates.
104
105
 
@@ -126,31 +127,32 @@ At runtime source `3a9adf490883149e7f79ee070d1900877e17b891`, PR compatibility p
126
127
 
127
128
  Fresh precommit evidence for that runtime passed real Pi checkout/live-site and supported disposable Electron smoke, configured-source lifecycle, packaged runtime-only SDK/CLI loading, real-upstream checks, native macOS and the canonical named Ubuntu target (Debian 12). Local macOS is the documented alternate, not an SSH pass. Docs/workflow-only delivery may reuse this runtime evidence only after all 104 rebuilt runtime files match the checked artifact; changed published docs require a newly checked retained tarball. No additional paid/live gate is implied by an otherwise byte-identical runtime.
128
129
 
129
- Linux/macOS, declared Node floors, official/fork host identities, required consumer artifacts and Native checkpoint Linux remain required. Routine GitHub Actions is enabled for PRs to `main` and manual dispatch; its focused results do not substitute for the release and platform gates. Retain all three final reviewer approvals before merge/release/activation. The unchanged composed `release`/`prepublishOnly` command still includes Windows and is not reported as passed under this waiver; see [release guidance](RELEASE.md#current-0616-rollout-waiver).
130
+ Linux/macOS, declared Node floors, official/fork host identities, required consumer artifacts and Native lifecycle Linux remain required. Routine GitHub Actions is enabled for PRs to `main` and manual dispatch; its focused results do not substitute for the release and platform gates. Retain all three final reviewer approvals before merge/release/activation. The unchanged composed `release`/`prepublishOnly` command still includes Windows and is not reported as passed under this waiver; see [release guidance](RELEASE.md#current-0616-rollout-waiver).
130
131
 
131
132
  ## Verification evidence
132
133
 
133
134
  **0.38.1 PR evidence (2026-09-17, local macOS):** the full unit/fake suite passed 1,146 tests with 27 opt-in skips; the final review fixes then passed typecheck and 64 affected tests. Generated docs, live command-reference sampling, and the 132-file packaged Pi smoke passed. The real-upstream contract and 75 native batch/fidelity checks passed, as did all eight deterministic dogfood flows. Interactive compiled-checkout Pi smoke covered example.com and react.dev, delta/ref follow-ups, conditional screenshots, and a recording batch whose persisted result had two verified artifacts and no pending artifacts. Separate native probes confirmed helper-consumed WebMCP catalog updates remain visible. These checks do not qualify release-only platform/lifecycle gates; the hosted native-Windows result is recorded on the PR.
134
135
 
135
- Re-run the gates below before each release. Dated outcomes in this table are historical evidence for their named source/version, not qualification of the current 0.38.1 candidate. The earlier 0.36.0 rebaseline passed local pre-PR, real-upstream and deterministic dogfood on 2026-09-01; the 0.35.0 floor was last validated locally on 2026-08-26. The historical 0.38.1 PR qualification used local macOS and the hosted native-Windows gate. Current explicit owner waivers take precedence; neither historical passes nor failures qualify the new candidate. Release-only cross-platform/model/lifecycle and publication gates remain separate.
136
+ Re-run the gates below before each release. Dated outcomes in this table are historical evidence for their named source/version, not qualification of the current Pi 1.0 implementation. The earlier 0.36.0 rebaseline passed local pre-PR, real-upstream and deterministic dogfood on 2026-09-01; the 0.35.0 floor was last validated locally on 2026-08-26. The historical 0.38.1 PR qualification used local macOS and the hosted native-Windows gate. Current explicit owner waivers take precedence; neither historical passes nor failures qualify the new candidate. Release-only cross-platform/model/lifecycle and publication gates remain separate.
136
137
 
137
138
  | Gate | Evidence | Status |
138
139
  | --- | --- | --- |
140
+ | Native lifecycle Linux | Portable public SDK/native-browser lifecycle gate covers branch/reload, ordered code cancellation, ownership/routing, journal-begin failure and root save/reopen; see [native qualification](RELEASE.md#native-lifecycle-qualification). | Requalify the exact final source and host graph; no Pi 1.0 candidate pass is claimed by historical evidence below. |
139
141
  | Default local gate | `npm run verify` checks generated playbook drift, clean-builds generated `dist/`, runs `tsc --noEmit`, unit/fake tests, generated command-reference blocks, and live command-reference sampling. | **Earlier 0.36.0:** pass on 2026-09-01; 779 tests passed, two opt-in real-upstream tests skipped, and build/typecheck/docs/live command-reference gates passed. |
140
142
  | Pre-PR local gate | `npm run verify -- pre-pr` composes the default gate with package-content verification. Use before larger local handoffs or PR-ready claims when lifecycle/platform/live dogfood cost is not warranted. | **Earlier 0.36.0 / package 0.6.2:** pass on 2026-09-01; 779 tests passed, two opt-in tests skipped, and the 127-file tarball verified. |
141
143
  | Windows argument transport (#102/#131/#141) | `test/agent-browser.windows-argv.test.ts` exercises actual host argv, empty values, quotes, Unicode/spaces, stdin, custom shims and failure outcomes. `test/agent-browser.windows-stock-launcher.test.ts` covers the recognized global npm CMD template's direct-native path, command selection, fallback, literal LF/CRLF and cancellation. Custom or unrecognized batch launchers retain their existing newline limitation. POSIX keeps Node `spawn`. | Native Windows focused qualification on 2026-09-21 passed all seven stock-launcher controls, all 29 Chromium cases and 33 process/argv cases (two existing platform skips). Actual upstream Rust received all 12 expected operands; the original CMD path lost all four newline-bearing operands. These focused results do not replace full-suite, managed-browser, package or release gates. |
142
144
  | Real upstream contract | `npm run verify -- real-upstream` runs the localhost fixture matrix against a real stable `agent-browser` at or above the configured floor. | **Earlier recommended 0.36.0:** pass on 2026-09-01 (2/2 tests), including WebMCP and `--no-webmcp`; the 0.35.0 floor last passed on 2026-08-26 (2/2 tests). |
143
145
  | Packaged Pi smoke | `npm run verify -- package-pi` validates package contents, installs the extracted tarball's runtime dependencies without lifecycle scripts or host peers, loads the packaged `agent_browser` tool without requiring optional Brave config, and executes fake-upstream `--version`. | **Earlier package 0.6.2 / Pi 0.84.4:** pass on 2026-09-01; the 127-file tarball loaded exactly one packaged `agent_browser` and executed `--version`. |
144
- | Startup profile | `npm run verify -- startup-profile --samples <n>` clean-builds generated `dist/`, records direct package entrypoint import/factory timing in fresh Node processes, and writes `.artifacts/startup-profile/latest.json`. It must not launch Pi, tmux, mise, npm, browsers, or `agent-browser`; full Pi TUI ready-prompt profiling is intentionally excluded after it proved too invasive for routine verification. Run this opt-in evidence when package layout, the compiled entrypoint, top-level imports, schema registration, or prompt/config startup logic changes. | **Earlier compiled 0.6.2 entrypoint:** pass on 2026-09-01 with three samples; median 104.9 ms and max 114.5 ms, below the 250 ms budget. |
146
+ | Startup profile | `npm run verify -- startup-profile --samples <n>` clean-builds generated `dist/`, records direct package entrypoint import/factory timing in fresh Node processes using the same `scripts/startup-measurement.mjs` measurement and 250ms budget as the startup owner test (the test retains its Android-only 1000ms exception), and writes `.artifacts/startup-profile/latest.json`. It must not launch Pi, tmux, mise, npm, browsers, or `agent-browser`; full Pi TUI ready-prompt profiling is intentionally excluded after it proved too invasive for routine verification. Run this opt-in evidence when package layout, the compiled entrypoint, top-level imports, schema registration, or prompt/config startup logic changes. | **Earlier compiled 0.6.2 entrypoint:** pass on 2026-09-01 with three samples; median 104.9 ms and max 114.5 ms, below the 250 ms budget. |
145
147
  | Deterministic dogfood smoke | `npm run verify -- dogfood` clean-builds, then `scripts/verify-agent-browser-dogfood.ts` drives the native wrapper against a loopback HTTP fixture through persistent code aggregation, advanced QA/actions, native batch, screenshot artifact verification, and session close with the real `agent-browser` on `PATH`. | **Earlier 0.36.0 / package 0.6.2 / Pi 0.84.4:** pass on 2026-09-01; QA, script branching/cleanup, fresh/current opens, semantic clicks, job screenshot verification, and close all passed. |
146
148
  | WebGPU and restore autosave | Live 0.31.2 feature probes validate the new upstream paths independently from ordinary browser dogfood. | **macOS:** `doctor --webgpu` passed Apple Metal render/readback and headless red-pixel screenshot checks; the official Hello Triangle sample exposed the Metal adapter and produced a verified non-black screenshot. **Ubuntu image:** `doctor --webgpu --headed --json` passed SwiftShader render/readback and red-pixel screenshot checks with the baked Vulkan/Mesa/Xvfb dependencies. **Restore autosave:** an idle headless page timer changed localStorage and the namespaced restore file contained the new value before close; test state was removed. Wrapper-owned headed launches default periodic autosave off to avoid upstream 0.33.2 visible temporary collector tabs; native close still saves, direct window close can lose newer state because headed browsers are exempt from idle shutdown, and explicit `AGENT_BROWSER_AUTOSAVE_INTERVAL_MS` opts in at daemon launch; its effective value persists across resume, and changing a running wrapper-owned headed daemon in either direction requires close plus a fresh launch. On 2026-08-06, a headed checkout dogfood run crossed `react.dev` → `example.com` → `react.dev`, idled past the autosave interval while recording, showed no temporary page switch in frame/contact-sheet review, and closed both sessions successfully; disposable evidence was removed. **Windows interactive desktop:** post-release validation on 2026-07-15 used a disposable clone of snapshot `57cc3c0d-7d7c-4a4c-9c57-8270d4174679`, a logged-in console session, `agent-browser 0.31.2`, and Edge 150. The headed doctor WebGPU render/readback subcheck passed in 0.99s and its decoded screenshot subcheck passed with `rgb(255,0,0)`; a separate `--webgpu --headed` launch opened the proof page and the Parallels console capture visibly recorded the red triangle (553,500 bright-red pixels; SHA-256 `f5a28f5336cbdfeb0ff557af9425458bddc6b266d3cc6b946de7b101a0b43288`). The full doctor remained nonzero only for the unrelated absence of a separately installed Chrome binary; the explicit Edge executable completed the launch and both WebGPU probes. Local evidence is under `.artifacts/windows-webgpu-interactive/20260715T150903Z/summary.json`; the disposable clone and temporary account were deleted afterward. |
147
149
  | Android/Termux local bring-up | Non-release-blocking source validation uses Termux system Chromium through upstream's Linux `which chromium` discovery, the packaged Linux-musl arm64 CLI, real Pi managed-session smoke, deterministic dogfood, and the default unit/package gate. Electron desktop lifecycle is not applicable. | **Historical 0.6 local evidence (not 0.7 code qualification):** Android 17 / arm64 Termux passed implicit, explicit, and namespaced fresh sessions, managed restore, script, QA, semantic action, job, click, eval/batch stdin, screenshot attachment, recording dependencies, and cleanup; Android is not yet a Crabbox release target. |
148
150
  | Crabbox platform smoke | `npm run check:platform-smoke` syntax-checks the harness and cheap invariants. `npm run smoke:platform:ubuntu-image` builds the project-owned Linux image, `npm run smoke:platform:doctor` checks Crabbox 0.26.0+ and local target readiness, and `npm run smoke:platform:all` runs doctor first, then fast target-local `platform-build` (`npm run verify -- platform-target`, pack, clean Pi install) plus `browser-dogfood-smoke` on Crabbox `macos`, `ubuntu`, and `windows-native`; see [`platform-smoke.md`](platform-smoke.md). Target artifacts include Crabbox/provider/work-root metadata, and release review also checks provider-specific `crabbox list` commands for leftover leases/clones. | **Earlier 0.36.0 / package 0.6.2 / Pi 0.84.4:** Ubuntu `platform-build` and `browser-dogfood-smoke` passed with 11/11 assertions each on 2026-09-01, including complete artifact manifests and lease cleanup. Under explicit GitHub-only release waivers, macOS SSH and native Windows were not run because localhost SSH and `prlctl` were unavailable. |
149
151
  | `verify -- release` / `prepublishOnly` | `npm run verify -- release` chains the default gate with the configured-source lifecycle harness, packaged Pi smoke, and the release-blocking Crabbox platform matrix (`verifySteps` `release` in [`scripts/project.mjs`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/scripts/project.mjs)). `package.json` `prepublishOnly` runs that compose before `npm pack --dry-run` during `npm publish`. It intentionally omits standalone real-upstream and host-only dogfood modes—see [`RELEASE.md`](RELEASE.md#pre-release-checks). | **Package 0.6.2:** on 2026-09-01 the default, lifecycle, package-Pi, startup, real-upstream, deterministic dogfood, harness, Ubuntu image, and Ubuntu target gates passed individually. The canonical full composition was not reported as passed because macOS SSH and native Windows were explicitly waived after doctor confirmed localhost SSH and `prlctl` were unavailable. That historical release created GitHub artifacts only; it did not authorize npm publishing. |
150
- | Configured-source lifecycle | `npm run verify -- lifecycle` (`scripts/verify-lifecycle.mjs`) drives `/reload`, closes and relaunches Pi with the same exact `--session-id`, checks the JSONL session header id, session continuity, slash-command sentinel tokens (`v1` before reload and `v2` after full relaunch), persisted spill reachability, and real Pi `tool_result` failure-patch semantics for a QA reclassification with a fake upstream on `PATH`. Default Pi model is `zai/glm-5.2`; default per-step wait is **180000 ms** (`DEFAULT_TIMEOUT_MS`); override model with `--model <id>` and waits with `--timeout-ms <ms>`. Passthrough flags in [`scripts/project.mjs`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/scripts/project.mjs): `--keep-artifacts`, `--model`, `--verbose`, and `--timeout-ms` plus a value (for example `npm run verify -- lifecycle --model openai-codex/gpt-5.5:minimal --keep-artifacts --verbose --timeout-ms 600000`). | **Pi 0.84.4 on 2026-09-01:** pass; `/reload`, exact-session relaunch, managed continuity, persisted spill reachability, and Pi failure-patch behavior all verified. |
152
+ | Configured-source lifecycle | `npm run verify -- lifecycle` (`scripts/verify-lifecycle.mjs`) drives `/reload`, closes and relaunches Pi with the same exact `--session-id`, checks the JSONL session header id, session continuity, slash-command sentinel tokens (`v1` before reload and `v2` after full relaunch), persisted spill reachability, and native returned failure status and JSON preservation for a QA reclassification with a fake upstream on `PATH`. Default Pi model is `zai/glm-5.2`; default per-step wait is **180000 ms** (`DEFAULT_TIMEOUT_MS`); override model with `--model <id>` and waits with `--timeout-ms <ms>`. Passthrough flags in [`scripts/project.mjs`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/scripts/project.mjs): `--keep-artifacts`, `--model`, `--verbose`, and `--timeout-ms` plus a value (for example `npm run verify -- lifecycle --model openai-codex/gpt-5.5:minimal --keep-artifacts --verbose --timeout-ms 600000`). | **Pi 0.84.4 on 2026-09-01:** pass; `/reload`, exact-session relaunch, managed continuity, persisted spill reachability, and Pi failure status all verified. |
151
153
  | Quick isolated Pi smoke | `pi --approve --no-extensions --no-skills -e .` from trusted repo root; checkout-native browser tools only. | **Earlier 0.36.0 / package 0.6.2 / Pi 0.84.4:** isolated checkout tmux smoke passed on 2026-09-01; native `agent_browser` completed version, localhost open, WebMCP list/invoke, visible-text verification, and close. |
152
154
 
153
- Runtime floor note: package metadata requires Node 24.21.0 or newer, keeps optional Pi core package peer ranges wildcard per installed Pi package docs, pins direct Pi validation dependencies to 0.99.2, and makes `pi --version` below 0.87.0 a setup failure through `pi-agent-browser-doctor` / `npm run doctor`. The Pi floor follows the native tool-history/prompt APIs and includes no older-host compatibility shim.
155
+ Runtime floor note: package metadata requires Node 24.21.0 or newer, keeps optional Pi core package peer ranges wildcard per installed Pi package docs, pins direct Pi validation dependencies to 1.0.0, and makes `pi --version` below 1.0.0 a setup failure through `pi-agent-browser-doctor` / `npm run doctor`. The Pi floor follows the native tool-history/prompt APIs and includes no older-host compatibility shim.
154
156
 
155
157
  ## Baseline checklist by inventory section
156
158
 
@@ -158,7 +160,7 @@ Runtime floor note: package metadata requires Node 24.21.0 or newer, keeps optio
158
160
  | --- | --- | --- | --- | --- | --- |
159
161
  | Built-in skills | 19 canonical tokens from baseline section `skills`; see [`scripts/agent-browser-capability-baseline.mjs`](../scripts/agent-browser-capability-baseline.mjs) and generated [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#built-in-skills). | [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#built-in-skills), generated baseline block, README proof section, release docs. | `needsManagedSession` keeps read-only skills inspection sessionless while preserving thin upstream passthrough; upstream `@agent-browser/sandbox` remains external package guidance, not a bundled wrapper dependency. | Runtime and extension-validation skills/provider matrix; real-upstream inspection/skills group. | Supported. |
160
162
  | Core page, element, navigation, and extraction commands | Canonical tokens from baseline section `core-commands`; see [`scripts/agent-browser-capability-baseline.mjs`](../scripts/agent-browser-capability-baseline.mjs) and generated [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#core-page-and-element-commands). | [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#core-page-and-element-commands), [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md), README quick start. | Thin passthrough with wrapper-owned JSON/session planning, ref guidance, artifact verification, page-change summaries, click-dispatch diagnostics only after native temporary-marker target identity readback (otherwise abstaining), inspection-only recovery for upstream overlay-blocked clicks, deterministic document scroll before wheel/no-op diagnostics and instant CSS-container movement, shorthand compilers, and redaction. | Real-upstream core matrix (including snapshot-ref select) plus fake core matrix for passthrough, ordering, diagnostics, and compiler validation. | Supported. Upstream semantics remain upstream-owned. |
161
- | Sessions, state, tabs, frames, dialogs, and windows | 28 canonical tokens from baseline section `state-tabs-frames-dialogs`; see [`scripts/agent-browser-capability-baseline.mjs`](../scripts/agent-browser-capability-baseline.mjs) and generated [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#session-state-frames-dialogs-windows-and-inspection-commands). | [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#session-state-frames-dialogs-windows-and-inspection-commands), stateful workflow notes, [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details). | Stateful summaries redact credentials while preserving restore identifiers and every session/state list row; explicit targets and paths pass through. Runtime retains state artifact verification, sessionless local command planning, automatic managed restore, native-CDP-ID tab recovery across duplicate URLs and transcript replay, reached failed-batch target invalidation/live verification, active-target refresh after tab close, and close alias cleanup. | Extension tab/ref tests, real-upstream stable-id/label tab lifecycle, runtime session/resume tests, presentation redaction tests, lifecycle harness. | Supported. External profile/auth state remains operator-owned. |
163
+ | Sessions, state, tabs, frames, dialogs, and windows | 28 canonical tokens from baseline section `state-tabs-frames-dialogs`; see [`scripts/agent-browser-capability-baseline.mjs`](../scripts/agent-browser-capability-baseline.mjs) and generated [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#session-state-frames-dialogs-windows-and-inspection-commands). | [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#session-state-frames-dialogs-windows-and-inspection-commands), stateful workflow notes, [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details). | Stateful summaries redact credentials while preserving restore identifiers, every session/state list row, and ordinary `cookies set --curl` file operands in invocation echoes and failed batch diagnostics; explicit targets and paths pass through. Runtime retains state artifact verification, sessionless local command planning, automatic managed restore, native-CDP-ID tab recovery across duplicate URLs and transcript replay, reached failed-batch target invalidation/live verification, active-target refresh after tab close, and close alias cleanup. | Extension tab/ref tests, real-upstream stable-id/label tab lifecycle, runtime session/resume tests, presentation redaction tests, lifecycle harness. | Supported. External profile/auth state remains operator-owned. |
162
164
  | Network, storage, artifacts, diagnostics, and performance | Canonical tokens from baseline section `network-storage-artifacts-diagnostics`; see [`scripts/agent-browser-capability-baseline.mjs`](../scripts/agent-browser-capability-baseline.mjs) and generated [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#page-state-finding-mouse-settings-network-and-storage). | [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#page-state-finding-mouse-settings-network-and-storage), diagnostic sections, [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details). | Thin passthrough plus native-owned click/download execution for all downloads (including loopback, Blob exports, and redirects), compact diagnostics with identical credential redaction for page/origin/URL-filtered details and exports, route-mock warnings, useful-but-redacted storage output, stream idempotency normalization, FPS/cursor/contact-sheet-aware recording destinations/pinning and contact-sheet image verification, truthful ref-refresh and missing-ffmpeg warnings, positive WebMCP navigation hints and catalog updates, sensitive-data redaction, timeout bounds, and cleanup-pair guidance. | Fake non-core matrix and safe real-upstream coverage for network/HAR, diff, trace/profiler, console/errors/highlight, stream, vitals, React missing-renderer, native FPS recording path/page checks and WebMCP navigation hints. | Supported. Environment-sensitive operations need suitable local/browser state. |
163
165
  | Batch, auth, confirmations, setup, dashboard, devices, and AI commands | Canonical tokens from baseline section `batch-auth-setup-ai`; see [`scripts/agent-browser-capability-baseline.mjs`](../scripts/agent-browser-capability-baseline.mjs) and generated [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#batch-auth-confirmations-sessions-chat-dashboard-devices-and-setup). | [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#batch-auth-confirmations-sessions-chat-dashboard-devices-and-setup), README security notes, release docs. | Native-tool batch stdin, generated QA/lookup batch plans, auth/confirmation redaction, sessionless local auth/setup/dashboard/doctor/plugin planning, upgrade-only native text normalization with error precedence and explicit-JSON results, plugin list/show JSON envelope normalization, bare-`mcp` validation with `mcp --help` preserved, timeout/cleanup guidance. | Parser/runtime plugin and MCP unit coverage; fake-upstream plugin list/show and MCP help/blocking coverage; registered upgrade text/success/nonzero/timeout/abort/JSON controls in `test/agent-browser.upgrade-output.test.ts`; real-upstream plugin list shape probe; structured input-mode tests. | Supported. Interactive side-effecting setup/auth/chat remains upstream-owned. `plugin` is local/sessionless; `mcp` is external-client-only except help; `auth login --credential-provider` resolves credentials via a plugin; `install --with-deps` failures remain upstream-owned. |
164
166
  | Global flags, config, providers, policy, and environment | Canonical tokens from baseline section `options-and-env`; see [`scripts/agent-browser-capability-baseline.mjs`](../scripts/agent-browser-capability-baseline.mjs) and generated [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#important-global-flags-config-and-environment). | [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#important-global-flags-config-and-environment), README provider/setup notes, [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#sessionmode), architecture/runtime docs. | Runtime preserves caller-requested JSON for early filters, scroll results, and preparation failures without output-file prose (help/version remains native text), and handles command discovery, value-flag prevalidation, launch-scoped flags, redacted echoes, fresh-session recovery hints, explicit sessions, provider/device launch-scoping, parent env forwarding with consistent managed idle-timeout/socket/operation-timeout overrides on top-level and helper subprocesses, subprocess completion, and package-owned Pi-scoped config for optional companion features. | Runtime tests for flags/planning/redaction/session behavior; process/ref tests for env consistency and stdio-linger completion; config/web-search/CLI tests; fake provider/specialized-skill matrix; package doctor. | Supported. Provider clouds, iOS/Appium, proxies, profiles, and credentials require external setup. |
@@ -16,7 +16,9 @@ The extension synchronously registers a `browser` instruction group through the
16
16
 
17
17
  Group enablement reveals selected declarations and instructions, not callable permissions. `agent_browser_tools` remains the separate advanced-tool activation path. Existing host selections, exclusions, namespaces, and restored tool history are unchanged.
18
18
 
19
- Pi 0.87.0 or newer is required; official and fork qualification is independent. Five specialized tools are registered but initially inactive: `agent_browser_action`, `agent_browser_qa`, `agent_browser_electron`, `agent_browser_source`, and `agent_browser_network_source`. Explicit CLI allowlists, filtered SDK catalogs, and restored Pi tool history are respected. Omit CLI `--tools` for lazy activation, or include every desired advanced tool in its allowlist; the loader reports excluded tools as unavailable rather than bypassing host selection. Pi 0.87 does not distinguish an SDK explicitly selecting the complete browser catalog from its default catalog; SDK hosts choosing activation for that complete catalog can call `session.setActiveToolsByName(...)` after `bindExtensions()`.
19
+ Pi 1.0.0 or newer is required; official and fork qualification is independent. Five specialized direct tools declare native `defaultActive: false`: `agent_browser_action`, `agent_browser_qa`, `agent_browser_electron`, `agent_browser_source`, and `agent_browser_network_source`. They require activation unless selected by the host; they are not deferred tools. Explicit CLI allowlists, SDK selections/defaultTools, loader activation, restored tool history, tree navigation and reload are respected. Omit CLI `--tools` for lazy activation, or include every desired advanced tool in its allowlist; the loader reports excluded tools as unavailable rather than bypassing host selection.
20
+
21
+ Official Pi 1.0's initial SDK resume supplies an initial tool selection that bypasses native transcript restoration. The extension retains a narrow additive resume fallback for available advanced tools; it never deactivates host-selected tools or bypasses an explicit allowlist/filtered catalog. Remove that fallback only when the minimum supported official host restores this state natively.
20
22
 
21
23
  ## Why this tool shape
22
24
 
@@ -55,7 +57,7 @@ Supplying the callback registers `agent_browser` with Pi's native `executionMode
55
57
 
56
58
  ## Optional companion web search
57
59
 
58
- `agent_browser_web_search` is a separate custom tool, not an `agent_browser` input mode. It is available when the extension can see at least one configured/resolvable Exa or Brave credential source from `~/.pi/config/pi-agent-browser-native/config.json`, `.pi/config/pi-agent-browser-native/config.json`, `PI_AGENT_BROWSER_CONFIG`, or the `EXA_API_KEY` / `BRAVE_API_KEY` environment fallbacks, and runtime execution still checks that the final available merged config has not set `webSearch.enabled` to `false`. Config layers merge global → project → `PI_AGENT_BROWSER_CONFIG` override; under Pi 0.84.0+, globally installed and CLI-loaded copies read `.pi/config/...` when Pi trust allows that project layer, and they skip the project layer when Pi reports the project is untrusted or when launched with `--no-approve`. Disable scope is explicit: a global disable is a normal user default, a project disable applies to one repo, and an override file with `webSearch.enabled: false` is the highest-priority hard disable for that run. Credential sources may be plaintext, `$ENV_VAR` / `${ENV_VAR}` interpolation, escaped literals, or command sources such as `"!op read 'op://Private/Exa/API Key'"` from any loaded config layer; they make the tool available without exposing the value in status text, and command values resolve when the tool executes. Browser profile/executable config uses the same paths and emits prompt guidance from the highest-priority loaded layer, including project config when that layer is loaded.
60
+ `agent_browser_web_search` is a separate custom tool, not an `agent_browser` input mode. It is available when the extension can see at least one configured/resolvable Exa or Brave credential source from `~/.pi/config/pi-agent-browser-native/config.json`, `.pi/config/pi-agent-browser-native/config.json`, `PI_AGENT_BROWSER_CONFIG`, or the `EXA_API_KEY` / `BRAVE_API_KEY` environment fallbacks, and runtime execution still checks that the final available merged config has not set `webSearch.enabled` to `false`. Config layers merge global → project → `PI_AGENT_BROWSER_CONFIG` override; globally installed and CLI-loaded copies read `.pi/config/...` when Pi trust allows that project layer, and they skip the project layer when Pi reports the project is untrusted or when launched with `--no-approve`. Disable scope is explicit: a global disable is a normal user default, a project disable applies to one repo, and an override file with `webSearch.enabled: false` is the highest-priority hard disable for that run. Credential sources may be plaintext, `$ENV_VAR` / `${ENV_VAR}` interpolation, escaped literals, or command sources such as `"!op read 'op://Private/Exa/API Key'"` from any loaded config layer; they make the tool available without exposing the value in status text, and command values resolve when the tool executes. Browser profile/executable config uses the same paths and emits prompt guidance from the highest-priority loaded layer, including project config when that layer is loaded.
59
61
 
60
62
  Prefer it for live/current external web facts, current docs/news, and candidate URLs. Prefer it over browser-driving public search-engine forms such as Google: headless typing flows may be redirected to anti-bot or CAPTCHA pages, and agents should use search API results, then `agent_browser` on a target URL, instead of attempting CAPTCHA bypass. Use `agent_browser` when the task needs browser interaction, screenshots, authenticated/profile content, page inspection, or DOM work. The search tool is namespaced to avoid colliding with generic `web_search`, chooses Exa or Brave automatically from available credentials, defaults to Exa when both are available (unless `webSearch.preferredProvider` is set), and must not expose resolved API keys in content, details, errors, status output, docs examples, logs, or PR artifacts.
61
63
 
@@ -132,7 +134,7 @@ Result details:
132
134
  }
133
135
  ```
134
136
 
135
- For Exa, `details.searchType` is the effective requested type even when the provider response does not echo it. `requestId` is included when Exa returns one. Brave omits both fields. `pageDate` comes from Exa `publishedDate` (an estimated page creation date) or Brave `page_age`; Brave may separately return `age`. These provider fields are not crawl/retrieval age or proof that a result matches a requested version. For version-sensitive work, inspect the result, constrain one follow-up to the primary domain (`includeDomains` for Exa or `site:` in a Brave query), and read the primary page.
137
+ For Exa, `details.searchType` is the effective requested type even when the provider response does not echo it. `requestId` is included when Exa returns one. Brave omits both fields. `pageDate` comes from Exa `publishedDate` (an estimated page creation date) or Brave `page_age`; Brave may separately return `age`. These provider fields are not crawl/retrieval age or proof that a result matches a requested version. For version-sensitive work, inspect the result, constrain one follow-up to the primary domain (`includeDomains` for Exa or `site:` in a Brave query), and read the primary page. Failures return structured results: local config/validation problems (invalid config, disabled tool, missing credential, blank query, Exa-only filters resolved to Brave) are `validation-error`; provider/network failures are `upstream-error`; both keep `isError` and redacted messages.
136
138
 
137
139
  ## Input mode chooser
138
140
 
@@ -319,7 +321,7 @@ The browser persists between code and direct calls. JavaScript variables do not.
319
321
 
320
322
  Inner calls are serialized, including calls issued with `Promise.all`. The maximum is 25 attempted calls, 64 KiB emitted JSON, 1 MiB per IPC message, and 8 MiB cumulative IPC. Inner execution keeps full redacted data without full model rendering/spilling/image encoding; only selected outer output is rendered. An observation that cannot fit the bridge limit fails rather than silently discarding recovery or fabricating data.
321
323
 
322
- Source runs in a fresh permissioned Node child with an empty child environment, 64 MiB V8 heap ceiling, and a VM context whose string/WebAssembly code generation is disabled. Task globals have null prototypes and JSON-only IPC; no parent promise/object/function is exposed. There are no host filesystem, network, process, import, or timer APIs. This language boundary is separate from native browser capabilities: parent-side browser subprocesses still receive ordinary auth/config/environment. `node:vm` alone is not a security boundary, and this contract is not a universal sandbox certification.
324
+ Source runs in a fresh permissioned Node child with an empty child environment, 64 MiB V8 heap ceiling, and a VM context whose string/WebAssembly code generation is disabled. Task globals have null prototypes and JSON-only IPC; no parent promise/object/function is exposed. There are no host filesystem, network, process, import, or timer APIs. When Pi itself runs as a Bun-compiled binary, the child is hosted by a real `node` runtime from `PATH`; if none is available the call fails as `missing-binary` with that exact remediation instead of hanging the handshake. This language boundary is separate from native browser capabilities: parent-side browser subprocesses still receive ordinary auth/config/environment. `node:vm` alone is not a security boundary, and this contract is not a universal sandbox certification.
323
325
 
324
326
  #### Failure and persistence
325
327
 
@@ -528,7 +530,9 @@ These calls return plain text and stay stateless: the extension does not inject
528
530
 
529
531
  ### Canonical observation
530
532
 
531
- Direct and advanced results expose the same decision-relevant observation in model-visible JSON or prose; code receives it as data without rendering/reparsing prose. The base is `{ success, resultCategory, data?, error?, summary?, successCategory?, failureCategory? }`. Optional fields include exact `nextActions`, warnings, session/namespace, artifact verification, image observations, page-change evidence, timeout partial progress, and QA/source/diagnostic results. Batch observations retain per-step outcomes. Native help/version remains plain text.
533
+ Direct and advanced results expose the same decision-relevant observation in model-visible JSON or prose; code receives it as data without rendering/reparsing prose. The base is `{ success, resultCategory, data?, error?, summary?, successCategory?, failureCategory? }`; `summary` is omitted when it is byte-identical to `error` so large failure text is not counted twice. Optional fields include exact `nextActions`, warnings, session/namespace, artifact verification, image observations, page-change evidence, timeout partial progress, and QA/source/diagnostic results. Batch observations retain per-step outcomes. Native help/version remains plain text.
534
+
535
+ Tool declarations share native Browser namespace metadata and an `outputSchema`. Returned `structuredContent` exposes the same bounded redacted projection, including failed/preparation/cancelled results, rather than raw internal `details`. Oversized observations use the existing compact object and complete redacted spill path. The loader returns `{ inventory, added }`; optional search returns its normalized provider data in the observation's `data`. This supports host-selected native codemode without auto-enabling it, changing advanced activation, or replacing the Browser code VM. Structured image paths/handles are metadata, not native `image()` input; retain verified Pi image blocks and current-cell `emitImage` semantics.
532
536
 
533
537
  `details` retains audit, process, ownership, and replay metadata; it is not the sole channel for actionable failures. JSON remains parseable, including early preparation failures and filters. Prose retains useful command output and appends canonical observation metadata. Final visible text is bounded to 16,000 characters. If necessary, the complete redacted observation is spilled and the result names `observationPath` plus retrieval instructions. Exact recovery objects are either included whole or remain in that complete observation; truncated argv/stdin is never presented as executable recovery. An unavailable spill is reported honestly.
534
538
 
@@ -600,7 +604,7 @@ These categories are intentionally bounded and stable so agents can branch on th
600
604
 
601
605
  For argv-supplied `--allowed-domains`, the wrapper treats domain containment as launch-scoped. Upstream owns request, worker, popup, and WebRTC containment plus incompatible-mode rejection; the wrapper passes the setting and upstream result through unchanged.
602
606
 
603
- Real Pi custom tools only mark a tool result failed when the tool throws during `execute`; returned `isError` fields are not authoritative. The extension therefore also registers a `tool_result` handler for the direct, code, and advanced browser tools that treats a result with `details.resultCategory: "failure"` as a real Pi tool error. For normal prose output, it appends `Result category: failure; failureCategory: …; Pi tool isError: true.` to model-visible text. For caller-requested `--json` output, it only patches `isError` and preserves visible parseable JSON content unchanged. The TUI renderer also repeats that category line at the top of failed rendered results so collapsed failed rows keep the outcome visible. The hook treats `--json` as requested when echoed `details.args` or the original tool `input.args` includes that flag; it skips appending the prose notice when any non-empty text content item is parseable JSON, even if other text items are not parseable. Invalid or non-JSON text still gets the visible prose notice. Implementation: `buildAgentBrowserToolResultPatch` in `extensions/agent-browser/lib/pi-tool-rendering.ts`; `extensions/agent-browser/index.ts` registers the handler. This keeps Pi transcript semantics aligned with the machine-readable result contract, including wrapper-side reclassifications such as `qa-failure` after an upstream-successful batch and `artifact-missing` after an upstream-successful artifact command whose requested file is absent.
607
+ Final public results return canonical `isError: true` when `resultCategory` is `failure`; Pi 1.0 honors that return without a `tool_result` repair hook. For normal prose, finalization appends `Result category: failure; failureCategory: …; Pi tool isError: true.` to model-visible text. Explicit parseable JSON remains unchanged, including code JSON and preparation failures; invalid/non-JSON text retains the notice. The TUI also shows the category at the top of failed rendered results so collapsed rows keep the outcome visible. Shared finalization lives in `lib/native-output.ts` and `finalizeAgentBrowserFailure` in `lib/pi-tool-rendering.ts`. This keeps transcript, UI and structured outcomes aligned after wrapper-side reclassification such as `qa-failure` or `artifact-missing`.
604
608
 
605
609
  For `batch`, top-level `details` still carries `resultCategory` plus `successCategory` or `failureCategory` for the **aggregate** tool outcome: if any step fails, the overall result is a failure (`resultCategory: "failure"`) even when later steps succeed—inspect `batchSteps[]` for per-step outcomes. Each `batchSteps[]` entry includes its own `resultCategory` and either `successCategory` or `failureCategory` for that step. When upstream reports it, successful and failed rows also expose a dedicated `lifecycle` field containing only the bounded `effectiveLaunch.browserLaunched` boolean; on failed rows this preserves launch evidence even though the ordinary result payload is omitted. Live state and transcript replay use that evidence to distinguish a terminal nested close from a post-close browser launch. `batchFailure.failedStep` duplicates the first failing step’s details, including its `failureCategory`, bounded lifecycle evidence, and any `nextActions`.
606
610
 
@@ -614,7 +618,7 @@ Ref preflight details (command taxonomy in `extensions/agent-browser/lib/command
614
618
  - **URL alignment:** `refSnapshot.target.url` and the session’s current tab URL are compared via `targetsMatch` / `normalizeComparableUrl` in `extensions/agent-browser/index.ts`: values are trimmed, parsed as URLs when possible, compared **after dropping the `#fragment`**, and the query string remains significant. If either side lacks a `url`, `targetsMatch` treats the pair as matching so early-session calls are not blocked.
615
619
  - **Batch stdin ordering:** user `batch` JSON is scanned in order. Any step whose first token satisfies `isRefInvalidatingBatchCommand` sets a latch that blocks later steps whose first token satisfies `isRefGuardedCommand` and that mention `@e…` refs, except for same-snapshot native form-control steps whose current snapshot role metadata identifies all refs as safe controls (`check`/`uncheck` or direct `click`/`tap` on checkbox or radio refs, and `select` on combobox refs). A step whose first token is `snapshot` clears that latch for subsequent steps (pre-spawn intent only; it does not wait for upstream success). These predicates read explicit command capability flags from `command-taxonomy.ts`: navigation/mutation verbs such as `open` / `goto`, `reload`, non-form `click`, and related upstream commands have `invalidatesBatchRefs`, and `record start` steps (any outcome), `record restart` steps with a URL operand, plus WebMCP `invoke` / `result` / `cancel` steps also set the latch because upstream swaps or navigates the active page; same-snapshot `fill` rows and the role-checked native form-control rows stay guarded against missing/stale refs but do not set the latch, allowing ordinary form batches before a final click/submit step. Direct `click`/`tap @e…` is only treated as a safe form-control row when every ref in that step is a latest-snapshot checkbox or radio; other click/tap refs remain invalidating. Ref-guarded commands accept page-scoped refs for interaction (`click`, `fill`, `download`, `scrollintoview` / `scrollinto`, and others centralized in the command taxonomy). Changing either capability requires updating this contract, [`docs/SUPPORT_MATRIX.md`](SUPPORT_MATRIX.md) `RQ-0072`/`RQ-0087` notes, README and command-reference pitfalls, and `test/agent-browser.extension-validation.test.ts`.
616
620
 
617
- **Presentation redaction (implementation map):** Successful non-`batch` tool calls and each successful `batchSteps[]` row run upstream `data` through `redactPresentationData` in `extensions/agent-browser/lib/results/presentation/diagnostics.ts`: `cookies` still walk objects/arrays and replace case-insensitive `value` keys with `"[REDACTED]"`; `storage` redacts values when the key or value looks credential-like (token, cookie, auth, secret, JWT, bearer/basic credential, high-entropy token-like string, or nested sensitive JSON) but keeps low-risk primitive QA values such as booleans, numbers, and short strings visible. Redacted storage entries add `valueRedacted` plus `valueRedactionReason` in `details.data`; diagnostic formatters mirror the same decision. Every other command’s payload is recursively scrubbed with the shared `redactSensitiveValue`, which redacts known sensitive key names and applies string-level sensitivity heuristics so network, diff, trace/profiler, stream, dashboard, chat, and other structured results do not echo bearer tokens, proxy credentials, or similar fields verbatim into `details.data`. Echoed `command` arrays in `details` and in batch roll-ups use `redactInvocationArgs` from `extensions/agent-browser/lib/runtime.ts` to mask trailing values for sensitive global flags (including `--body`, `--headers`, `--password`, and `--proxy`), preserve the special positional rules for `cookies set`, `storage local|session set`, and `set credentials`, and scrub other argv tokens for URLs and inline secrets. Raw batch row strings are parsed and command-redacted for presentation and ordered intent/completion journals; execution argv remains unchanged. Failed batch steps additionally run `redactExactValues` on structured step errors so literals taken from that step’s argv (cookie value, storage set value, `--password` / `--password=` tokens) cannot reappear inside formatted error blobs. When the full batch is large enough to need its own aggregate spill, that spill reapplies these per-command data and argv redactors before persistence rather than using generic batch redaction.
621
+ **Presentation redaction (implementation map):** Successful non-`batch` tool calls and each successful `batchSteps[]` row run upstream `data` through `redactPresentationData` in `extensions/agent-browser/lib/results/presentation/diagnostics.ts`: `cookies` still walk objects/arrays and replace case-insensitive `value` keys with `"[REDACTED]"`; `storage` redacts values when the key or value looks credential-like (token, cookie, auth, secret, JWT, bearer/basic credential, high-entropy token-like string, or nested sensitive JSON) but keeps low-risk primitive QA values such as booleans, numbers, and short strings visible. Redacted storage entries add `valueRedacted` plus `valueRedactionReason` in `details.data`; diagnostic formatters mirror the same decision. Every other command’s payload is recursively scrubbed with the shared `redactSensitiveValue`, which redacts known sensitive key names and applies string-level sensitivity heuristics so network, diff, trace/profiler, stream, dashboard, chat, and other structured results do not echo bearer tokens, proxy credentials, or similar fields verbatim into `details.data`. Echoed `command` arrays in `details` and in batch roll-ups use `redactInvocationArgs` from `extensions/agent-browser/lib/runtime.ts` to mask trailing values for sensitive global flags (including `--body`, `--headers`, `--password`, and `--proxy`), preserve the special positional rules for `cookies set`, `storage local|session set`, and `set credentials` (native `cookies set --curl <file>` imports are file operands, so ordinary import paths remain visible in echoes and failed batch diagnostics), and scrub other argv tokens for URLs and inline secrets. Raw batch row strings are parsed and command-redacted for presentation and ordered intent/completion journals; execution argv remains unchanged. Failed batch steps additionally run `redactExactValues` on structured step errors so literals taken from that step’s argv (cookie value, storage set value, `--password` / `--password=` tokens) cannot reappear inside formatted error blobs. When the full batch is large enough to need its own aggregate spill, that spill reapplies these per-command data and argv redactors before persistence rather than using generic batch redaction.
618
622
 
619
623
  `nextActions` is an optional list of exact follow-ups. Each entry has a `tool`, `id`, `reason`, optional `safety`, and executable `params` or an `artifactPath`. Native actions use `agent_browser` with argv/stdin; Electron and network-source actions use their actual advanced tool name and flat params. Enable the corresponding capability with `agent_browser_tools` if needed. Both prose and JSON expose recovery; oversized observations retain complete payloads in the named observation spill rather than inventing shortened calls.
620
624
 
@@ -695,7 +699,7 @@ Additional structured fields can appear when relevant:
695
699
  - `attachedBrowserSession: true` on successful calls that establish or reuse a wrapper-tracked CDP/auto-connect/Electron attachment, and on a failed fresh attachment only when `managedSessionOutcome.activeAfter` proves its daemon remained active for cleanup. The marker restores attachment continuity from the active transcript branch, including that active-after-failure case; live state and transcript replay remove it after a terminal successful close/cleanup even when aggregate verification failed; a close followed by a later step whose lifecycle reports a browser launch preserves it, while a successful non-launching diagnostic leaves the close terminal. Caller config, environment, paths, and file-access settings remain upstream-owned; the marker only adds live-URL verification and lifecycle continuity.
696
700
  - `lifecycle: { effectiveLaunch: { browserLaunched } }` when upstream returned that boolean. It separates starting the requested `agent-browser` CLI process from the effective Chrome session context. `readSource` exposes upstream's string `data.source` for direct `read` calls and identifies the raw HTTP fetch path; its lifecycle boolean can be `false` before a browser launch or `true` when the same managed session already has an active browser. Direct reads also append one visible `Read execution` line with the source, CLI-start result, managed browser lifecycle, and managed-session outcome so Pi models do not have to infer model-invisible details.
697
701
  - `browserWindow: { mode: "headed", ownership: "wrapper-managed", sessionName, visibility: "unverified" }` only after a successful first/fresh local wrapper-managed headed call (including `batch`) that is not an attachment and whose lifecycle proves a browser launched and whose managed-session outcome is `created` or `replaced`. One visible handoff sentence tells the user to complete the login in that window if they can see it, then continue with `sessionMode: "auto"`; the field never claims OS desktop visibility.
698
- - `sessionTabTarget` retains the observed `url`, optional `title`, and native CDP `targetId` when available. When an observed page lacks a native ID, a read-only `tab list` observes current identity; earlier commands and equal URLs cannot supply it. If another tab matches the observed URL while the active tab does not, existing URL-based drift recovery selects the matching tab instead of attaching the unrelated active ID. Resume and branch recovery select that exact target, even when several tabs share an address/title; a missing known ID never falls back to another same-address tab. Older transcripts without an ID retain URL-based recovery. An existing cold-managed-browser reopen records its new native ID. `sessionTabCorrection.selectionKind` can be `targetId`, `tabId`, `label`, or `index`.
702
+ - `sessionTabTarget` retains the observed `url`, optional `title`, and native CDP `targetId` when available. When an observed page lacks a native ID, a read-only `tab list` observes current identity; earlier commands and equal URLs cannot supply it. If another tab matches the observed URL while the active tab does not, existing URL-based drift recovery selects the matching tab instead of attaching the unrelated active ID. Resume and branch recovery select that exact target, even when several tabs share an address/title; a missing known ID never falls back to another same-address tab. Older transcripts without an ID retain URL-based recovery. An existing cold-managed-browser reopen records its new native ID. `sessionTabCorrection.selectionKind` can be `targetId`, `tabId`, `label`, or `index`. `sessionTabCorrection` records an applied tab selection (before the command or during post-command recovery), not proof of the final page or successful later recovery. Use `sessionTabTarget` for the final observed position and `aboutBlankSessionMismatch.recoveryApplied` for the recovery outcome; the historical correction may remain when that recovery fails.
699
703
  - `sessionTabTargetUnknown: true` after a spawned `connect`, `state load`, history navigation, tab-selection/close, `window new`, or `diff url` call changes the active page without a trustworthy observed target. Direct `window new` / `diff url` and reached native batch rows retire the old target and refs; an intentional new blank window or an observed blank URL-diff destination never triggers old-tab recovery. URL diff inputs do not prove the final URL after redirects. Successful tab creation/selection/close, including dispatched batch rows, live-probes URL and a fresh non-blank title before state is committed, even when the new tab shares the prior URL; new blank tabs, explicitly selected `about:blank` tabs, and post-close blank targets are retained. It is persisted and restored across branch/reload replay, clears stale refs and tab pinning, and blocks page inspection until `get url` or explicit navigation observes a target; `tab list`, tab selection, close, and blocking-dialog `status` / `accept` / `dismiss` remain available. A timeout against an unknown target removes standalone snapshot actions and returns `verify-page-target-after-timeout`, a session-scoped `batch --bail` whose stdin runs `get url` before `snapshot -i`.
700
704
  - `compiledSemanticAction` when the call used `agent_browser_action` and the result includes the unified `details` merge: `{ action, locator, args }` for `find` actions or `{ action: "select", selector?, locator?, values, args }` for `select`, with the same redaction rules as `args` / `effectiveArgs`; omitted for plain direct native calls and omitted on some early error returns that omit this field (see the `agent_browser_action` section above)
701
705
  - `compiledJob` is internal QA batch-plan metadata: `{ args: ["batch", "--bail"], failFast: true, stdin, steps }`, with redacted step argv. It does not expose a public job input or compiler.