@arnilo/prism 0.0.8 → 0.0.96

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.
@@ -110,7 +110,7 @@ export interface SseEvent {
110
110
  }
111
111
 
112
112
  export class ProviderTransportError extends Error {
113
- readonly code: "sse_buffer_overflow" | "sse_event_overflow" | "response_body_overflow" | "aborted";
113
+ readonly code: "sse_buffer_overflow" | "sse_event_overflow" | "response_body_overflow" | "aborted" | "invalid_json_arguments" | "incomplete_delta";
114
114
  readonly limitBytes?: number;
115
115
  }
116
116
 
@@ -131,6 +131,12 @@ export function parseJsonObjectArguments(
131
131
  text: string,
132
132
  options?: { toolName?: string; maxBytes?: number },
133
133
  ): JsonObject;
134
+
135
+ /** Non-throwing variant for recoverable tool-call recovery; prefer with \`toolCallFromArgumentsText\`. */
136
+ export function tryParseJsonObjectArguments(
137
+ text: string,
138
+ options?: { toolName?: string; maxBytes?: number },
139
+ ): { ok: true; value: JsonObject } | { ok: false; error: ProviderTransportError };
134
140
  ```
135
141
 
136
142
  **Performance:** Single pass over chunks; retained memory is `O(min(buffer, maxBufferBytes))`, not `O(stream)`. No full-stream accumulation.
@@ -2,13 +2,13 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- Prism is published as one core package, twenty-four first-party capability packages, and six pure-manifest family/profile packages. This page describes how they are packed, what each tarball contains, how to install them, the required `@arnilo/prism` peer dependency, the release workflow, and the offline test budget.
5
+ Prism is published as one core package, twenty-five first-party capability packages, and six pure-manifest family/profile packages. This page describes how they are packed, what each tarball contains, how to install them, the required `@arnilo/prism` peer dependency, the release workflow, and the offline test budget.
6
6
 
7
7
  Core package:
8
8
 
9
9
  - `@arnilo/prism` — the runtime, contracts, registries, streaming events, CLI (including `prism init`), and the `/docs` hub. `files`: `dist` (with `!dist/__tests__` and `!dist/**/*.map` negations), `docs`, `templates`, `CHANGELOG.md`. `bin`: `prism` -> `dist/cli.js`. `sideEffects`: `["dist/cli.js"]`.
10
10
 
11
- First-party workspace packages (each has non-optional `@arnilo/prism@0.0.8` peer and `sideEffects: false`; RAG also peers on memory, and server also peers on workflows):
11
+ First-party workspace packages (each has non-optional `@arnilo/prism@0.0.96` peer and `sideEffects: false`; RAG also peers on memory, and server also peers on workflows):
12
12
 
13
13
  - `@arnilo/prism-provider-openai`, `@arnilo/prism-provider-openrouter`, `@arnilo/prism-provider-kimi`, `@arnilo/prism-provider-zai`, `@arnilo/prism-provider-opencode-go`, `@arnilo/prism-provider-neuralwatt` — provider adapters.
14
14
  - `@arnilo/prism-provider-ai-sdk` — optional AI SDK `LanguageModelV4` adapter; included by the provider and all umbrellas.
@@ -27,6 +27,7 @@ First-party workspace packages (each has non-optional `@arnilo/prism@0.0.8` peer
27
27
  - `@arnilo/prism-server` — optional framework-free authorized Web agent/workflow routes (peers on workflows).
28
28
  - `@arnilo/prism-supervisor` — optional bounded child delegation and A2A 1.0 card/server/client interoperability.
29
29
  - `@arnilo/prism-web-tools` — optional bounded host-selected Brave/Exa search and Firecrawl Markdown/schema extraction; native fetch, no vendor SDK/browser.
30
+ - `@arnilo/prism-browser` — optional host-supplied Playwright browser tools (`browser_open`/`browser_snapshot`/`browser_act`/`browser_close`); import launches nothing; `playwright-core@1.61.0` optional peer.
30
31
 
31
32
  Family/profile packages (pure manifests, no code or `dist`; ship `README.md` and `CHANGELOG.md`; use exact hard `dependencies`):
32
33
 
@@ -36,9 +37,9 @@ Family/profile packages (pure manifests, no code or `dist`; ship `README.md` and
36
37
  - `@arnilo/prism-code` — base + coding-agent + coding-security + MCP; providers and persistence remain explicit choices.
37
38
  - `@arnilo/prism-sdk` — base + workflows + MCP + Node credentials + OpenTelemetry; providers and persistence remain explicit choices.
38
39
  - `@arnilo/prism-evals` remains optional and network-free by default; model judges are host callbacks and live credentialed gates run separately. `examples/evaluation-gate.ts` demonstrates non-zero threshold gating.
39
- - `@arnilo/prism-all` — every first-party package: code + SDK + providers + persistence + evals + memory/RAG + server + supervisor + web tools. Installation alone activates no network/listener, telemetry, database, memory, evaluation, delegation, MCP, shell, or filesystem capability.
40
+ - `@arnilo/prism-all` — every first-party package: code + SDK + providers + persistence + evals + memory/RAG + server + supervisor + web tools + browser. Installation alone activates no network/listener, telemetry, database, memory, evaluation, delegation, MCP, shell, filesystem, or browser capability.
40
41
 
41
- Profile footprint snapshot (Node 24/npm 11, lockfile graph, 2026-07-19): `base` reaches 6 first-party packages and one external dependency root (Ajv); `code` reaches 10 and three (Ajv, MCP SDK, diff); `sdk` reaches 11 and three (Ajv, MCP SDK, keyring); `all` reaches all 31 first-party manifests and seven external roots (those plus better-sqlite3, pg, and AI SDK provider types). Native database drivers stay out of base/code/sdk; both appear only in all.
42
+ Profile footprint snapshot (Node 24/npm 11, lockfile graph, 2026-07-19): `base` reaches 6 first-party packages and one external dependency root (Ajv); `code` reaches 10 and three (Ajv, MCP SDK, diff); `sdk` reaches 11 and three (Ajv, MCP SDK, keyring); `all` reaches all 32 first-party manifests and seven external roots (those plus better-sqlite3, pg, and AI SDK provider types). Native database drivers stay out of base/code/sdk; both appear only in all.
42
43
 
43
44
  Each code package's `files` array is `["dist", "!dist/__tests__", "!dist/**/*.map", "README.md", "CHANGELOG.md"]`; `README.md`, `LICENSE`, and `CHANGELOG.md` ship in every code-package tarball, the core tarball also ships the `docs/` directory, and family/profile tarballs ship `README.md` + `CHANGELOG.md` + `package.json`.
44
45
 
@@ -61,13 +62,14 @@ Consumers install the core package for the runtime and add first-party packages
61
62
  | Install everything | `npm install @arnilo/prism-all` |
62
63
  | Install core + a single provider | `npm install @arnilo/prism @arnilo/prism-provider-openai` |
63
64
  | Install bounded web research tools | `npm install @arnilo/prism @arnilo/prism-web-tools @arnilo/prism-tool-validator-json-schema` |
65
+ | Install browser automation tools | `npm install @arnilo/prism @arnilo/prism-browser playwright-core@1.61.0` |
64
66
  | Build everything (core + workspaces) | `npm run build` |
65
67
  | Run the default (network-free) test suite | `npm test` |
66
68
  | Dry-run pack core + every package | `npm run pack:dry-run` |
67
69
  | Local mirror of the release verify gate | `npm run release:dry-run` |
68
- | Validate clean tag/version/ranges and reject registry collisions | `npm run release:check -- --version 0.0.8` |
69
- | Preview deterministic publish order | `npm run release:publish -- --version 0.0.8 --dry-run --allow-dirty --allow-untagged` |
70
- | Resume interrupted tagged publication | `npm run release:publish -- --version 0.0.8 --resume --report release-artifacts/publish-report.json` |
70
+ | Validate clean tag/version/ranges and reject registry collisions | `npm run release:check -- --version 0.0.96` |
71
+ | Preview deterministic publish order | `npm run release:publish -- --version 0.0.96 --dry-run --allow-dirty --allow-untagged` |
72
+ | Resume interrupted tagged publication | `npm run release:publish -- --version 0.0.96 --resume --report release-artifacts/publish-report.json` |
71
73
  | Full SDK readiness gate (typecheck + offline tests + pack) | `npm run sdk:ready` |
72
74
 
73
75
  Public core import specifiers (from the root `exports` map):
@@ -104,7 +106,7 @@ A packed tarball contains only public compiled output and release files:
104
106
  - Code packages ship `README.md`, `LICENSE`, and `CHANGELOG.md`; family/profile packages ship `README.md` and `CHANGELOG.md`.
105
107
  - The core tarball additionally ships the full `docs/` directory (the docs hub) and `templates/init/` used by `prism init`.
106
108
  - `dist/cli.js` and the `bin` link in core.
107
- - **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.0.8.tgz`; first-party packages produce `arnilo-prism-provider-<name>-0.0.8.tgz` / `arnilo-prism-compaction-<name>-0.0.8.tgz` / `arnilo-prism-coding-agent-0.0.8.tgz`; family/profile packages produce `arnilo-prism-{providers,compaction,base,code,sdk,all}-0.0.8.tgz`. The CLI bin name `prism` is unaffected by the package name (`npx prism` still works; npm allows the bin field to differ from the package name).
109
+ - **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.0.96.tgz`; first-party packages produce `arnilo-prism-provider-<name>-0.0.96.tgz` / `arnilo-prism-compaction-<name>-0.0.96.tgz` / `arnilo-prism-coding-agent-0.0.96.tgz`; family/profile packages produce `arnilo-prism-{providers,compaction,base,code,sdk,all}-0.0.96.tgz`. The CLI bin name `prism` is unaffected by the package name (`npx prism` still works; npm allows the bin field to differ from the package name).
108
110
 
109
111
  Excluded from every tarball by `files` negation:
110
112
 
@@ -123,9 +125,9 @@ Excluded from every tarball by `files` negation:
123
125
  "name": "host-app",
124
126
  "type": "module",
125
127
  "dependencies": {
126
- "@arnilo/prism": "0.0.8",
127
- "@arnilo/prism-provider-openai": "0.0.8",
128
- "@arnilo/prism-compaction-observational-memory": "0.0.8"
128
+ "@arnilo/prism": "0.0.96",
129
+ "@arnilo/prism-provider-openai": "0.0.96",
130
+ "@arnilo/prism-compaction-observational-memory": "0.0.96"
129
131
  }
130
132
  }
131
133
  ```
@@ -135,7 +137,7 @@ Installing the provider/compaction packages without `@arnilo/prism` present prod
135
137
  ```text
136
138
  npm error code ERESOLVE
137
139
  npm error Could not resolve dependency:
138
- npm error peer @arnilo/prism@"0.0.8" from @arnilo/prism-provider-openai@0.0.8
140
+ npm error peer @arnilo/prism@"0.0.96" from @arnilo/prism-provider-openai@0.0.96
139
141
  ```
140
142
 
141
143
  ## Implementation example
@@ -168,11 +170,11 @@ For SDK readiness, run the same one-command gate directly. It composes existing
168
170
  npm run sdk:ready
169
171
  ```
170
172
 
171
- Release publication derives all 31 packages from the workspace once, validates exact `0.0.8` manifest/lockfile/internal ranges, then uses deterministic dependency order. `release:check` requires a clean commit tagged `v0.0.8` and rejects any existing registry version. `release:publish --resume` skips only registry versions whose internal dependency fingerprint matches the local manifest; conflicting versions fail closed. Each attempted package is written immediately to the JSON report, so a failed job can rerun safely. `--dry-run` still performs registry availability checks and invokes `npm publish --dry-run` with explicit public access, provenance, and `latest` tag.
173
+ Release publication derives all 32 packages from the workspace once, validates exact `0.0.96` manifest/lockfile/internal ranges, then uses deterministic dependency order. `release:check` requires a clean commit tagged `v0.0.96` and rejects any existing registry version. `release:publish --resume` skips only registry versions whose internal dependency fingerprint matches the local manifest; conflicting versions fail closed. Each attempted package is written immediately to the JSON report, so a failed job can rerun safely. `--dry-run` still performs registry availability checks and invokes `npm publish --dry-run` with explicit public access, provenance, and `latest` tag.
172
174
 
173
175
  ```bash
174
- npm run release:check -- --version 0.0.8
175
- npm run release:publish -- --version 0.0.8 --dry-run --allow-dirty --allow-untagged
176
+ npm run release:check -- --version 0.0.96
177
+ npm run release:publish -- --version 0.0.96 --dry-run --allow-dirty --allow-untagged
176
178
  ```
177
179
 
178
180
  `--allow-dirty` and `--allow-untagged` exist only for local preview; real publication and CI never pass them. npm registry calls occur only in these release preflight/publication commands, never build/test/package discovery.
@@ -183,9 +185,9 @@ Optional live smoke tests stay separate from SDK readiness because they require
183
185
  PRISM_LIVE_PROVIDER_TESTS=1 npm run test --workspaces --if-present
184
186
  ```
185
187
 
186
- ### 0.0.8 publish handoff
188
+ ### 0.0.96 publish handoff
187
189
 
188
- **Decision: GO after operator prerequisites below.** Code, tests, package graph, protected PostgreSQL CI, registry availability, packed artifacts, security gates, and dependency-ordered publication dry-run passed from the Phase 3 release-candidate tree. Clean protected-branch CI, signed commit/tag, npm authentication, OIDC attestation, and actual publication remain operator/workflow prerequisites. No package was published during readiness work.
190
+ **Decision: GO after operator prerequisites below.** Code, tests, package graph, protected PostgreSQL CI, registry availability, packed artifacts, security gates, coding/browser adversarial fixtures, Synapta Defects 1a/1b/2 (tool-call stream recovery / typed incomplete deltas / empty-candidate rejection), and dependency-ordered publication dry-run passed from the Phase 4 release-candidate tree. Clean protected-branch CI, signed commit/tag, npm authentication, OIDC attestation, protected Docker/Playwright live gates (when host-provisioned), and actual publication remain operator/workflow prerequisites. No package was published during readiness work. Scope includes coding and browser execution only; **no Office** package, binary, SDK, wrapper, docs page, test, or release gate exists.
189
191
 
190
192
  #### npm authentication prerequisite
191
193
 
@@ -193,7 +195,7 @@ The existing GitHub Actions secret `NPM_TOKEN` is used only by the publish step
193
195
 
194
196
  #### Release commit and tag
195
197
 
196
- Merge through the protected release branch, then run these commands from a clean checkout of the protected merge commit. `git push origin v0.0.8` is the workflow dispatch; there is no manual publish command.
198
+ Merge through the protected release branch, then run these commands from a clean checkout of the protected merge commit. `git push origin v0.0.96` is the workflow dispatch; there is no manual publish command.
197
199
 
198
200
  ```bash
199
201
  # Prepare and push the release commit.
@@ -202,22 +204,22 @@ npm ci
202
204
  npm run sdk:ready
203
205
  git add -A
204
206
  git diff --cached --check
205
- git commit -S -m "Release 0.0.8"
207
+ git commit -S -m "Release 0.0.96"
206
208
  git push origin HEAD
207
209
 
208
210
  # Merge/confirm protected branch CI, then check out that exact clean merge commit.
209
211
  test -z "$(git status --porcelain)"
210
212
  npm ci
211
- npm run release:check -- --version 0.0.8 --allow-untagged --report /tmp/prism-0.0.8-preflight.json
213
+ npm run release:check -- --version 0.0.96 --allow-untagged --report /tmp/prism-0.0.96-preflight.json
212
214
 
213
- git tag -s v0.0.8 -m "Prism 0.0.8"
214
- git verify-tag v0.0.8
215
- test "$(git rev-parse HEAD)" = "$(git rev-list -n 1 v0.0.8)"
216
- npm run release:check -- --version 0.0.8 --report /tmp/prism-0.0.8-tagged-preflight.json
217
- git push origin v0.0.8
215
+ git tag -s v0.0.96 -m "Prism 0.0.96"
216
+ git verify-tag v0.0.96
217
+ test "$(git rev-parse HEAD)" = "$(git rev-list -n 1 v0.0.96)"
218
+ npm run release:check -- --version 0.0.96 --report /tmp/prism-0.0.96-tagged-preflight.json
219
+ git push origin v0.0.96
218
220
  ```
219
221
 
220
- The tag workflow's only publication command is `npm run release:publish -- --version "${GITHUB_REF_NAME#v}" --resume --report release-artifacts/publish-report.json`. Latest registry preflight returned `available` for all 31 `0.0.8` versions. Publisher order is stable and dependency-safe:
222
+ The tag workflow's only publication command is `npm run release:publish -- --version "${GITHUB_REF_NAME#v}" --resume --report release-artifacts/publish-report.json`. Latest registry preflight returned `available` for all 32 `0.0.96` versions at handoff (including first publication of `@arnilo/prism-browser`). Publisher order is stable and dependency-safe:
221
223
 
222
224
  ```text
223
225
  1 @arnilo/prism
@@ -241,21 +243,22 @@ The tag workflow's only publication command is `npm run release:publish -- --ver
241
243
  19 @arnilo/prism-supervisor
242
244
  20 @arnilo/prism-tool-validator-json-schema
243
245
  21 @arnilo/prism-web-tools
244
- 22 @arnilo/prism-workflows
245
- 23 @arnilo/prism-coding-security
246
- 24 @arnilo/prism-compaction
247
- 25 @arnilo/prism-providers
248
- 26 @arnilo/prism-rag
249
- 27 @arnilo/prism-server
250
- 28 @arnilo/prism-base
251
- 29 @arnilo/prism-code
252
- 30 @arnilo/prism-sdk
253
- 31 @arnilo/prism-all
246
+ 22 @arnilo/prism-browser
247
+ 23 @arnilo/prism-workflows
248
+ 24 @arnilo/prism-coding-security
249
+ 25 @arnilo/prism-compaction
250
+ 26 @arnilo/prism-providers
251
+ 27 @arnilo/prism-rag
252
+ 28 @arnilo/prism-server
253
+ 29 @arnilo/prism-base
254
+ 30 @arnilo/prism-code
255
+ 31 @arnilo/prism-sdk
256
+ 32 @arnilo/prism-all
254
257
  ```
255
258
 
256
259
  #### Interruption and resume
257
260
 
258
- Do not create another tag or rerun packages manually. Re-run failed jobs for the same tag in GitHub Actions. The workflow invokes `release:publish --resume`: registry versions with matching names, versions, and internal dependency fingerprints are skipped; any mismatch stops the job. Retain `release-artifacts-v0.0.8` and `publish-report-v0.0.8` for audit.
261
+ Do not create another tag or rerun packages manually. Re-run failed jobs for the same tag in GitHub Actions. The workflow invokes `release:publish --resume`: registry versions with matching names, versions, and internal dependency fingerprints are skipped; any mismatch stops the job. Retain `release-artifacts-v0.0.96` and `publish-report-v0.0.96` for audit.
259
262
 
260
263
  #### Bounded post-publish smoke
261
264
 
@@ -263,9 +266,9 @@ Download the workflow artifact and run `sha256sum -c SHA256SUMS`. Then verify al
263
266
 
264
267
  ```bash
265
268
  while read -r package; do
266
- test "$(npm view "$package@0.0.8" version)" = "0.0.8"
267
- test "$(npm view "$package" dist-tags.latest)" = "0.0.8"
268
- npm view "$package@0.0.8" dist.integrity >/dev/null
269
+ test "$(npm view "$package@0.0.96" version)" = "0.0.96"
270
+ test "$(npm view "$package" dist-tags.latest)" = "0.0.96"
271
+ npm view "$package@0.0.96" dist.integrity >/dev/null
269
272
  done <<'PACKAGES'
270
273
  @arnilo/prism
271
274
  @arnilo/prism-coding-agent
@@ -279,6 +282,7 @@ done <<'PACKAGES'
279
282
  @arnilo/prism-server
280
283
  @arnilo/prism-supervisor
281
284
  @arnilo/prism-observability-opentelemetry
285
+ @arnilo/prism-provider-ai-sdk
282
286
  @arnilo/prism-provider-kimi
283
287
  @arnilo/prism-provider-neuralwatt
284
288
  @arnilo/prism-provider-openai
@@ -289,6 +293,7 @@ done <<'PACKAGES'
289
293
  @arnilo/prism-session-store-sqlite
290
294
  @arnilo/prism-tool-validator-json-schema
291
295
  @arnilo/prism-web-tools
296
+ @arnilo/prism-browser
292
297
  @arnilo/prism-workflows
293
298
  @arnilo/prism-coding-security
294
299
  @arnilo/prism-compaction
@@ -302,7 +307,7 @@ PACKAGES
302
307
  consumer="$(mktemp -d)"
303
308
  cd "$consumer"
304
309
  npm init -y >/dev/null
305
- npm install --no-audit --no-fund @arnilo/prism-all@0.0.8
310
+ npm install --no-audit --no-fund @arnilo/prism-all@0.0.96
306
311
  node --input-type=module <<'NODE'
307
312
  for (const name of [
308
313
  "@arnilo/prism", "@arnilo/prism-coding-agent", "@arnilo/prism-coding-security",
@@ -314,6 +319,7 @@ for (const name of [
314
319
  "@arnilo/prism-tool-validator-json-schema", "@arnilo/prism-workflows", "@arnilo/prism-evals",
315
320
  "@arnilo/prism-provider-ai-sdk", "@arnilo/prism-memory", "@arnilo/prism-rag",
316
321
  "@arnilo/prism-server", "@arnilo/prism-supervisor", "@arnilo/prism-web-tools",
322
+ "@arnilo/prism-browser",
317
323
  ]) await import(name);
318
324
  NODE
319
325
  ./node_modules/.bin/prism --help >/dev/null
@@ -324,12 +330,12 @@ This smoke is bounded to registry metadata, imports, CLI startup, checksums, sig
324
330
 
325
331
  #### Rollback limitations
326
332
 
327
- npm publication is not transactional and published versions are immutable. Partial publication is a resume case, not rollback. For a confirmed systemic defect after completion, deprecate every affected `@0.0.8`; restore `latest` to `0.0.3` only for the 13 previously published packages, and remove `latest` from the 12 first-publication packages. Exact `0.0.8` installs remain possible, so publish a fixed version promptly. Do not unpublish except for a security/legal emergency under npm policy.
333
+ npm publication is not transactional and published versions are immutable. Partial publication is a resume case, not rollback. For a confirmed systemic defect after completion, deprecate every affected `@0.0.96`; restore `latest` to the previous good release only where that tag already existed. Exact `0.0.96` installs remain possible, so publish a fixed version promptly. Do not unpublish except for a security/legal emergency under npm policy.
328
334
 
329
335
  ## Extension and configuration notes
330
336
 
331
- - **Required `@arnilo/prism` peer.** Every first-party package declares `peerDependencies: { "@arnilo/prism": "0.0.8" }` with no `peerDependenciesMeta` (non-optional). The range stays pinned to `0.0.8` for the 0.x series and will widen to `^1.0.0` at the 1.x stable release. Inside the workspace each package also declares `"@arnilo/prism": "file:../.."` in `devDependencies` so `npm install` resolves the peer locally; that devDependency is stripped from consumer installs and is not a runtime dependency.
332
- - **Public access.** All 31 manifests (25 code packages + 6 family/profile packages) declare `"publishConfig": { "access": "public" }`; the publisher also passes `--access public` explicitly because scoped packages otherwise default to restricted on first publish.
337
+ - **Required `@arnilo/prism` peer.** Every first-party package declares a non-optional `@arnilo/prism@0.0.96` peer (`peerDependenciesMeta` must not mark `@arnilo/prism` optional; other peers such as `playwright-core` may be optional). The range stays pinned to `0.0.96` for the 0.x series and will widen to `^1.0.0` at the 1.x stable release. Inside the workspace each package also declares `"@arnilo/prism": "file:../.."` in `devDependencies` so `npm install` resolves the peer locally; that devDependency is stripped from consumer installs and is not a runtime dependency.
338
+ - **Public access.** All 32 manifests (26 code packages + 6 family/profile packages) declare `"publishConfig": { "access": "public" }`; the publisher also passes `--access public` explicitly because scoped packages otherwise default to restricted on first publish.
333
339
  - **Map retention knob.** Source maps are emitted locally but stripped from tarballs by `!dist/**/*.map`. Removing that `files` negation ships maps in releases (larger tarballs, better consumer stack traces).
334
340
  - **Release workflow.** `.github/workflows/release.yml` has six jobs. `verify` runs network-free SDK readiness on Node 24; `node20-compat` builds/imports every public root `exports` default target on Node 20 for declared `engines.node >=20` (docs examples need Node >=22.6 native TypeScript stripping); `postgres-integration` uses `pgvector/pgvector:pg16`; `supply-chain` runs high-severity audit, SPDX/license policy, and tracked-source secret scanning; and tag-only `codeql-release` runs SAST. Tag-only `publish` needs all five gates, preserves clean exact-tag/version/topological publication, and alone receives `NPM_TOKEN`, `id-token: write`, and `attestations: write`. Before npm publish it packs all current tarballs, generates checksums plus SPDX, scans unpacked public artifacts, creates GitHub attestations for tarballs and SBOM, then retains artifacts for 30 days. Registry state remains the resumable journal. Local `npm run release:dry-run` remains network-free SDK readiness; local PostgreSQL coverage is `PRISM_TEST_POSTGRES_URL=... npm run test:postgres`.
335
341
  - **Adding a package.** New workspace packages are picked up automatically by `npm run build --workspaces`, `npm test --workspaces`, `npm run pack:dry-run`, the packaging guard (`src/__tests__/packaging.test.ts`), and the install-smoke test (`src/__tests__/install-smoke.test.ts`) via the workspace glob; add the package to both tests' config arrays for explicit per-package assertions.
@@ -346,6 +352,8 @@ npm publication is not transactional and published versions are immutable. Parti
346
352
  - `NEURALWATT_API_KEY` for `@arnilo/prism-provider-neuralwatt`
347
353
  - `OPENCODE_API_KEY` for `@arnilo/prism-provider-opencode-go`
348
354
  - `PRISM_LIVE_WEB=1` — gates `@arnilo/prism-web-tools` restricted live tests; provider calls additionally require `PRISM_BRAVE_SEARCH_TOKEN`, `PRISM_EXA_API_KEY`, or `PRISM_FIRECRAWL_API_KEY`. Run `npm run test:live -w @arnilo/prism-web-tools`; default tests use injected fake fetch only.
355
+ - `PRISM_TEST_PLAYWRIGHT=1` or `PRISM_LIVE_PLAYWRIGHT=1` — gates `@arnilo/prism-browser` protected Playwright adversarial matrix (`npm run test:live -w @arnilo/prism-browser`). Host must supply a pinned Chromium binary via `playwright-core`. Default tests use fake Playwright APIs only; enabled but missing browser fails closed.
356
+ - `PRISM_TEST_DOCKER_SANDBOX=1` — gates `@arnilo/prism-coding-security` protected Docker matrix. Requires host-preloaded digest-pinned `PRISM_TEST_DOCKER_IMAGE` and absolute `PRISM_TEST_DOCKER_BIN` (optional `PRISM_TEST_DOCKER_USER`). Prism never pulls/builds the image during default tests. Missing prerequisites fail closed when the gate is enabled; disabled gate skips safely.
349
357
  - `PRISM_LIVE_CANARIES=1` — gates `scripts/live-canary.mjs`, used only by scheduled/manual `.github/workflows/live-canaries.yml` in protected `live-canaries` environment. It requires provider endpoint/key/model, MCP endpoint/token, A2A endpoint/token, and Brave token environment entries; performs four probes plus at most one MCP session DELETE; caps provider output at one token, each response at 64 KiB, each request at 15 seconds (30 seconds hard), and emits only aggregate kind/status/code/duration. Disabled gate skips before network; enabled but incomplete configuration fails closed.
350
358
  - `PRISM_LIVE_COMPACTION_TESTS=1` — gates `@arnilo/prism-compaction-llm`'s live summary-provider smoke test (placeholder).
351
359
  - `PRISM_LIVE_OBSERVATIONAL_MEMORY_TESTS=1` — gates `@arnilo/prism-compaction-observational-memory`'s live worker/provider checks (placeholder).
@@ -354,14 +362,32 @@ npm publication is not transactional and published versions are immutable. Parti
354
362
  - Provider live tests read the API key from the env only when both gates are set; the key is used as a bearer token and never logged. `assertNoSecretLeak` verifies the key value does not appear in any streamed event. The compaction placeholders still carry no real credentials.
355
363
  - Enforced by `network-free-guard.test.ts` (default suite stays network-free) and by source-scanning meta-tests that assert each `live.test.ts` keeps its `skip:` guard.
356
364
  - **Supply-chain workflows.** `.github/workflows/security.yml` runs CodeQL JavaScript/TypeScript SAST, PR-only dependency review, `npm audit`, SPDX 2.3 generation, exact license allow/deny policy, tracked-source plus unpacked-tarball credential-pattern scans, and seven-day SBOM retention. Dependabot opens bounded weekly npm and GitHub Actions updates. Every third-party action uses a full immutable revision; workflows never use `pull_request_target`. GitHub repository secret scanning/push protection and required-check branch rules remain repository settings because GitHub provides no equivalent checked-in workflow toggle; enable `security / codeql`, `security / supply-chain`, PR dependency review, and release checks on protected branches.
365
+ - **Sandbox/browser protected workflow.** `.github/workflows/sandbox-browser.yml` is scheduled/manual only in protected `sandbox-browser` environment. It runs network-free adversarial eval fixtures by default, optionally enables digest-pinned Docker and Playwright gates via repository variables (`PRISM_TEST_DOCKER_IMAGE`, `PRISM_ENABLE_PLAYWRIGHT_GATE`), receives no provider/npm/OIDC secrets, and uploads only a redacted aggregate status artifact (7-day retention).
357
366
  - **Release attestations.** Tag publication uses GitHub OIDC with only `contents: read`, `id-token: write`, and `attestations: write` at the publish job. `actions/attest-build-provenance` attests every `.tgz` and `sbom.spdx.json` before npm publication; npm still receives `--provenance`. Verify downloaded attestations with GitHub CLI and npm signatures on the release host.
358
367
  - **Install smoke is offline.** The install-smoke test packs core + every package into a temp dir and installs tarballs with `--offline --no-audit --no-fund` into a fresh project. External dependencies are satisfied from the lockfile-backed npm cache prepared by `npm ci`; any attempted uncached registry fetch fails the gate.
359
368
  - **Offline test budget.** The default `npm test` (no `PRISM_LIVE_PROVIDER_TESTS`) is pinned at **< 60s on Node 20** with a measured local baseline of ~45s (build ~18s + network-free tests/workspace tests/packaging smoke ~27s). The full CI `sdk:ready` gate runs on Node 24 because docs tests execute `examples/*.ts` via native TypeScript stripping. `npm run sdk:ready` also runs typecheck and pack dry-run, so it is allowed to exceed the `npm test` budget while remaining network-free. The CI `sdk:ready` step has `timeout-minutes: 5` as a hang backstop; the separate Node 20 compatibility step has `timeout-minutes: 3`. The budget was raised from 30s after the default suite grew to include every first-party package, offline install smoke, packaging guards, docs examples, and workspace tests; optimize before raising it again.
360
369
 
370
+ ### 0.0.9 dependency audit decision (2026-07-21)
371
+
372
+ `npm audit --audit-level=high` reports 0 vulnerabilities and `npm ls --all --depth=0` resolves the exact 32-package `0.0.96` graph (including `@arnilo/prism-browser`). Locked-install SPDX contains 185 packages and eight approved license expressions; `scripts/verify-sbom.mjs` passed. Browser keeps `playwright-core@1.61.0` as an optional peer and ships no browser binary/image; no Office package/binary enters the graph.
373
+
361
374
  ### 0.0.8 dependency audit decision (2026-07-20)
362
375
 
363
376
  `npm audit --audit-level=high` reports 0 vulnerabilities and `npm ls --all --depth=0` resolves the exact 31-package `0.0.8` graph. Locked-install SPDX contains 183 packages and eight approved license expressions; `scripts/verify-sbom.mjs` passed. New runtime dependencies remain isolated to optional packages: MCP stays pinned to SDK 1.29.0 and web tools add no vendor SDK. Native `better-sqlite3` remains the sole install-script dependency and stays in opt-in SQLite.
364
377
 
378
+ ### 0.0.9 release-candidate verification — 2026-07-21
379
+
380
+ | Gate | Result |
381
+ | --- | --- |
382
+ | Package graph | Root + 31 workspaces = 32 publishable manifests at exact `0.0.96` with exact internal peer/dependency ranges; `@arnilo/prism-browser` in `@arnilo/prism-all` only (not `@arnilo/prism-code`). |
383
+ | Deterministic suites | Post–Synapta Task 13 re-verify: `npm run sdk:ready` passed: 1,934 tests across core/workspaces (1,905 pass, 29 explicit live skips, 0 fail), full typecheck/build/examples, docs/export/package/install smoke, and 32 dry-run packs. |
384
+ | Synapta Defects 1a/1b/2 | Malformed streamed tool-call args → failed/`tool_execution_blocked` (`invalid_json_arguments`, never executes); incomplete deltas → typed `incomplete_delta` fail-closed; empty/thinking-only call-free artifacts → `parse_error` revision budget with no `succeeded` without `artifact_finished`. Conformance helper matches recovery/`incomplete_delta` contract. |
385
+ | Coding/browser | Network-free coding-agent + browser adversarial fixtures unchanged; dated `scripts/benchmark-0.0.9.mjs` evidence retained (Node v24.18.0 Linux x64, 100 iterations); protected Docker (`PRISM_TEST_DOCKER_SANDBOX=1`) and Playwright (`PRISM_LIVE_PLAYWRIGHT=1`) remain explicit operator P0 gates when host-provisioned. |
386
+ | Supply chain | `npm audit --audit-level=high` = 0 vulnerabilities; SPDX SBOM 185 packages / 8 approved licenses; working-tree secret scan 2,402 files / 0 findings; unpacked-tarball secret scan 847 files / 0 findings; `git diff --check` clean. |
387
+ | Artifacts | Packed review: 972,339 bytes compressed / 3,755,038 unpacked / 847 files across 32 tarballs; core 519,366 / 1,819,939; browser 29,171 / 132,669 with no Playwright binary/image and no Office package/binary. |
388
+ | Registry/order | Public `release:check` found all 32 `@arnilo/*@0.0.96` versions available. Dependency-ordered `release:publish --dry-run --allow-dirty --allow-untagged` completed 32/32 dry-run with explicit public/latest/provenance; no commit, tag, or publication created. |
389
+ | Office exclusion | No Office package, binary, SDK, wrapper, docs page, test, or release gate. |
390
+
365
391
  ### 0.0.8 release-candidate verification — 2026-07-20
366
392
 
367
393
  Phase 3 validation ran from this working tree without creating a release commit/tag or publishing. Clean protected-branch/tag, GitHub CodeQL/dependency-review, environment approval, OIDC, and actual canary/publication checks remain mandatory in the handoff above.
@@ -393,7 +419,7 @@ Every release gate maps to an exact enforcement test or command, so the checklis
393
419
  | Root SDK export surface freeze | `public-export-contract.test.ts` `root export surface is frozen` snapshots every value and type export of `src/index.ts` (107 value + 69 type) so any add/remove is a deliberate test update; `every frozen value export resolves at runtime` rebuilds `dist/index.js` and asserts each value export is present (catches build drift), and `every frozen type export appears in the built type declarations` asserts each type export is in `dist/index.d.ts`. |
394
420
  | Examples compile and are listed; runnable demos execute | `npm run typecheck` runs `tsc -p examples --noEmit`; `docs.test.ts` checks every `examples/*.ts` file is listed in `examples/README.md`, then runs demos offline and scans output for secrets. |
395
421
  | Examples run to completion with no secret leakage | `docs.test.ts` `examples_demos_run_to_completion_and_emit_no_secret` runs each demo (Node strips TypeScript types natively) with exit-0 and real-secret scans; `external_app_example_*` pins the DB-backed adapter reference exercising the `RunLedger`, branch-handle checkout, fork, and prior-run resume. |
396
- | Tarball excludes built tests, source maps, and source | `packaging.test.ts` rejects `dist/__tests__/`, `*.map`, `src/`, `plans/`, and internal files; confirms every package ships README/changelog (and code packages ship LICENSE), core ships docs + CLI, exported targets exist (`dist/index.js` + `dist/index.d.ts` for NeuralWatt), and `prism-all` transitively reaches all 31 published first-party manifests. |
422
+ | Tarball excludes built tests, source maps, and source | `packaging.test.ts` rejects `dist/__tests__/`, `*.map`, `src/`, `plans/`, and internal files; confirms every package ships README/changelog (and code packages ship LICENSE), core ships docs + CLI, exported targets exist (`dist/index.js` + `dist/index.d.ts` for NeuralWatt), and `prism-all` transitively reaches all 32 published first-party manifests. |
397
423
  | NeuralWatt package/docs/examples release gate | `packaging.test.ts` pins `@arnilo/prism-provider-neuralwatt` package exports/type declarations and `@arnilo/prism-providers`/`@arnilo/prism-all` membership; `docs.test.ts` asserts `docs/index.md` links `providers/neuralwatt.md` and `provider-caching.md`, and that `examples/cache-aware-prompt-assembly.ts` plus `examples/neuralwatt-agent-run.ts` exist and are listed. |
398
424
  | Version graph and resumable publication | `release.test.ts` covers exact package/lock/range validation, topological order, registry collisions, dry-run, interrupted reports/resume, clean tagged git state, provenance/public/tag arguments, and token-safe errors. `release:check` and `release:publish` derive the workspace graph without a manual package list. |
399
425
  | Supply-chain and live-canary policy | `supply-chain-security.test.ts` verifies SPDX allow/deny behavior, bounded source/artifact secret detection, credential-free canary reports, timeout/redacted failures, immutable action revisions, no `pull_request_target`, protected live environment, attestation paths, and publish dependency on `supply-chain`; CI adds CodeQL and PR dependency review. |
@@ -0,0 +1,175 @@
1
+ # Review coverage — 2026-07-20 Phase 4
2
+
3
+ Working evidence for Plan 072 Task 0. This page freezes revised Phase 4 scope, source/external revisions, primitive ownership, finite-limit targets, threats, tests, docs, and release gates before implementation.
4
+
5
+ **Evidence frozen:** 2026-07-20. **Prism source:** `0d109989b4892e3fe4378ab782044ceadc460277` (`Release 0.0.8`). **Release target:** 0.0.9. **Default test rule:** local fakes and fixtures only; Docker/Playwright execution is a separate protected gate.
6
+
7
+ ## Revised product decision
8
+
9
+ 0.0.9 contains production coding and browser execution only. Office document execution is host-selected skill/instruction work outside Prism packaging. Prism will not ship `@arnilo/prism-work-tools/officecli`, an OfficeCLI binary/SDK/wrapper, Office-specific runtime contracts, generic Office MCP/CLI passthrough, Office tests/docs, or an Office release gate. This is a removed product criterion, not deferred 0.0.9 implementation.
10
+
11
+ Cloud Microsoft 365 and Google Workspace connectors remain a separate later roadmap decision. They cannot depend on or imply local OfficeCLI execution.
12
+
13
+ ## Status legend
14
+
15
+ | Status | Meaning |
16
+ | --- | --- |
17
+ | `existing` | Current public contract covers the requirement. |
18
+ | `extend` | Owning task extends an existing optional package/contract. |
19
+ | `new-package` | New optional package; core remains dependency-free. |
20
+ | `compose` | Existing public primitives are sufficient; only example/docs or package-local glue may be needed. |
21
+ | `removed` | Deliberately outside Prism product/release scope. |
22
+
23
+ ## Frozen external revisions
24
+
25
+ | Surface | Frozen reference | Compatibility decision |
26
+ | --- | --- | --- |
27
+ | Prism | [`0d109989b4892e3fe4378ab782044ceadc460277`](../plans/072-release-0-0-9-production-coding-and-browser-execution.md) | All primitive/caller claims below were checked against the 0.0.8 release tree. |
28
+ | Node.js | Local reference `v24.18.0`; Prism release support remains Node 20 and current | Use `node:child_process`, `node:fs`, streams, `AbortSignal`, `URL`, crypto hashes, and path APIs only. Node 20/current tests own compatibility. |
29
+ | Playwright | [`playwright-core@1.61.0`](https://github.com/microsoft/playwright/tree/v1.61.0), npm integrity `sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==` | Task 5 tests this exact compatibility line. Browser binary remains host supplied; package install performs no browser download. Only documented Browser/BrowserContext/Page/Locator/Download APIs are allowed. |
30
+ | Playwright context/locator/snapshot/network docs | [BrowserContext](https://playwright.dev/docs/api/class-browsercontext), [Locator](https://playwright.dev/docs/api/class-locator), [locators](https://playwright.dev/docs/locators), [ARIA snapshots](https://playwright.dev/docs/aria-snapshots), [network](https://playwright.dev/docs/network), retrieved 2026-07-20 | Non-persistent contexts; role/label/test-id and snapshot refs before CSS; `ariaSnapshot({ mode: "ai" })`; service workers blocked when routing must observe requests. Request routing is defense in depth, not DNS containment. |
31
+ | Docker CLI/Engine | Local reference client/server `29.6.1`; [container run](https://docs.docker.com/reference/cli/docker/container/run/), [resource constraints](https://docs.docker.com/engine/containers/run/), [default seccomp](https://docs.docker.com/engine/security/seccomp/), retrieved 2026-07-20 | Task 1 uses an absolute host-selected Docker executable, digest-pinned preloaded image, `--pull=never`, typed arguments, read-only root/source, finite tmpfs workspace, non-root user, dropped capabilities, default seccomp, no-new-privileges, and network none. Exact supported-version floor follows tested flag preflight; 29.6.1 is reference evidence. |
32
+ | Git | Local reference `git version 2.55.0`; [official manuals](https://git-scm.com/docs), retrieved 2026-07-20 | Task 3 uses porcelain/plumbing argument arrays: `status --porcelain=v2 -z`, `diff --no-ext-diff --no-textconv`, `check-ref-format`, `worktree`, `apply --check`, `commit`, and `bundle`. Exact supported-version floor follows fixture/live conformance; 2.55.0 is reference evidence. |
33
+
34
+ No Office executable, SDK, repository, schema, or version is pinned because Office execution is outside the release boundary.
35
+
36
+ ## Capability traceability matrix
37
+
38
+ | Revised roadmap criterion | Current surface | Minimum 0.0.9 gap | Status / owner | Required proof | Docs | Release gate |
39
+ | --- | --- | --- | --- | --- | --- | --- |
40
+ | Disposable read-only-base sandbox; writable bounded workspace; deny-default network; CPU/memory/PID/disk/time/secret/termination controls | `SandboxAdapter.exec(command)` maps only shell operations; coding tools have local operation seams | Typed process/lifecycle/import/export Docker reference with real limits and cleanup | `extend` / Task 1 | fake CLI matrix plus protected filesystem/network/process/resource escape tests | `coding-security.md`, `host-security.md`, `performance.md` | protected Docker gate + offline adapter tests |
41
+ | Native bounded repository list/search | `createReadOnlyTools()` contains only `read`; read already has path, byte, line, image, abort bounds | Streaming stdlib list/search and sandbox operation wiring | `extend` / Task 2 | traversal/search ordering, symlink, binary, regex, byte/time/abort tests | `coding-agent-tools.md`, `performance.md` | offline coding conformance |
42
+ | Structured Git status/diff/branch/worktree/patch/commit | Shell can invoke Git but has coarse operation policy | Typed arguments, bounded parsers/results, safe repo config, rollback, artifacts | `extend` / Task 3 | hostile path/ref/config/hook, dirty-tree, rollback, worktree tests | `coding-agent-tools.md`, `coding-security.md` | offline Git conformance + protected sandbox |
43
+ | Named test/lint/typecheck/security commands and diagnostics | Shell operation backend, output accumulator, execution policy, progress events | Host-declared name → fixed executable/args map; bounded summaries/artifacts | `extend` / Task 3 | unknown name, fixed args/env, timeout/output/secret tests | `coding-agent-tools.md`, `performance.md` | offline command conformance |
44
+ | Durable plans/todos/checkpoints/approvals/background branches/restart | Workspace files; `CheckpointStore`; workflow state/suspend/resume/coordinator/leases/events | Reference composition and immutable workspace artifact metadata; no second runtime | `compose` / Task 4 | restart/revision/owner/hash/lease/cancel/stale-worker matrix | `workflows.md`, `coding-agent-tools.md` | offline durable workflow journey |
45
+ | Host-owned PR creation | No repository host API; workflow results can return bounded data | PR handoff metadata + patch/bundle reference only | `extend` / Task 3, composed by Task 4 | deterministic bounded handoff; prove no push/network/credential use | `coding-agent-tools.md`, `workflows.md` | offline handoff conformance |
46
+ | Four Playwright browser tools with one run-owned isolated context and ordered actions | Core tool dispatch/exclusive flag, execution policy, guardrails, run identity; no browser package | Optional package and finite context/page/snapshot/action manager | `new-package` / Task 5 | fake API lifecycle, isolation, stale-ref, ordered-action, cleanup tests | `browser-automation.md`, `tools.md` | package/pack/install + protected Playwright |
47
+ | Browser egress/side-effect/artifact policy | Execution/permission policy, guardrails, path containment, `ImageContent`, redaction | Context routing + host firewall/proxy requirement; upload/download/screenshot quarantine | `new-package` / Task 6 | redirects/private/DNS/service-worker, approval, artifact, secret tests | `browser-automation.md`, `host-security.md` | protected egress/browser gate |
48
+ | Adversarial coding/browser evals and reproducible benchmarks | `@arnilo/prism-evals`, network-free fixtures, current benchmark/live workflow patterns | Package datasets, one 0.0.9 benchmark, protected real gate | `extend` / Task 7 | deterministic score thresholds and benchmark schema/cleanup | `evaluations.md`, `performance.md` | default eval gate + protected live gate |
49
+ | 0.0.9 package/docs/release evidence | 31-package 0.0.8 graph and deterministic release pipeline | Add at most browser package; version/docs/pack/install/audit evidence | `extend` / Task 8 | `sdk:ready`, Node 20/current, pack/install, supply chain, release dry-run | `release-and-install.md`, `migration.md` | complete 0.0.9 release gate |
50
+ | OfficeCLI/Office package/runtime/tests/docs/release criterion | Roadmap-only proposal; no current package | None | `removed` / product decision | docs assertion: absent from Phase 4/package graph/release checklist | this page, `roadmap.md` | explicit absence check |
51
+
52
+ ## Primitive and caller inventory
53
+
54
+ | Primitive | Existing contract/callers at frozen revision | Phase 4 disposition |
55
+ | --- | --- | --- |
56
+ | `ToolDefinition` / tool dispatch | `src/contracts.ts` defines name/schema/static `exclusive`/execute; `src/tools.ts` applies registry filter, trust, permission, validation, `beforeExecute`, guardrails, run-limit charge, events, ledger, and redaction. Coding, web, MCP, workflows, providers, examples, and tests consume it. | Reuse for list/search/Git/check/browser tools. Browser tools set static `exclusive: true` and also queue per run. No browser-specific dispatch runtime. |
57
+ | `ExecutionPolicy` | String-extensible `ExecutionAction.kind`, operation/paths/command/risk/metadata and allow/modify/deny check in `src/execution-policy.ts`; coding tools enforce immediately before operations; workflow tool nodes can define actions and durable approval. | Reuse. Add package-local `git`, `check`, and `browser` action kinds/metadata; no core enum or approval engine. Policy is authorization, not containment. |
58
+ | `PermissionPolicy` / trust | `src/security.ts`; `dispatchToolCall` and resource loading check host policies before execution/load. MCP/supervisor/extensions also consume permission/trust contracts. | Reuse at dispatch/resource boundaries. Do not duplicate permission logic in sandbox/browser managers. |
59
+ | Guardrails / redaction | `src/tools.ts` runs tool-input/output guardrails and redacts results/events/ledger; `src/agents.ts` handles agent/provider stages. | Reuse for untrusted repository/browser content. Secrets remain host-known redactor inputs; sandbox/browser internals must redact before errors/artifact metadata too. |
60
+ | `RunLimits` / `RunLimitTracker` | Defaults/hard caps in `src/run-limits.ts`; runtime charges turns, provider attempts, tool rounds/calls, wall time, request/response bytes, tokens, cost. MCP/workflow types accept limits. | Reuse for total agent work. Package-local external-resource limits below charge before work/retention; no expansion of `RunLimits` until another domain needs identical counters. |
61
+ | `CheckpointStore` / leases | Generic owner-scoped versioned CAS/fencing contract; memory, SQLite, PostgreSQL, agent lifecycle/state, workflows, and schedules consume it. | Reuse for durable workflow metadata. Store artifact URI/hash/bytes and summaries, never repository/browser state blobs or credentials. |
62
+ | Workflow state/suspend/coordinator | Workflow revision hash, bounded state/history/checkpoints, tool approval suspension, background enqueue, lease renewal/fencing/cancel, finite coordinator concurrency/pages. | Compose coding plan/todo files and branch artifact references. No `CodingRun`, todo DB, scheduler, or second workflow engine. |
63
+ | Coding operation backends | `ReadOperations`, `WriteOperations`, `EditOperations`, `BashOperations`; local defaults; `SandboxAdapter` currently maps shell only. | Task 1 extends coding-security with typed `execFile`/lifecycle; Task 2 wires bounded repository operations. Preserve current custom/local contracts unless tests prove one shared addition is required. |
64
+ | `withFileMutationQueue` | Process-wide map keyed by resolved realpath; used by write/edit; serializes same real path and releases on error. | Reuse for local same-path mutation. Git disposable worktree/patch transaction owns multi-file rollback; do not turn queue into transaction manager. |
65
+ | `ResourceLoader` | Optional load/list with abort, trust, permission; bounded binary helper exists; inputs/contributions/extensions consume it. | May rehydrate a host-owned immutable artifact reference. It is not an artifact store, workspace transport, browser downloader, or network-containment bypass. Task 1/3 use narrow host callbacks for export. |
66
+ | `ImageContent` / media bounds | Core content contract; coding read returns bounded images and can require host transform. | Reuse for bounded screenshots. Browser package enforces pixel/encoded-byte caps before returning content; no new image type. |
67
+ | Agent/workflow events | Tool progress/start/finish/error/block, guardrail/limit events, workflow ordered events and finite buffers. | Reuse for diagnostics/progress/cleanup evidence. No coding/browser event bus or hook registry. |
68
+ | `@arnilo/prism-evals` | Immutable datasets, bounded experiments/concurrency, function scorers, trace/judge/comparison/report limits. | Extend with package-local coding/browser datasets/scorers only; no mandatory model/network/service. |
69
+ | `SandboxAdapter` | One `exec({ command, cwd, env, onData, signal, timeout })` contract and `createSandboxBashOperations`; no lifecycle, typed arguments, transfer, status, or containment implementation. | Extend in coding-security Task 1. Generic core sandbox contract is not authorized. |
70
+
71
+ ### Primitive decision
72
+
73
+ No new core primitive is authorized by Task 0.
74
+
75
+ Authorized package-local work:
76
+
77
+ 1. `@arnilo/prism-coding-security`: minimal typed executable, disposable lifecycle, import/export, status, and cleanup contracts implemented by the real Docker reference. Preserve current `SandboxAdapter.exec` compatibility.
78
+ 2. `@arnilo/prism-coding-agent`: repository/Git/check/artifact types and operation overrides only where local and sandbox implementations both consume them.
79
+ 3. `@arnilo/prism-browser`: run/context/action/artifact manager and Playwright types stay entirely optional-package local.
80
+
81
+ A shared primitive can be promoted later only with two concrete non-test consumers and migration/conformance evidence. One-consumer interfaces, artifact databases, browser planners, Git libraries, proxy/firewall implementations, Office types, and remote worker/control-plane contracts are rejected.
82
+
83
+ ## Frozen capability boundary
84
+
85
+ | Surface | Supported in 0.0.9 | Explicitly unsupported |
86
+ | --- | --- | --- |
87
+ | Sandbox | Host-invoked Docker CLI reference; digest-pinned preloaded image; disposable container; finite tmpfs workspace; typed execution; bounded import/export; deterministic cleanup; default network none | Docker daemon provisioning, image build/pull/update, Kubernetes/remote scheduler, bundled image/proxy, host Docker-socket exposure, claim that command policy equals containment |
88
+ | Coding | Native list/literal-or-bounded-regex search; structured Git/status/diff/branch/worktree/patch/commit; named fixed checks; workspace plan/todos; rollback/discard; background workflow composition; PR handoff | Language server/index/watch service, arbitrary model-created commands, implicit repo hook execution, GitHub/GitLab authentication/push/PR client, second coding runtime |
89
+ | Browser | Four model tools; host-supplied Playwright 1.61-compatible browser; non-persistent context; ARIA snapshot/refs and user-facing locators; bounded screenshots/uploads/downloads/popups/dialogs | `evaluate`, arbitrary JavaScript/CSS/XPath, CDP/devtools, extensions, persistent/local profiles, browser binary download, generic MCP proxy, visual/coordinate planner |
90
+ | Network | Network none by default; real browsing only behind host-contained proxy/firewall plus Playwright route checks | DNS rebinding protection by URL regex/routing alone; in-package firewall/proxy; public-network default tests |
91
+ | Artifacts | Bounded host callbacks/references/hashes; download quarantine; screenshot `ImageContent`; patch/bundle/PR handoff | Artifact SaaS/database, unrestricted host paths, checkpointing credentials/storage state/full workspace, automatic upload/push |
92
+ | Office | Host-selected skills/instructions may guide external user-owned work | Any Prism Office executable, SDK, wrapper, package, protocol, tool, test, doc page, binary, or release gate |
93
+
94
+ ## Frozen finite limits and charging points
95
+
96
+ Values are target defaults / hard caps for Tasks 1–7, not active 0.0.8 APIs. Existing stricter limits remain authoritative. Validate host configuration before starting work; charge count/declared bytes before each operation and stream-count actual bytes before retention/export.
97
+
98
+ ### Sandbox and workspace
99
+
100
+ | Resource | Default / hard cap | Charge/check point | Failure and cleanup owner |
101
+ | --- | --- | --- | --- |
102
+ | Startup / run wall / idle | 30 s / 120 s; 20 min / 30 min; 5 min / 15 min | Before create; absolute deadline starts before Docker invocation; idle resets only on accepted operation | Task 1 stops, then kills and removes recorded container |
103
+ | CPU / memory+swap / PIDs | 2 / 8 CPUs; 2 GiB / 16 GiB; swap equal to memory; 256 / 1,024 PIDs | Validated before `docker run`; enforced by container/cgroup flags | Task 1 aborts run on limit exit and cleans container |
104
+ | File descriptors | 1,024 / 8,192 | Validated before `docker run`; `nofile` ulimit | Task 1 |
105
+ | Workspace / temp / download tmpfs | 1 GiB / 8 GiB; 256 MiB / 2 GiB; 64 MiB / 512 MiB | Size option validated before create; kernel tmpfs cap enforces writes | Task 1/6 discard on overflow |
106
+ | Commands / concurrent exec | 100 / 256; 1 / 8 | Before queue/start; total also remains under run tool-call/wall limits | Task 1 rejects/aborts; close drains finite queue then kills |
107
+ | Command output | existing 64 MiB / 1 GiB total; model result spill remains separately bounded | Stream byte count before append/write | Coding output accumulator + Task 1 termination |
108
+ | Environment/secrets | 64 names / 256; 64 KiB / 256 KiB aggregate values | Validate exact host allow-list before create/exec; inherit none | Task 1 redacts errors and never exports environment |
109
+ | Import/export | 50,000 / 250,000 entries; 256 MiB / 2 GiB bytes; 16 / 64 retained artifacts | Count headers/entries and stream bytes before write/retain; verify real path/type/hash | Task 1 aborts export, removes partial host artifact, source remains unchanged |
110
+ | Stop grace / forced cleanup | 5 s / 30 s; one stop then one kill; cleanup deadline 30 s / 120 s | Terminal/abort/timeout/lease loss/browser crash | Task 1 records unresolved cleanup as release-blocking error |
111
+
112
+ ### Repository, Git, checks, and durable work
113
+
114
+ | Resource | Default / hard cap | Charge/check point | Owner |
115
+ | --- | --- | --- | --- |
116
+ | Repository depth / entries / files | 32 / 128; 10,000 / 100,000; 10,000 / 100,000 | Before descending/retaining next entry/file | Task 2 |
117
+ | Search scan/file/matches | 64 MiB / 1 GiB aggregate; 8 MiB / 64 MiB per file; 1,000 / 10,000 matches | Prefix/binary check then stream bytes; check aggregate before next file/match | Task 2 |
118
+ | Search pattern/line/context/time | 512 / 4,096 UTF-8 bytes; 50 KiB / 1 MiB line; 5 / 20 context lines; 30 s / 300 s | Before regex compile; before line/context retention; absolute deadline | Task 2 |
119
+ | Repository concurrency | 8 / 32 open/read workers | Before opening next directory/file | Task 2 |
120
+ | Git paths/refs/message | 1,000 / 10,000 paths; 1 KiB / 4 KiB ref; 64 KiB / 256 KiB commit message | Validate before process/temp-file creation | Task 3 |
121
+ | Git output/diff/patch | 4 MiB / 64 MiB inline output; 10,000 / 100,000 diff lines; 1,000 / 10,000 changed files; 16 MiB / 64 MiB patch input | Stream before retain; spill only through bounded artifact callback | Task 3 |
122
+ | Worktrees/background runs | 4 / 16 per parent run; coordinator default remains 4 and hard cap 256 | Before create/lease claim; exact branch/root ownership recorded | Task 3/4 |
123
+ | Named checks | 8 / 32 names per host config; 1 / 4 concurrent; 10 min / 60 min each; 2,000 / 100,000 diagnostic lines; 4 MiB / 64 MiB inline output | Validate config at construction; charge before start/line retention | Task 3 |
124
+ | Workflow state/checkpoint/history | Existing 64 KiB / 512 KiB state; 1 MiB / 8 MiB checkpoint; 32 / 128 history revisions | Existing workflow adapter checks before save | Task 4 |
125
+ | Workspace checkpoint artifacts | 16 / 64 references; 256 MiB / 2 GiB each, also sandbox export aggregate | Hash/size verify before checkpoint metadata/import | Task 4 with host artifact owner |
126
+ | Plan/todo and PR handoff | 256 KiB / 1 MiB plan; 1,000 / 10,000 todos; 256 KiB / 1 MiB handoff JSON | Before write/checkpoint/result exposure | Task 4 / Task 3 handoff |
127
+
128
+ ### Browser
129
+
130
+ | Resource | Default / hard cap | Charge/check point | Owner |
131
+ | --- | --- | --- | --- |
132
+ | Contexts/pages/actions/queued actions | exactly 1 context per run; 4 / 16 pages; 100 / 256 actions; 16 / 64 queued | Before context/page/action/queue creation; invalidate refs on mutation | Task 5 |
133
+ | Snapshot refs/depth/bytes | 2,000 / 10,000 refs; depth 30 / 100; 256 KiB / 2 MiB encoded YAML | Before retaining each ref/node and before result exposure | Task 5 |
134
+ | Navigation/action/wait/run time | 30 s / 120 s navigation; 10 s / 60 s action; 30 s / 120 s explicit wait; sandbox 20 min / 30 min run | Absolute deadline before Playwright call; no timeout retries unless action budget charged | Task 5 |
135
+ | Popups/dialogs/listeners | 4 / 16 popups; 16 / 64 dialogs; 64 / 256 registered listeners | Before accepting/retaining; deterministic deny/dismiss after cap | Task 5/6 |
136
+ | Network requests/redirects/WebSockets | 1,000 / 10,000 requests; 10 / 32 redirects/request; 8 / 32 WebSockets | Before route continuation/redirect/socket acceptance | Task 6; host firewall/proxy owns actual egress |
137
+ | Screenshots | 16 / 64 megapixels; existing 10 MB / 32 MiB encoded image cap; 16 / 64 per run | Validate clip/viewport before capture and bytes before result/artifact | Task 6 |
138
+ | Uploads | 8 / 32 files; 16 MiB / 64 MiB each; 64 MiB / 256 MiB aggregate | Realpath/type/size/approval before Playwright receives path | Task 6 |
139
+ | Downloads | 8 / 32 files; 32 MiB / 256 MiB each; 64 MiB / 512 MiB aggregate | Stream to quarantine with count/hash; approval before export | Task 6 |
140
+ | Browser cleanup | 5 s / 30 s close grace, then sandbox kill; 0 retained context/storage-state objects | Abort, terminal run, explicit close, browser crash, lease loss | Task 5 manager and Task 1 sandbox |
141
+
142
+ ## Threat and authority matrix
143
+
144
+ | Boundary | Trusted authority | Untrusted input | Mandatory control | Default/unsupported behavior |
145
+ | --- | --- | --- | --- | --- |
146
+ | Docker daemon/executable/image | Host operator supplies absolute CLI, daemon, digest, non-root image UID and policy | Model/repository/container output | Typed args; preflight; `--pull=never`; no socket/device/privileged/host namespaces; labels/recorded IDs | Missing/mutable/untrusted input fails before create; daemon compromise is outside Prism containment |
147
+ | Source/workspace import/export | Host selects source and artifact callback | Paths, links, repository entries, archive headers/content | Read-only source; finite tmpfs; realpath/type checks; no devices; stream bounds; hash; atomic partial cleanup | No direct write-back; failed run discards workspace |
148
+ | Process/environment/secrets | Host declares named checks and exact env allow-list | Model command text, repo scripts/config/hooks, process output | Typed exec for first-party tools; shell explicit; inherited env empty; noninteractive Git; redaction; limits | Unknown command/check/env denied; no implicit hooks/credentials |
149
+ | Network/DNS | Host firewall/proxy/network policy | URLs, redirects, DNS, page scripts/service workers/WebSockets | Network none default; isolated proxy/firewall for browse; route validation and service-worker block in depth | No proxy attestation means no external browser network; private/local/file/devtools denied |
150
+ | Playwright/browser endpoint | Host owns pinned browser launch/control endpoint | Pages, DOM/a11y text, refs, popups, downloads | One non-persistent context/run; short-lived host-only endpoint; ordered actions; no evaluate/CDP/profile | Endpoint/browser mismatch fails construction; import is inert |
151
+ | Side effects/approval | Host `PermissionPolicy`, `ExecutionPolicy`, workflow approval | Model/page instructions and action metadata | Dispatch permission/guardrails then immediate operation policy; high-impact durable approval | Page text cannot authorize; denial produces bounded stable result |
152
+ | Browser storage/secrets | Host injects at context/request edge | Cookies/storage state/page content/errors | Never return/persist/log storage state; redact known secret canaries; close context | No local profile; no checkpointed browser internals |
153
+ | Upload/download/screenshot | Host roots, artifact callback, approval | Filenames, MIME, bytes, page pixels, symlinks | Realpath containment; quarantine; stream/pixel/byte caps; hashes; explicit release | Overflow/unknown type stays quarantined then deleted |
154
+ | Durable checkpoint/resume | Host-owned checkpoint/lease/artifact stores and ownership scope | Persisted metadata, stale workers, artifact URI/content | CAS/fencing; workflow revision; image/tool/policy fingerprints; artifact hash/size; current approval | Wrong owner/revision/hash/fence fails before import/action |
155
+ | Office work | User/host-selected external skill/tool | Office files/commands | Outside Prism runtime | No package, executable, schema, docs, test, or release claim |
156
+
157
+ ## Validation matrix for Task 0
158
+
159
+ | Check | Frozen assertion |
160
+ | --- | --- |
161
+ | Traceability | Every retained Phase 4 criterion above has one primary owner Task 1–8; cross-task composition is explicit. Removed Office criterion has product-decision owner and no implementation task. |
162
+ | Primitive reuse | No new core primitive. Package-local additions have concrete local+sandbox or coding+browser consumers where shared; otherwise remain in owning package. |
163
+ | Finite resources | Every external start/read/write/retain/queue/export path above has default/hard caps, pre-charge point, abort behavior, and cleanup owner. |
164
+ | Security claims | Sandbox containment is Docker/host policy, not regex; browser DNS containment is host proxy/firewall, not Playwright routing; daemon, image, credentials, network, artifacts, and approvals stay host-owned. |
165
+ | Scope absence | Revised roadmap Phase 4, package ledger, persona outcomes, and release checklist contain no OfficeCLI/Office runtime/package gate. |
166
+
167
+ ## Documentation and release ownership
168
+
169
+ - Task 1: `docs/coding-security.md`, `docs/host-security.md`, `docs/performance.md`, protected Docker gate.
170
+ - Tasks 2–4: `docs/coding-agent-tools.md`, `docs/workflows.md`, `docs/evaluations.md`, offline coding/Git/durable-workflow gates.
171
+ - Tasks 5–6: new `docs/browser-automation.md`, plus tools/guardrails/security/performance docs, package/install and protected Playwright gate.
172
+ - Task 7: eval, benchmark, and protected-gate evidence — completed network-free coding/browser adversarial fixtures (`eval-fixtures.test.ts`), `scripts/benchmark-0.0.9.mjs` (+ schema test), protected Playwright live matrix, expanded Docker protected matrix, and `.github/workflows/sandbox-browser.yml`.
173
+ - Task 8: migration/release docs, package graph, Node/pack/install/supply-chain/release dry-run evidence — completed 32-package exact `0.0.9` graph (`@arnilo/prism-browser` in `prism-all` only), finalized docs/changelogs/migration/release handoff, dated `benchmark-0.0.9` evidence, and release-candidate gates recorded in Plan 072.
174
+
175
+ No public implementation API changed in Task 0. This page and `roadmap.md` are the authoritative pre-implementation boundary; later tasks may tighten defaults but cannot raise hard caps or broaden authority without updating tests, docs, and this evidence.
@@ -231,9 +231,9 @@ Key cross-seam points:
231
231
  - `generate-validate-revise` is selected via `AgentConfig.loop` / `RunOptions.loop` (`RunOptions.loop` wins). See [Agent loops](agent-loops.md). `resolveLoop()` maps the options form to the factory; an unknown `strategy` throws before the first turn; a custom `AgentLoopStrategy` instance bypasses the options form.
232
232
  - Native structured output uses provider-neutral `StructuredOutputOptions` on `ProviderRequestOptions` / loop options. Capable OpenAI-family providers map to JSON-schema wire fields; unsupported models fail before fetch unless the host sets `structuredOutputMode: "artifact-loop"` and relies on parser/validator/repairer only.
233
233
  - `validateStructuredOutputOptions()` enforces JSON-safe schemas, forbidden prototype-pollution keys, and a 64 KiB schema size cap.
234
- - The default parser treats assistant text as the value (`{ ok: true, value: text }`); supply a host parser whenever `T` is not `string`.
234
+ - The default parser treats non-empty assistant text as the value (`{ ok: true, value: text }`); empty/whitespace-only call-free text is a `parse_error` before the parser. Supply a host parser whenever `T` is not `string`.
235
235
  - The default repairer builds a user message from `validation.errors[].message`; supply a host repairer for schema-specific guidance.
236
- - `maxRevisions` (default 3) bounds revision turns; budget exhaustion ends the loop and emits `artifact_failed` (it does not throw).
236
+ - `maxRevisions` (default 3) bounds revision turns; budget exhaustion ends the loop and emits `artifact_failed`. Session runs then fail with `AgentRunError` unless `artifact_finished` occurred (direct `loop.run` still returns usage without throwing).
237
237
  - Tools are inert in artifact turns unless `loop.toolCalls: "bounded"` is explicit. Bounded mode uses run-global `maxToolRounds`, dispatches calls sequentially through normal runtime guards, skips parser/validator for tool-calling responses, and permits at most `1 + maxRevisions + maxToolRounds` provider turns. An extra tool response yields terminal `artifact_failed` with `result.metadata.reason === "tool_round_limit"` and executes nothing.
238
238
 
239
239
  ## Security and performance notes
package/docs/tools.md CHANGED
@@ -11,6 +11,7 @@ APIs:
11
11
  - `dispatchToolCall()`
12
12
  - `ToolFilter`, `ToolFilterInput`, `ToolValidator`, `DispatchToolCallOptions`
13
13
  - Optional [Web search, fetch, and extraction](web-tools.md): three narrow host-selected `ToolDefinition`s with untrusted bounded outputs.
14
+ - Optional [Browser automation](browser-automation.md): four exclusive Playwright tools over a host-supplied browser with run-owned contexts and snapshot refs.
14
15
 
15
16
  ## When to use it
16
17
 
@@ -91,6 +92,8 @@ When `options.ledger` is set, `dispatchToolCall()` also appends a `ToolCallRecor
91
92
 
92
93
  Blocked reasons are `unknown_tool`, `tool_denied`, `invalid_arguments`, `permission_denied`, and `validation_failed`. Progress snapshots reuse status `started` because the tool call is still in flight.
93
94
 
95
+ Malformed streamed tool-call JSON (id+name present, arguments not a JSON object) does not fail the provider turn. Providers emit a tool call with `argumentsError`; `dispatchToolCall` blocks with reason `invalid_arguments` and `error.code: "invalid_json_arguments"`, persists a failed tool result, and never calls `execute()`. The model can self-correct within `maxToolRounds`/`maxTurns`.
96
+
94
97
  ## Request/response example
95
98
 
96
99
  ```json
package/docs/web-tools.md CHANGED
@@ -67,7 +67,7 @@ Default/hard limits: query 4/16 KiB; results 10/20; URLs 5/20; request 256 KiB/1
67
67
 
68
68
  Provider credentials never enter tool schemas/results, prompts, telemetry, URLs, or errors. Error text excludes remote bodies. Search snippets, Markdown, and extracted JSON are prompt-injection-capable data: never concatenate them into system instructions or use them to modify tools, permissions, credentials, trust, routing, or schemas. Firecrawl fetches target URLs remotely; Prism cannot claim target DNS pinning after handoff. Use controlled host fetch when that guarantee is required.
69
69
 
70
- Default tests use injected fake fetch and make no public request. Restricted smoke: `PRISM_LIVE_WEB=1 npm run test:live -w @arnilo/prism-web-tools` plus least-privilege provider environment credential. Browser automation, arbitrary HTML execution, model-selected providers, automatic OAuth forwarding, and generic web/MCP passthrough are unsupported.
70
+ Default tests use injected fake fetch and make no public request. Restricted smoke: `PRISM_LIVE_WEB=1 npm run test:live -w @arnilo/prism-web-tools` plus least-privilege provider environment credential. Prefer these tools over `@arnilo/prism-browser` for ordinary public retrieval; use browser automation only for interactive/authenticated/JavaScript-heavy work behind a host egress proxy. Arbitrary HTML execution, model-selected providers, automatic OAuth forwarding, and generic web/MCP passthrough are unsupported.
71
71
 
72
72
  ## Related APIs
73
73
 
package/docs/workflows.md CHANGED
@@ -299,4 +299,5 @@ Use workflows for known, durable, replayable graphs. Use optional supervisor del
299
299
  - [PostgreSQL persistence](postgres-persistence.md): durable `persistence.checkpoints`
300
300
  - [Observability](observability.md): exporting workflow/agent events
301
301
  - [Coding execution approval and sandboxing](coding-security.md): `ExecutionPolicy` for tool nodes
302
+ - [Coding agent tools](coding-agent-tools.md): opt-in `createGitTools()` / `git_pr_handoff` produce bounded host-owned PR payloads; durable coding plans/todos are workspace Markdown plus `state.coding` metadata helpers — workflows may compose them for restart/resume/background branches but Prism never pushes or opens PRs
302
303
  - [Release and install](release-and-install.md): atomic and profile installs