@arnilo/prism 0.5.6 → 0.7.0

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 (160) hide show
  1. package/CHANGELOG.md +81 -5
  2. package/README.md +10 -10
  3. package/dist/agent-approval.js +7 -6
  4. package/dist/agent-definitions.js +1 -0
  5. package/dist/agent-loops.js +51 -12
  6. package/dist/agent-run-lifecycle.js +11 -0
  7. package/dist/agent-run-state.d.ts +6 -0
  8. package/dist/agent-run-state.js +29 -9
  9. package/dist/agent-session/session/assemble.js +33 -2
  10. package/dist/agent-session/session/persist.js +6 -2
  11. package/dist/agent-session/session/tool-round.js +1 -0
  12. package/dist/agent-session/session/types.d.ts +10 -0
  13. package/dist/agent-session/session.d.ts +15 -0
  14. package/dist/agent-session/session.js +59 -4
  15. package/dist/agent-tool-dispatch.js +5 -4
  16. package/dist/artifacts.d.ts +39 -1
  17. package/dist/artifacts.js +73 -0
  18. package/dist/attention-compiler.d.ts +121 -0
  19. package/dist/attention-compiler.js +479 -0
  20. package/dist/cli-init.js +20 -6
  21. package/dist/content.d.ts +3 -16
  22. package/dist/content.js +9 -99
  23. package/dist/context-budget.d.ts +32 -2
  24. package/dist/context-budget.js +51 -19
  25. package/dist/contracts-core/agent.d.ts +18 -0
  26. package/dist/contracts-core/agent.js +4 -1
  27. package/dist/contracts-core/attention.d.ts +66 -0
  28. package/dist/contracts-core/attention.js +2 -0
  29. package/dist/contracts-core/compaction.d.ts +59 -0
  30. package/dist/contracts-core/compaction.js +77 -1
  31. package/dist/contracts-core/provider.d.ts +4 -0
  32. package/dist/contracts-core.d.ts +1 -0
  33. package/dist/contracts-core.js +1 -0
  34. package/dist/contracts-protocol.d.ts +29 -0
  35. package/dist/contracts-run-state.d.ts +6 -0
  36. package/dist/host-composition.d.ts +78 -0
  37. package/dist/host-composition.js +248 -0
  38. package/dist/index.d.ts +11 -8
  39. package/dist/index.js +6 -5
  40. package/dist/input.d.ts +19 -1
  41. package/dist/input.js +52 -2
  42. package/dist/media-types.d.ts +34 -0
  43. package/dist/media-types.js +158 -0
  44. package/dist/pinned-fetch.d.ts +2 -2
  45. package/dist/pinned-fetch.js +11 -12
  46. package/dist/redaction.js +74 -1
  47. package/dist/secure-agent.d.ts +2 -0
  48. package/dist/secure-agent.js +6 -1
  49. package/dist/session-stores.d.ts +11 -0
  50. package/dist/session-stores.js +23 -8
  51. package/dist/tool-result-fold.d.ts +12 -0
  52. package/dist/tool-result-fold.js +13 -6
  53. package/dist/tools.d.ts +10 -0
  54. package/dist/tools.js +41 -0
  55. package/docs/acp-agent.md +42 -11
  56. package/docs/acp.md +3 -2
  57. package/docs/ag-ui.md +9 -5
  58. package/docs/agent-definitions.md +9 -1
  59. package/docs/agent-events.md +6 -1
  60. package/docs/agent-loops.md +1 -1
  61. package/docs/agent-session-runtime.md +9 -7
  62. package/docs/attention-compiler.md +272 -0
  63. package/docs/browser-automation.md +5 -2
  64. package/docs/cli-rpc.md +4 -2
  65. package/docs/coding-agent-tools.md +1 -1
  66. package/docs/coding-security.md +5 -3
  67. package/docs/coding-tools.md +1 -1
  68. package/docs/coding-workspaces.md +22 -0
  69. package/docs/compaction-and-retry.md +36 -4
  70. package/docs/compaction-observational-memory.md +62 -9
  71. package/docs/context-and-skills.md +4 -2
  72. package/docs/contributing.md +37 -0
  73. package/docs/conversations.md +1 -1
  74. package/docs/core.md +2 -0
  75. package/docs/dev-inspector.md +4 -0
  76. package/docs/device-adapters.md +1 -0
  77. package/docs/document-reader.md +12 -2
  78. package/docs/documents.md +11 -3
  79. package/docs/enterprise-postgres-state.md +2 -2
  80. package/docs/evaluations.md +168 -4
  81. package/docs/execution-timeline.md +180 -0
  82. package/docs/graft.md +3 -1
  83. package/docs/history/0.7.0-primitive-review.md +254 -0
  84. package/docs/history/migration-0.0.md +2 -2
  85. package/docs/history/release-handoffs.md +70 -1
  86. package/docs/host-compositions.md +147 -0
  87. package/docs/host-security.md +2 -2
  88. package/docs/hosted-sandboxes.md +94 -0
  89. package/docs/index.md +73 -41
  90. package/docs/input-and-prompt-assembly.md +5 -4
  91. package/docs/knowledge-sync.md +84 -0
  92. package/docs/language-intelligence.md +2 -2
  93. package/docs/live-testing.md +4 -1
  94. package/docs/mcp-tools.md +2 -1
  95. package/docs/memory-fabric.md +416 -0
  96. package/docs/migrate-to-0.5.md +8 -3
  97. package/docs/migrate-to-0.6.md +90 -0
  98. package/docs/migrate-to-0.7.md +345 -0
  99. package/docs/migration.md +43 -1
  100. package/docs/model-registry.md +1 -1
  101. package/docs/model-routing.md +79 -4
  102. package/docs/multi-agent-patterns.md +20 -6
  103. package/docs/multimodal-content.md +1 -1
  104. package/docs/obscura.md +3 -1
  105. package/docs/observability.md +52 -1
  106. package/docs/operations.md +13 -1
  107. package/docs/options-index.md +298 -0
  108. package/docs/peer-dependencies.md +96 -0
  109. package/docs/performance.md +34 -2
  110. package/docs/ponytail.md +2 -0
  111. package/docs/postgres-persistence.md +3 -1
  112. package/docs/process-sessions.md +3 -1
  113. package/docs/prompt-registry.md +1 -1
  114. package/docs/provider-caching.md +4 -2
  115. package/docs/provider-conformance.md +2 -2
  116. package/docs/provider-packages.md +23 -23
  117. package/docs/provider-primitives.md +2 -1
  118. package/docs/providers/ai-sdk.md +5 -2
  119. package/docs/providers/bedrock.md +71 -7
  120. package/docs/providers/openai.md +1 -1
  121. package/docs/public-contracts.md +2 -2
  122. package/docs/rag.md +24 -8
  123. package/docs/realtime-voice.md +87 -0
  124. package/docs/release-and-install.md +78 -56
  125. package/docs/runs-and-usage.md +3 -2
  126. package/docs/server.md +6 -4
  127. package/docs/session-stores.md +3 -1
  128. package/docs/speech.md +2 -0
  129. package/docs/sqlite-persistence.md +2 -0
  130. package/docs/supervisors.md +33 -5
  131. package/docs/testing.md +38 -0
  132. package/docs/thinking-and-reasoning.md +3 -1
  133. package/docs/tools.md +7 -6
  134. package/docs/web-tools.md +2 -1
  135. package/docs/wiki.md +1 -1
  136. package/docs/work-artifacts-and-review.md +14 -4
  137. package/docs/work-connectors.md +3 -1
  138. package/docs/work-tools.md +14 -4
  139. package/docs/workflows.md +69 -1
  140. package/docs/working-and-semantic-memory.md +25 -14
  141. package/package.json +5 -5
  142. package/templates/README.md +2 -0
  143. package/templates/business-worker/README.md.tmpl +19 -0
  144. package/templates/business-worker/env.example.tmpl +1 -0
  145. package/templates/business-worker/gitignore.tmpl +11 -0
  146. package/templates/business-worker/manifest.json +11 -0
  147. package/templates/business-worker/package.json.tmpl +23 -0
  148. package/templates/business-worker/src/agent.ts.tmpl +92 -0
  149. package/templates/business-worker/src/index.ts.tmpl +13 -0
  150. package/templates/business-worker/src/tests/agent.test.ts.tmpl +77 -0
  151. package/templates/business-worker/tsconfig.json.tmpl +15 -0
  152. package/templates/personal-assistant/README.md.tmpl +18 -0
  153. package/templates/personal-assistant/env.example.tmpl +1 -0
  154. package/templates/personal-assistant/gitignore.tmpl +11 -0
  155. package/templates/personal-assistant/manifest.json +11 -0
  156. package/templates/personal-assistant/package.json.tmpl +23 -0
  157. package/templates/personal-assistant/src/agent.ts.tmpl +65 -0
  158. package/templates/personal-assistant/src/index.ts.tmpl +13 -0
  159. package/templates/personal-assistant/src/tests/agent.test.ts.tmpl +28 -0
  160. package/templates/personal-assistant/tsconfig.json.tmpl +15 -0
@@ -0,0 +1,87 @@
1
+ # Realtime voice
2
+
3
+ ## What it does
4
+
5
+ `createRealtimeVoiceBridge` in `@arnilo/prism-core/runtime/realtime` runs an existing `RealtimeSession` through ordinary host tool dispatch, device admission, barge-in, reconnect dedupe, and transcript privacy. OpenAI Realtime (`createOpenAIRealtimeSession`) maps host `function_call` items onto `RealtimeEvent.tool_call`, emits `usage`, and returns results with `completeTool`.
6
+
7
+ ## When to use it
8
+
9
+ Use it when microphone audio should drive the same tools, approvals, usage ledger, and memory consent as a text run. Do not use it as a second agent loop or a voice-specific policy engine. One-shot TTS/STT stays on [Speech and transcription](speech.md).
10
+
11
+ ## Inputs / request
12
+
13
+ ```ts
14
+ import { resolveDevicePolicy } from "@arnilo/prism";
15
+ import { createOpenAIRealtimeSession } from "@arnilo/prism-providers/openai";
16
+ import { createRealtimeVoiceBridge } from "@arnilo/prism-core/runtime/realtime";
17
+
18
+ const policy = resolveDevicePolicy(
19
+ { kind: "voice", enabled: true, requireApproval: true, sandbox: "voice" },
20
+ { runLimits: { maxTurns: 8, maxToolCalls: 32 } },
21
+ );
22
+ const session = createOpenAIRealtimeSession({
23
+ ownerId: "user-1",
24
+ model: { provider: "openai", model: "gpt-realtime" },
25
+ apiKey,
26
+ tools: [{ name: "lookup", parameters: { type: "object" } }],
27
+ });
28
+ const bridge = createRealtimeVoiceBridge({
29
+ session,
30
+ policy,
31
+ admit: { approved: true, activeSessions: 0 },
32
+ toolNames: ["lookup"],
33
+ strictGovernance: true,
34
+ retainTranscripts: false,
35
+ execute: (call, ctx) => dispatchToolCall({ call, signal: ctx.signal }),
36
+ recordUsage: (usage) => router.recordUsage({ identity, provider: "openai", model, tokens: usage.totalTokens, kind: "generation" }),
37
+ });
38
+ ```
39
+
40
+ | Field | Meaning |
41
+ | --- | --- |
42
+ | `session` | Existing `RealtimeSession` (`sendAudio` / `events` / `interrupt` / `close`). |
43
+ | `policy` + `admit` | `assertDeviceAdmit` on construct, each `sendAudio`, and reconnect (new bridge). |
44
+ | `execute` | Host dispatch (approvals, `toolNames`, effect store). Not provider-hosted calls. |
45
+ | `toolNames` | Same names-only grant as `RunOptions.toolNames`. Omitted = all host tools; `[]` = none. |
46
+ | `strictGovernance` | Provider-hosted tools are unknown, never dispatched. |
47
+ | `seenCallIds` | Reconnect skip list. Duplicate ids are not replayed. |
48
+ | `retainTranscripts` | Default `false`. Audio is never retained. |
49
+
50
+ ## Outputs / response / events
51
+
52
+ `bridge.run()` consumes `session.events()` until close. `snapshot()` reports pending/completed/cancelled/unknown call ids, `interrupted`, `consent`, `effectAfterInterrupt`, and `usageMissing`. Barge-in aborts queued calls before `execute`; an execute that still succeeds after interrupt sets `effectAfterInterrupt` (072 invariant 0). Outbound `audio_delta` is dropped after interrupt until the next `sendAudio`.
53
+
54
+ ## Request/response example
55
+
56
+ ```json
57
+ {
58
+ "type": "response.function_call_arguments.done",
59
+ "call_id": "call_001",
60
+ "name": "lookup",
61
+ "arguments": "{\"q\":\"x\"}"
62
+ }
63
+ ```
64
+
65
+ ## Implementation example
66
+
67
+ See `examples/realtime-voice-host.ts` (network-free mock session, keyboard-free barge-in). Hosts that need a text approval UI call `execute` through the same `dispatchToolCall` / durable-approval path as a text run.
68
+
69
+ ## Extension and configuration notes
70
+
71
+ OpenAI `session.update` advertises at most 32 host function tools. `completeTool` sends `conversation.item.create` (`function_call_output`) then `response.create`. Optional `completeTool` on `RealtimeSession` is the generic gap; transports that cannot complete tools omit it. Transcript memory uses Task 16 `remember` only when `retainTranscripts` is true and the host passes `onTranscript`.
72
+
73
+ ## Security and performance notes
74
+
75
+ - Microphone consent is not tool approval. `revokeConsent` closes the session; later `sendAudio` throws `ERR_PRISM_REALTIME_CONSENT`.
76
+ - Re-admit on every reconnect. Side effects never replay from `seenCallIds`.
77
+ - Raw audio is not made safe by text redaction and is not uploaded or stored by the bridge.
78
+ - Ambiguous outcomes after interrupt stay `unknown`, never fabricated success.
79
+ - Event/audio caps stay on the Realtime session (`maxAudioEventsPerSecond` / `maxBytesPerSecond` / `maxWallMs`). Pending host calls cap at 32.
80
+
81
+ ## Related APIs
82
+
83
+ - [Device adapters](device-adapters.md): deny-by-default voice admission.
84
+ - [Speech and transcription](speech.md): one-shot TTS/STT.
85
+ - [Tools](tools.md): `RunOptions.toolNames` grant used by the bridge.
86
+ - [Runs and usage ledger](runs-and-usage.md): voice tokens settle as `kind: "generation"`.
87
+ - [OpenAI provider](providers/openai.md): `createOpenAIRealtimeSession`.
@@ -5,25 +5,27 @@
5
5
  ## What it does
6
6
 
7
7
 
8
- Prism's current **0.5.x** line has **10 publishable manifests**: the root `@arnilo/prism` core package plus **9 workspace packages** — **19 provider adapters** (19 provider adapter subpaths inside the `@arnilo/prism-providers` family), 3 `prism-*` family/profile packages, and 6 capability packages. (Generated by `node scripts/package-truth.mjs` → `scripts/package-truth.json` — the manifest-derived single source for counts, provider membership, umbrella closures, and profile closures.) The last lockstep cut was 0.3.0; Decision B now publishes changed packages independently inside `^0.3.0` — the plan 039 changed-package cut moved root `@arnilo/prism` and every plan-035+ changed package to **0.3.1**, and the plan 050 changed-package cut moved root plus four changed packages to **0.3.2**; the plan 041-044 changed-package cut moves root to **0.3.3** with `@arnilo/prism-memory@0.3.2` (composite recall scoring), `@arnilo/prism-evals@0.3.1` (trace-to-dataset curation), the three session-store packages at **0.3.1** (run-ledger `promptVersion` provenance), and the initial `@arnilo/prism-prompts@0.0.1` (independent opt-in, outside `prism-all`); plan 054 consolidation then folded `@arnilo/prism-browser` and `@arnilo/prism-obscura` into the `@arnilo/prism-web-tools` family as `/browser` and `/obscura` subpaths, folded `@arnilo/prism-rag`, both compaction strategies, `@arnilo/prism-graft`, and `@arnilo/prism-wiki` into the `@arnilo/prism-memory` family as `/rag`, `/compaction/llm`, `/compaction/observational-memory`, `/graft`, and `/wiki` subpaths (deleting the `@arnilo/prism-compaction` profile), and folded all 17 `@arnilo/prism-provider-*` packages into the `@arnilo/prism-providers` family as `/<adapter>` subpaths (Azure/Bedrock/Vertex stop being special all-only manifests); independent publication continues inside `^0.3.0` ranges (which satisfy 0.3.1, 0.3.2, and 0.3.3). This page describes how they are packed, what each tarball contains, how to install them, the required non-optional **caret** `@arnilo/prism@^0.5.6` peer range, the release workflow, and the offline test budget. The measurable 1.0 readiness gates (command-per-gate) live in [`0.1.0-readiness.md`](history/./0.1.0-readiness.md).
8
+ Prism's current **0.7.0** line has **10 publishable manifests**: the root `@arnilo/prism` core package plus **9 workspace packages** — **19 provider adapters** (19 provider adapter subpaths inside the `@arnilo/prism-providers` family), 3 `prism-*` family/profile packages, and 6 capability packages. (Generated by `node scripts/package-truth.mjs` → `scripts/package-truth.json` — the manifest-derived single source for counts, provider membership, umbrella closures, and profile closures.) The last lockstep cut was 0.3.0; Decision B now publishes changed packages independently inside `^0.3.0` — the plan 039 changed-package cut moved root `@arnilo/prism` and every plan-035+ changed package to **0.3.1**, and the plan 050 changed-package cut moved root plus four changed packages to **0.3.2**; the plan 041-044 changed-package cut moves root to **0.3.3** with `@arnilo/prism-memory@0.3.2` (composite recall scoring), `@arnilo/prism-evals@0.3.1` (trace-to-dataset curation), the three session-store packages at **0.3.1** (run-ledger `promptVersion` provenance), and the initial `@arnilo/prism-prompts@0.0.1` (independent opt-in, outside `prism-all`); plan 054 consolidation then folded `@arnilo/prism-browser` and `@arnilo/prism-obscura` into the `@arnilo/prism-web-tools` family as `/browser` and `/obscura` subpaths, folded `@arnilo/prism-rag`, both compaction strategies, `@arnilo/prism-graft`, and `@arnilo/prism-wiki` into the `@arnilo/prism-memory` family as `/rag`, `/compaction/llm`, `/compaction/observational-memory`, `/graft`, and `/wiki` subpaths (deleting the `@arnilo/prism-compaction` profile), and folded all 17 `@arnilo/prism-provider-*` packages into the `@arnilo/prism-providers` family as `/<adapter>` subpaths (Azure/Bedrock/Vertex stop being special all-only manifests); independent publication continues inside `^0.3.0` ranges (which satisfy 0.3.1, 0.3.2, and 0.3.3). This page describes how they are packed, what each tarball contains, how to install them, the required non-optional **caret** `@arnilo/prism@^0.7.0` peer range, the release workflow, and the offline test budget. The measurable 1.0 readiness gates (command-per-gate) live in [`0.1.0-readiness.md`](history/./0.1.0-readiness.md).
9
9
 
10
10
  Core `@arnilo/prism` ships runtime, CLI, templates, and docs. Every code package has a required `@arnilo/prism` peer inside the Decision B window — the caret current spec is `@arnilo/prism@^0.3.3` and every declared window peer satisfies it: packages republishing in the plan 050 cut carry `^0.3.2`; the plan 039 set keeps `^0.3.1`; unchanged packages keep their `^0.3.0` peer; profiles are pure manifests. The plan 050 republished set declares the required `@arnilo/prism@^0.3.2` peer; the plan 041-044 republished set keeps its existing `^0.3.0` window peer; unchanged packages keep their prior window. Installation activates no provider, listener, database, browser, credential, or tool capability.
11
11
 
12
+ The **0.6.0 and 0.7.0 lockstep cuts** each moved all ten manifests together: the current declared peer is `@arnilo/prism@^0.7.0` on every package, and `release.mjs` lockstep mode fails closed on any internal range that merely satisfies the cut version instead of matching it. The independent-publication history above (0.3.x, 0.4.x, 0.5.x) describes how the line grew when packages moved separately.
13
+
12
14
  <!-- generated:package-truth:inventory begin -->
13
15
  **10 publishable manifests** — root `@arnilo/prism` plus 9 workspace packages (3 `prism-*` family packages, 6 capability packages). Generated by `node scripts/package-truth.mjs --emit-docs` — do not hand-edit.
14
16
 
15
17
  | package | version | notes |
16
18
  | --- | --- | --- |
17
- | `@arnilo/prism` | 0.5.6 | core — runtime, CLI/RPC, templates, docs |
18
- | `@arnilo/prism-coding-tools` | 0.5.6 | family — /agent, /security, /document-reader, /openapi, /computer-use-linux, /dev, /caveman, /ponytail, /impeccable subpaths |
19
- | `@arnilo/prism-core` | 0.5.6 | family — /runtime, /sessions, /governance, /credentials, /enterprise, /work, /validation subpaths |
20
- | `@arnilo/prism-providers` | 0.5.6 | family — all provider adapters as `/<adapter>` subpaths |
21
- | `@arnilo/prism-acp-agent` | 0.5.6 | capability — ACP adapter |
22
- | `@arnilo/prism-ag-ui` | 0.5.6 | capability — AG-UI/A2A/A2UI adapter |
23
- | `@arnilo/prism-mcp` | 0.5.6 | capability — MCP client/server/OAuth interop |
24
- | `@arnilo/prism-memory` | 0.5.6 | capability — memory plus /rag, /compaction/*, /graft, /wiki subpaths |
25
- | `@arnilo/prism-office` | 0.5.6 | capability — /documents, /sheets, /diagrams subpaths |
26
- | `@arnilo/prism-web-tools` | 0.5.6 | capability — Brave/Exa/Firecrawl plus peer-gated /browser and /obscura subpaths |
19
+ | `@arnilo/prism` | 0.7.0 | core — runtime, CLI/RPC, templates, docs |
20
+ | `@arnilo/prism-coding-tools` | 0.7.0 | family — /agent, /security, /document-reader, /openapi, /computer-use-linux, /dev, /caveman, /ponytail, /impeccable subpaths |
21
+ | `@arnilo/prism-core` | 0.7.0 | family — /runtime, /sessions, /governance, /credentials, /enterprise, /work, /validation subpaths |
22
+ | `@arnilo/prism-providers` | 0.7.0 | family — all provider adapters as `/<adapter>` subpaths |
23
+ | `@arnilo/prism-acp-agent` | 0.7.0 | capability — ACP adapter |
24
+ | `@arnilo/prism-ag-ui` | 0.7.0 | capability — AG-UI/A2A/A2UI adapter |
25
+ | `@arnilo/prism-mcp` | 0.7.0 | capability — MCP client/server/OAuth interop |
26
+ | `@arnilo/prism-memory` | 0.7.0 | capability — memory plus /rag, /compaction/*, /fabric, /graft, /wiki subpaths |
27
+ | `@arnilo/prism-office` | 0.7.0 | capability — /documents, /sheets, /diagrams subpaths |
28
+ | `@arnilo/prism-web-tools` | 0.7.0 | capability — Brave/Exa/Firecrawl plus peer-gated /browser and /obscura subpaths |
27
29
  <!-- generated:package-truth:inventory end -->
28
30
 
29
31
 
@@ -32,30 +34,30 @@ Core `@arnilo/prism` ships runtime, CLI, templates, and docs. Every code package
32
34
 
33
35
  | adapter package | version |
34
36
  | --- | --- |
35
- | `@arnilo/prism-providers/ai-sdk` | 0.5.6 |
36
- | `@arnilo/prism-providers/alibaba` | 0.5.6 |
37
- | `@arnilo/prism-providers/anthropic` | 0.5.6 |
38
- | `@arnilo/prism-providers/azure` | 0.5.6 |
39
- | `@arnilo/prism-providers/bedrock` | 0.5.6 |
40
- | `@arnilo/prism-providers/clinepass` | 0.5.6 |
41
- | `@arnilo/prism-providers/commandcode` | 0.5.6 |
42
- | `@arnilo/prism-providers/deepseek` | 0.5.6 |
43
- | `@arnilo/prism-providers/google` | 0.5.6 |
44
- | `@arnilo/prism-providers/hyper` | 0.5.6 |
45
- | `@arnilo/prism-providers/kimi` | 0.5.6 |
46
- | `@arnilo/prism-providers/model-discovery` | 0.5.6 |
47
- | `@arnilo/prism-providers/neuralwatt` | 0.5.6 |
48
- | `@arnilo/prism-providers/ollama` | 0.5.6 |
49
- | `@arnilo/prism-providers/openai` | 0.5.6 |
50
- | `@arnilo/prism-providers/opencode-go` | 0.5.6 |
51
- | `@arnilo/prism-providers/openrouter` | 0.5.6 |
52
- | `@arnilo/prism-providers/vertex` | 0.5.6 |
53
- | `@arnilo/prism-providers/xai` | 0.5.6 |
54
- | `@arnilo/prism-providers/zai` | 0.5.6 |
37
+ | `@arnilo/prism-providers/ai-sdk` | 0.7.0 |
38
+ | `@arnilo/prism-providers/alibaba` | 0.7.0 |
39
+ | `@arnilo/prism-providers/anthropic` | 0.7.0 |
40
+ | `@arnilo/prism-providers/azure` | 0.7.0 |
41
+ | `@arnilo/prism-providers/bedrock` | 0.7.0 |
42
+ | `@arnilo/prism-providers/clinepass` | 0.7.0 |
43
+ | `@arnilo/prism-providers/commandcode` | 0.7.0 |
44
+ | `@arnilo/prism-providers/deepseek` | 0.7.0 |
45
+ | `@arnilo/prism-providers/google` | 0.7.0 |
46
+ | `@arnilo/prism-providers/hyper` | 0.7.0 |
47
+ | `@arnilo/prism-providers/kimi` | 0.7.0 |
48
+ | `@arnilo/prism-providers/model-discovery` | 0.7.0 |
49
+ | `@arnilo/prism-providers/neuralwatt` | 0.7.0 |
50
+ | `@arnilo/prism-providers/ollama` | 0.7.0 |
51
+ | `@arnilo/prism-providers/openai` | 0.7.0 |
52
+ | `@arnilo/prism-providers/opencode-go` | 0.7.0 |
53
+ | `@arnilo/prism-providers/openrouter` | 0.7.0 |
54
+ | `@arnilo/prism-providers/vertex` | 0.7.0 |
55
+ | `@arnilo/prism-providers/xai` | 0.7.0 |
56
+ | `@arnilo/prism-providers/zai` | 0.7.0 |
55
57
  <!-- generated:package-truth:providers end -->
56
58
 
57
59
 
58
- Core ships `dist`, docs, templates, and `CHANGELOG.md`; code packages ship compiled output, README, license, and changelog. Family/profile packages ship manifest, README, and changelog. `@arnilo/prism-providers` is the unified provider family: all provider adapters ship as `dist/<adapter>` subpaths in one tarball (Azure/Bedrock/Vertex included), with the required `@arnilo/prism` peer as the only dependency and `@ai-sdk/provider` an optional peer of `/ai-sdk`. `@arnilo/prism-core` provides the unified runtime, sessions, governance, credentials, enterprise persistence, and work integration family package. `@arnilo/prism-web-tools` provides the unified web tools family: root Brave/Exa/Firecrawl research tools plus `/browser` (Playwright-peer gated) and `/obscura` (host-binary + MCP gated) subpaths. `@arnilo/prism-memory` provides the unified memory and context family: root working/vector memory plus `/rag` (with `/rag/loaders` and `/rag/parsers`), `/compaction/llm`, `/compaction/observational-memory`, `/graft` (`@nanonets/graft` optional-peer gated), and `/wiki` subpaths, including the `prism-wiki` bin and bundled skills. `@arnilo/prism-coding-tools/dev` ships the loopback dev inspector — the `prism-dev` bin, the `prism dev` CLI composition, and the `/dev/cli` export the core CLI delegates to for `prism dev` (plan 040 Tasks 4–5); dev tooling is developer-time only and must never be the production API boundary. `@arnilo/prism-core/governance/prompts` (plan 042) is the versioned prompt registry: an explicit host opt-in with no first-party package depending on it — unlike `@arnilo/prism-memory` (a family member) and `@arnilo/prism-core/governance/evals` (used by the promotion helper as an optional peer). `@arnilo/prism-office` (plan 054 Task 8, absorbing plans 051–053) is the unified office family: `/documents`, `/sheets`, and `/diagrams` subpaths in one tarball with exact-pinned `@office-open/{docx,xlsx,pptx,xml}` regular dependencies and an optional `playwright-core` peer for the diagrams live embed. Importing one subpath never evaluates another. The three draft names `@arnilo/prism-documents`/`sheets`/`diagrams` were never published.
60
+ Core ships `dist`, docs, templates, and `CHANGELOG.md`; code packages ship compiled output, README, license, and changelog. Family/profile packages ship manifest, README, and changelog. `@arnilo/prism-providers` is the unified provider family: all provider adapters ship as `dist/<adapter>` subpaths in one tarball (Azure/Bedrock/Vertex included), with the required `@arnilo/prism` peer as the only dependency and `@ai-sdk/provider` an optional peer of `/ai-sdk`. `@arnilo/prism-core` provides the unified runtime, sessions, governance, credentials, enterprise persistence, and work integration family package. `@arnilo/prism-web-tools` provides the unified web tools family: root Brave/Exa/Firecrawl research tools plus `/browser` (Playwright-peer gated) and `/obscura` (host-binary + MCP gated) subpaths. `@arnilo/prism-memory` provides the unified memory and context family: root working/vector memory plus `/rag` (with `/rag/loaders` and `/rag/parsers`), `/compaction/llm`, `/compaction/observational-memory`, `/graft` (`@nanonets/graft` optional-peer gated), and `/wiki` subpaths, including the `prism-wiki` bin and bundled skills. `@arnilo/prism-coding-tools/dev` ships the loopback dev inspector — the `prism-dev` bin, the `prism dev` CLI composition, and the `/dev/cli` export the core CLI delegates to for `prism dev` (plan 040 Tasks 4–5); dev tooling is developer-time only and must never be the production API boundary. `@arnilo/prism-core/governance/prompts` (plan 042) is the versioned prompt registry: an explicit host opt-in with no first-party package depending on it — unlike `@arnilo/prism-memory` (a family member) and `@arnilo/prism-core/governance/evals` (used by the promotion helper as an optional peer). `@arnilo/prism-office` (plan 054 Task 8, absorbing plans 051–053) is the unified office family: `/documents`, `/sheets`, and `/diagrams` subpaths in one tarball with exact-pinned `@office-open/{docx,xlsx,pptx,xml}` regular dependencies and no optional peer (the diagrams embed is browser-agnostic; `playwright-core` stays a devDependency for the gated live draw.io test). Importing one subpath never evaluates another. The three draft names `@arnilo/prism-documents`/`sheets`/`diagrams` were never published.
59
61
 
60
62
  ## When to use it
61
63
 
@@ -82,7 +84,7 @@ Consumers install the core package for the runtime and add first-party packages
82
84
  | Install core + a single provider adapter | `npm install @arnilo/prism @arnilo/prism-providers` (import `@arnilo/prism-providers/openai`) |
83
85
  | 0.0.12 AG-UI (after release) | `npm install @arnilo/prism@0.0.12 @arnilo/prism-ag-ui@0.0.12` |
84
86
  | Install bounded web research tools | `npm install @arnilo/prism @arnilo/prism-web-tools @arnilo/prism-core` |
85
- | Install browser automation tools (Playwright-peer gated `/browser`) | `npm install @arnilo/prism @arnilo/prism-web-tools playwright-core@1.61.0` |
87
+ | Install browser automation tools (Playwright-peer gated `/browser`) | `npm install @arnilo/prism @arnilo/prism-web-tools playwright-core@1.63.0` |
86
88
  | Install Obscura browser-engine tools (host supplies the binary; `/obscura`) | `npm install @arnilo/prism @arnilo/prism-web-tools @arnilo/prism-mcp` |
87
89
  | Install RAG retrieval (memory family `/rag`) | `npm install @arnilo/prism @arnilo/prism-memory` |
88
90
  | Install the Wiki CLI and skills (memory family `/wiki`) | `npm install @arnilo/prism @arnilo/prism-memory` (`npx prism-wiki --help`) |
@@ -143,7 +145,7 @@ A packed tarball contains only public compiled output and release files:
143
145
  - Code packages ship `README.md`, `LICENSE`, and `CHANGELOG.md`; family/profile packages ship `README.md` and `CHANGELOG.md`.
144
146
  - The core tarball additionally ships the full `docs/` directory (the docs hub), `templates/init/`, and the `templates/` gallery (e.g. `deep-research`) used by `prism init`.
145
147
  - `dist/cli.js` and the `bin` link in core.
146
- - **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.5.6.tgz`; family packages produce `arnilo-prism-core-0.5.6.tgz`, `arnilo-prism-coding-tools-0.5.6.tgz`, `arnilo-prism-providers-0.5.6.tgz` (all 19 adapters inside), `arnilo-prism-memory-0.5.6.tgz`, `arnilo-prism-web-tools-0.5.6.tgz`, and `arnilo-prism-office-0.5.6.tgz`; capability packages like `arnilo-prism-mcp-0.5.6.tgz` carry their own package version. Independent-package tags carry their own version. 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).
148
+ - **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.7.0.tgz`; family packages produce `arnilo-prism-core-0.7.0.tgz`, `arnilo-prism-coding-tools-0.7.0.tgz`, `arnilo-prism-providers-0.7.0.tgz` (all 19 adapters inside), `arnilo-prism-memory-0.7.0.tgz`, `arnilo-prism-web-tools-0.7.0.tgz`, and `arnilo-prism-office-0.7.0.tgz`; capability packages like `arnilo-prism-mcp-0.7.0.tgz` carry their own package version. Independent-package tags carry their own version. 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).
147
149
 
148
150
  Excluded from every tarball by `files` negation:
149
151
 
@@ -242,14 +244,19 @@ Every side effect carries the run suffix and is cleaned up idempotently (PR clos
242
244
 
243
245
  Frozen by Phase 12 Task 0 in `scripts/phase12-freeze-manifest.json` (schema gate `node --test scripts/phase12-freeze.test.mjs`; docs agreement tripwired in the docs test suite). Any change requires a recorded freeze deviation in plan 012.
244
246
 
247
+ | Runtime | Supported | Measured in CI |
248
+ | --- | --- | --- |
249
+ | Node | 22, 24 (`engines.node >=22`) | `verify` runs the full `sdk:ready` gate on Node 24; `node22-compat` builds and imports every public root `exports` target on Node 22. Node 20 support was dropped in 0.6.0 (`dev-006`; Node 20 reached upstream end-of-life 2026-04-30); 0.7.0 keeps the same floor. |
250
+ | PostgreSQL | 16 (`pgvector/pgvector:pg16`) | `postgres-integration` service container |
251
+
245
252
  ## Extension and configuration notes
246
253
 
247
254
 
248
- - **Required `@arnilo/prism` peer.** Every first-party code package declares a non-optional **caret** `@arnilo/prism@^0.3.3` peer (plan 041-044 republished set; the plan 039 set keeps `^0.3.1` and unchanged packages keep the prior `^0.3.0` window peer — all satisfy the root) (`peerDependenciesMeta` must not mark `@arnilo/prism` optional; other peers such as `playwright-core` may be optional). **Peer-version policy (plan 030, Decision B — independent packages):** internal ranges stay inside the 0.x `^0.3.0` window, so a package may patch independently while consumers remain on a compatible 0.3.x line. A package outside that window (for example `0.4.0`) is refused by the release gate until the next coordinated peer bump. 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.
255
+ - **Required `@arnilo/prism` peer.** Every first-party code package declares a non-optional **caret** `@arnilo/prism@^0.7.0` peer (the lockstep 0.7.0 cut rewrote every internal range; the version-literal gate rejects a declared range that only satisfies the cut version) (`peerDependenciesMeta` must not mark `@arnilo/prism` optional; other peers such as `playwright-core` may be optional). **Peer-version policy (plan 030, Decision B — independent packages):** internal ranges stay inside the caret window of the cut they shipped in, so a package may patch independently while consumers remain on a compatible 0.x line. A package outside that window is refused by the release gate until the next coordinated peer bump. 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.
249
256
  - **Public access.** All 56 manifests (root + 55 workspace packages: 49 code packages + 6 pure-manifest family/profile packages — the 10 `prism-*` family/profile set is the 6 pure-manifest profiles plus the 4 code packages `prism-caveman`, `prism-impeccable`, `prism-openapi-tools`, `prism-ponytail`) declare `"publishConfig": { "access": "public" }`; the publisher also passes `--access public` explicitly because scoped packages otherwise default to restricted on first publish.
250
257
  - **Shipped vs repository docs.** The npm tarball ships `docs/` pages linked from `docs/index.md` (public API, security, migration, providers, install). It excludes `docs/_evidence/` (per-phase evidence freezes, including `release-0.2.7-evidence.md`), `docs/release-*-evidence.md`, and `docs/api-page-template.md`. Those files remain in git for audit. `dist/__tests__` and `*.map` stay excluded.
251
258
  - **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).
252
- - **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. `publish` runs on `v0.3.0` for the one lockstep cut and on `@arnilo/*@*` package tags afterward; it needs all five gates, preserves clean tagged/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`.
259
+ - **Release workflow.** `.github/workflows/release.yml` has six jobs. `verify` runs network-free SDK readiness on Node 24; `node22-compat` builds/imports every public root `exports` default target on Node 22 for declared `engines.node >=22` (docs examples need Node >=22.6 native TypeScript stripping, inside the ≥22 floor); `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. `publish` runs on `v0.3.0` for the one lockstep cut and on `@arnilo/*@*` package tags afterward; it needs all five gates, preserves clean tagged/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`.
253
260
  - **Protected integration matrix (plan 060).** Required on protected branches; pull requests do not run these jobs (no PR secrets). Connection strings are masked in logs.
254
261
 
255
262
  | Job | Workflow | Cadence | Evidence |
@@ -292,17 +299,17 @@ Frozen by Phase 12 Task 0 in `scripts/phase12-freeze-manifest.json` (schema gate
292
299
  - 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.
293
300
  - 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.
294
301
  - **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.
295
- - **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).
302
+ - **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`), plus Obscura (`PRISM_ENABLE_OBSCURA_GATE`, `PRISM_OBSCURA_BIN`) and draw.io (`PRISM_ENABLE_DRAWIO_GATE`, `PRISM_TEST_DRAWIO_URL`) legs whose suites live in `@arnilo/prism-web-tools` and `@arnilo/prism-office` — the draw.io leg runs through `scripts/live-matrix.mjs` with `PRISM_LIVE_FILTER=office/drawio-live`; it receives no provider/npm/OIDC secrets, and uploads only a redacted aggregate status artifact (7-day retention).
296
303
  - **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.
297
304
  - **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.
298
- - **Packed-install e2e journeys (plan 012 Task 3).** `scripts/e2e-enterprise-journey.test.mjs` and `scripts/e2e-coding-journey.test.mjs` pack the first-party packages for their journey, install the exact tarballs into a fresh consumer project, and run the journey script inside that consumer — public exports only, no workspace-relative resolution (asserted per run). The **enterprise journey** composes OIDC identity → OPA policy decision (durable ledger) → agent run with durable events (memory, or real PostgreSQL when `PRISM_TEST_POSTGRES_URL` is set) → batched approval → OpenAPI side effect with idempotency → artifact upload + signed delivery, with policy-deny and hash-mismatch fail-closed injections. The **coding journey** composes an ACP editor session (init capability negotiation, session new + load/resume) → bounded coding tools (git-aware list/search, glob, read-before-write write, delete, move) → sandboxed process session → forge handoff with idempotent PR creation, with execution-policy and read-before-write denial paths. Each fixture asserts the installed version matches the packed manifest graph and stays within the frozen `e2eJourneyFixtureMsCeiling` (120 s in `scripts/phase12-freeze-manifest.json`).
305
+ - **Packed-install e2e journeys (plan 012 Task 3).** `scripts/e2e-enterprise-journey.test.mjs` and `scripts/e2e-coding-journey.test.mjs` pack the first-party packages for their journey, install the exact tarballs into a fresh consumer project, and run the journey script inside that consumer — public exports only, no workspace-relative resolution (asserted per run). The **enterprise journey** composes OIDC identity → OPA policy decision (durable ledger) → agent run with durable events (memory, or real PostgreSQL when `PRISM_TEST_POSTGRES_URL` is set **and the `pg` peer is installed in that consumer**) → batched approval → OpenAPI side effect with idempotency → artifact upload + signed delivery, with policy-deny and hash-mismatch fail-closed injections. The durable leg is peer-gated and never assumed from the env alone: with `PRISM_TEST_POSTGRES_URL` ambient but `pg` unresolvable (the default, since `pg` is a peer of `@arnilo/prism-core` and the consumer installs only Prism tarballs), the fixture prints `SKIP durable postgres leg: …` and runs the memory event source instead of dying with `ERR_MODULE_NOT_FOUND`; the test reports that line as a TAP diagnostic and asserts it, so the skip can never be silent. Scope the env to the phase that needs it (`PRISM_TEST_POSTGRES_URL=… npm run test:postgres`, or `phase release:gate` in `.github/workflows/release.yml`) rather than exporting it globally. The **coding journey** composes an ACP editor session (init capability negotiation, session new + load/resume) → bounded coding tools (git-aware list/search, glob, read-before-write write, delete, move) → sandboxed process session → forge handoff with idempotent PR creation, with execution-policy and read-before-write denial paths. Each fixture asserts the installed version matches the packed manifest graph and stays within the frozen `e2eJourneyFixtureMsCeiling` (120 s in `scripts/phase12-freeze-manifest.json`).
299
306
  - **Protected restart-recovery leg (plan 012 Task 4).** `scripts/phase12-restart-recovery.test.mjs` (run by `npm run test:postgres` after the Phase 7 suite) spawns two real processes against one PostgreSQL schema: replica A runs a durable agent, suspends on a batched tool approval, appends durable events and is then SIGKILLed by the driver; replica B reconnects and resumes. Operators re-run the leg with `PRISM_TEST_POSTGRES_URL="postgresql://…" npm run test:postgres` against a disposable PostgreSQL 16 (e.g. `pgvector/pgvector:pg16`). Without the URL the gate records a named `BLOCKED GATE` failure instead of skipping. Reconnect p95 and 16-worker append contention p95 are asserted against the frozen `reconnectP95Ms` / `pointOpP95Ms` ceilings; set `PRISM_PHASE12_RECORD_EVIDENCE=1` to refresh the checked-in evidence file `scripts/phase12-restart-recovery.json`.
300
- - **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). Plan 057 retired the historical `phase11-freeze` … `phase34-freeze`/`phase30-release` gate files from the default suite (17 files, 247 tests) — they stay in the repo as immutable release evidence and remain audit-runnable standalone via `node --test scripts/<file>.test.mjs`, with their self-wiring assertions flipped to assert non-wiring so the retirement cannot silently regress. Release/security gates (`release-gate`, `tooling-gate`, `budget-gate`, `phase23-quality-gates`, `phase8–11` conformance) stay in the run. 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, pack dry-run, and the coverage summary, so it is allowed to exceed the `npm test` budget while remaining network-free. `npm run test:coverage` additionally runs the combined coverage summary (`npm run coverage:summary`, ~25s local: core + each workspace suite once with `--experimental-test-coverage`; measured total ~70s on Node 24) — additive reporting only, the core gate stays the only hard threshold. 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.
307
+ - **Offline test budget.** The default `npm test` (no `PRISM_LIVE_PROVIDER_TESTS`) is pinned at **< 60s** with a measured local baseline of ~45s (build ~18s + network-free tests/workspace tests/packaging smoke ~27s; the 0.5.x baselines were measured on Node 20, the current ones on Node 24). Plan 057 retired the historical `phase11-freeze` … `phase34-freeze`/`phase30-release` gate files from the default suite (17 files, 247 tests) — they stay in the repo as immutable release evidence and remain audit-runnable standalone via `node --test scripts/<file>.test.mjs`, with their self-wiring assertions flipped to assert non-wiring so the retirement cannot silently regress. Their criteria are content-verified, not filesystem-verified (plan 071 Tasks 5 and 10): capture ordering compares the baselines' recorded `captured` dates instead of file mtimes, phase markers resolve against the live file plus the frozen lineage (the phase plan of record and `docs/history/`) so a living doc that is rewritten between releases cannot fail an audit gate (a marker set that is checked this way is declared in the gate's own manifest — `phase26-freeze-manifest.json` `lineageCheckedFiles` — so the fallback stays bounded to the files that need it), a path retired since the freeze resolves to its recorded archive instead of being hash-compared (`status: "retired"` + `retiredTo` in the baseline, with the Task 0 `sha256` kept as history), and a version literal is asserted as a *transition* (`!`-prefixed marker: the pre-cut literal must be gone) rather than an equality that the next release sweep would invalidate. Release/security gates (`release-gate`, `tooling-gate`, `budget-gate`, `phase23-quality-gates`, `phase8–11` conformance) stay in the run. 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, pack dry-run, and the coverage summary, so it is allowed to exceed the `npm test` budget while remaining network-free. `npm run test:coverage` additionally runs the combined coverage summary (`npm run coverage:summary`, ~25s local: core + each workspace suite once with `--experimental-test-coverage`; measured total ~70s on Node 24) — additive reporting only, the core gate stays the only hard threshold. The CI `sdk:ready` step has `timeout-minutes: 30` as a hang backstop; the separate Node 22 compatibility job has `timeout-minutes: 10`. 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.
301
308
 
302
309
  ### GitHub Actions pipeline (0.0.27+)
303
310
 
304
311
 
305
- `.github/workflows/release.yml` is the single pipeline: **push to `main`** runs CI (`verify` = `npm run sdk:ready`, `node20-compat`, `postgres-integration`, `supply-chain`), **`v0.3.0` or `@arnilo/*@*` package tags** additionally run `codeql-release` and the `publish` job (deterministic `release:publish` in dependency order with provenance attestation). `security.yml` adds CodeQL/dependency-review/SBOM on push and PR; `live-canaries.yml` and `sandbox-browser.yml` are scheduled. All actions are SHA-pinned (2026-08-06 fix: CodeQL pins were invalid 404 refs and `workflow_dispatch` was missing — re-verified every pin against its upstream repo). Prerequisites outside the repo: Actions enabled in repository settings, and the `NPM_TOKEN` secret (with `id-token: write` for provenance). To re-cut a tag after a fix commit, delete and recreate it (`git push origin :v0.0.28 && git push origin v0.0.28`) so the tag creation event fires.
312
+ `.github/workflows/release.yml` is the single pipeline: **push to `main`** runs CI (`verify` = `npm run sdk:ready`, `node22-compat`, `postgres-integration`, `supply-chain`), **`v0.3.0` or `@arnilo/*@*` package tags** additionally run `codeql-release` and the `publish` job (deterministic `release:publish` in dependency order with provenance attestation). `security.yml` adds CodeQL/dependency-review/SBOM on push and PR; `live-canaries.yml` and `sandbox-browser.yml` are scheduled. All actions are SHA-pinned (2026-08-06 fix: CodeQL pins were invalid 404 refs and `workflow_dispatch` was missing — re-verified every pin against its upstream repo). Prerequisites outside the repo: Actions enabled in repository settings, and the `NPM_TOKEN` secret (with `id-token: write` for provenance). To re-cut a tag after a fix commit, delete and recreate it (`git push origin :v0.0.28 && git push origin v0.0.28`) so the tag creation event fires.
306
313
 
307
314
  ## Formatting, linting, and coverage
308
315
 
@@ -314,7 +321,7 @@ Prism uses one tool for formatting and linting — [Biome](https://biomejs.dev)
314
321
  | `npm run lint` | `biome lint .` — fails on any lint error (warnings are non-fatal). |
315
322
  | `npm run format:check` | `biome format .` — fails if any file is unformatted. |
316
323
  | `npm run format` | `biome format --write .` — normalizes formatting in place. |
317
- | `npm run test:coverage` | `node --test --experimental-test-coverage` over the core suite with enforced minimums: **lines 60%**, **functions 70%**, **branches 75%** (current baseline ≈ 90.5 / 84.2 / 90.6), then `scripts/coverage-summary.mjs` + the `phase23-coverage` gate. Excludes `__tests__/`, `node_modules/`, `scripts/`, and `packages/` from the core report. |
324
+ | `npm run test:coverage` | `node --test --experimental-test-coverage` over the core suite with enforced minimums: **lines 60%**, **functions 70%**, **branches 75%** (current baseline ≈ 92.0 / 85.0 / 92.6), then `scripts/coverage-summary.mjs` + the `phase23-coverage` gate. Excludes `__tests__/`, `node_modules/`, `scripts/`, and `packages/` from the core report. |
318
325
 
319
326
  All four gates run inside `npm run sdk:ready` (after `typecheck`, before `pack:dry-run`). A few rules are disabled in `biome.json` because they are false positives for this codebase: `noControlCharactersInRegex` and `noAssignInExpressions` (security/redaction code intentionally matches control characters and uses `while ((m = re.exec(…)))` loops), `noShadowRestrictedNames`, `noThenProperty` (the workflow DSL has a legitimate `then` branch field), `noExplicitAny`, `noVoidTypeReturn`, and `useYield`. Raise the coverage thresholds in `package.json` `test:coverage` as the baseline climbs.
320
327
 
@@ -326,13 +333,14 @@ Workspace coverage rows used to include the symlinked root core `dist/` (workspa
326
333
  | Fact | Value |
327
334
  | --- | --- |
328
335
  | Workspace include filter | `--test-coverage-include=dist/**` per package (package-local denominator) |
329
- | Per-package gate | `lines >= threshold` from `scripts/coverage-thresholds.json` (frozen 2026-08-14 = recompute − 3pp, two runs were byte-identical); branches/functions recorded, not gated |
330
- | Protected exceptions | `@arnilo/prism-core/sessions/postgres`, `@arnilo/prism-core/enterprise/postgres`, `@arnilo/prism-memory`, `@arnilo/prism-core/sessions/nats` — durable legs need `PRISM_TEST_POSTGRES_URL` or a real NATS server; plus `@arnilo/prism-coding-tools/security` — native-sandbox legs probe `unshare --net` (NETNS) and skip on CI runners (host runs exercise them); exempt from the gate, reported separately with the reason |
331
- | Artifact | `scripts/coverage-summary.json` (gitignored, CI-retained): per-package `lines`/`branches`/`functions`/`denominatorFiles`/`threshold`/`pass`/`protectedException` + `belowThreshold` |
336
+ | Workspace discovery | any `*.test.js` under `packages/<name>/dist/**`, nested layouts included (`@arnilo/prism-acp-agent` builds to `dist/src/__tests__`, `@arnilo/prism-office` to `dist/<area>/__tests__`) — all 9 workspace packages are measured |
337
+ | Per-package gate | `lines >= threshold` from `scripts/coverage-thresholds.json` (recaptured 2026-09-11 = min of two back-to-back runs − 3pp; the two runs differed by ≤ 0.02pp); branches/functions recorded, not gated. `phase23-coverage` also fails when a row names a package that is not in the live workspace graph — retired rows must be pruned |
338
+ | Protected exceptions | `@arnilo/prism-core` only (durable postgres/NATS legs need `PRISM_TEST_POSTGRES_URL` / `PRISM_TEST_NATS_URL`); exempt from the gate and reported separately with the reason. Env- or capability-gated legs elsewhere (memory postgres, coding-tools native sandbox, provider live legs) skip as protected skips but their packages stay gated on the measured run |
339
+ | Artifact | `scripts/coverage-summary.json` (gitignored, CI-retained): per-package `lines`/`branches`/`functions`/`denominatorFiles`/`threshold`/`pass`/`protectedException` + `belowThreshold`; a row whose child failed additionally carries `status`/`exitCode`/`tail` (a redacted tail of the child's output) |
332
340
  | Fail-closed | a non-protected package below its threshold, a suite failure, or a run producing no coverage data exits non-zero; a missing threshold entry is a config error |
333
341
  | Overrides | `PRISM_COVERAGE_THRESHOLDS`, `PRISM_COVERAGE_ARTIFACT` (used by the gate regression) |
334
342
 
335
- A new workspace package must add an evidence-based threshold entry (or a `protectedException` reason) to `scripts/coverage-thresholds.json` before `test:coverage` passes.
343
+ A new workspace package must add an evidence-based threshold entry (or a `protectedException` reason) to `scripts/coverage-thresholds.json` before `test:coverage` passes, and a removed package's row must be pruned in the same change (the retired-row assertion in `scripts/phase23-coverage.test.mjs` fails otherwise). Recapture the rows from a `scripts/coverage-summary.json` written by two back-to-back runs; never hand-edit a percentage. A failing package is self-describing: the summary prints the child's redacted output tail under the row (repo root and home become `<repo>`/`<home>`, credential-shaped env values are redacted through `createSecretRedactor` — names only, never values), and the same `tail` lands in the artifact, so a bare `(suite failed)` is never the whole story (`scripts/coverage-failure.mjs`, unit-tested by the gate).
336
344
 
337
345
  ### Release evidence and protected skips
338
346
 
@@ -350,6 +358,14 @@ Surfaces: core `npm test` (counts and the skip total come from the latest `phase
350
358
 
351
359
  Override `PRISM_RELEASE_EVIDENCE` to redirect the manifest (used by the gate regression). The manifest is gitignored and CI-retained (`release-evidence` artifact). A release cannot ship with a required env absent and unexplained — the operator sees every blocked surface in the retained manifest.
352
360
 
361
+ Protected legs fail closed through one convention (`scripts/blocked-gate.mjs`): a leg that cannot run prints exactly one canonical record and exits non-zero (test-style legs fail as a test failure), never a passing skip:
362
+
363
+ ```text
364
+ BLOCKED GATE <id> requires=<names> evidence=<surface> hint=<how to unblock>
365
+ ```
366
+
367
+ `node scripts/blocked-gate.mjs` audits the same registry — which protected legs cannot run with the current environment, which of them a release profile owns (their evidence surface decides the gate), and which are documented gaps that never block. `scripts/blocked-gate.test.mjs` (in-chain) asserts the registry, the record shape, and the fail-closed exits; `scripts/phase27-freeze-manifest.json` freezes the record template.
368
+
353
369
  ### Quality-gate reports and the Biome baseline
354
370
 
355
371
 
@@ -382,43 +398,46 @@ Major dependency upgrades are **isolated, compatibility-tested changes — never
382
398
 
383
399
  **Current third-party upgrade surface** (internal `@arnilo/prism-*` ranges are version-managed by the release tooling, not dependency upgrades; the core `@arnilo/prism` package has **zero** runtime dependencies, asserted by `core-boundaries.test.ts`):
384
400
 
401
+ Development type packages track the **declared** engines floor, not the machine that builds them: `@types/node` stays on the oldest supported Node line (`^22.20.0` while `engines.node` is `>=22`), so an API that the floor cannot provide fails the build instead of compiling clean against a newer type surface. Raising the floor is a support-matrix change (freeze manifest + CI legs + `docs/migration.md`), never a side effect of bumping the types package.
402
+
385
403
  | Dependency | Range | Resolved (lockfile) | Used by |
386
404
  | --- | --- | --- | --- |
387
405
  | `typescript` (dev) | `^7.0.2` | 7.0.2 | root build |
388
- | `@types/node` (dev) | `^26.1.1` | 26.1.1 | root build |
389
- | `@biomejs/biome` (dev) | `^2.5.5` | 2.5.5 | lint/format (Task 6) |
406
+ | `@types/node` (dev) | `^22.20.0` | 22.20.2 | root build (pinned to the `engines.node` floor) |
407
+ | `@biomejs/biome` (dev) | `^2.5.13` | 2.5.13 | lint/format |
390
408
  | `diff` | `^9.0.0` | 9.0.0 | `@arnilo/prism-coding-tools/agent` |
391
- | `pg` | `^8.22.0` | 8.22.0 | `@arnilo/prism-memory`, `@arnilo/prism-core/sessions/postgres` |
392
- | `better-sqlite3` | `^12.11.1` | 12.11.1 | `@arnilo/prism-core/sessions/sqlite` |
409
+ | `pg` | `^8.23.0` | 8.23.0 | `@arnilo/prism-memory`, `@arnilo/prism-core/sessions/postgres` |
410
+ | `better-sqlite3` | `^13.0.3` | 13.0.3 | `@arnilo/prism-core/sessions/sqlite` |
393
411
  | `ajv` | `^8.17.1` | 8.20.0 | `@arnilo/prism-core/validation/json-schema` |
394
- | `zod` | `^4.4.3` | 4.4.3 | `@arnilo/prism-mcp` |
412
+ | `zod` | `^4.6.2` | 4.6.2 | `@arnilo/prism-mcp` |
395
413
  | `@napi-rs/keyring` | `^1.3.0` | 1.3.0 | `@arnilo/prism-core/credentials/node` |
396
- | `@modelcontextprotocol/sdk` | `1.29.0` | 1.29.0 | `@arnilo/prism-mcp` |
414
+ | `@modelcontextprotocol/client` | `2.0.0` | 2.0.0 | `@arnilo/prism-mcp` |
415
+ | `@modelcontextprotocol/server` | `2.0.0` | 2.0.0 | `@arnilo/prism-mcp` |
397
416
  | `@ag-ui/core` | `0.0.59` | 0.0.59 | `@arnilo/prism-ag-ui` |
398
- | `@agentclientprotocol/sdk` | `1.3.0` | 1.3.0 | `@arnilo/prism-ag-ui` |
417
+ | `@agentclientprotocol/sdk` | `1.4.0` | 1.4.0 | `@arnilo/prism-ag-ui`, `@arnilo/prism-acp-agent` |
399
418
 
400
419
  **Recorded compatibility matrix (2026-07-26, release 0.0.16):**
401
420
 
402
421
  | Leg | Node | Result |
403
422
  | --- | --- | --- |
404
423
  | Full SDK readiness (`npm run sdk:ready`: typecheck, lint, format, test, coverage, pack, release:gate) | 24.18.0 (current) | ✅ green — 1312/1312 tests, lint 0 errors, format clean, coverage 64/72/79 vs 60/70/75 thresholds. |
405
- | Build toolchain (`tsc` 7.0.2, `biome` 2.5.5) | 20.20.2 (LTS iron) | ✅ both run under Node 20. |
424
+ | Build toolchain (`tsc` 7.0.2, `biome` 2.5.13) | 20.20.2 (LTS iron) | ✅ both run under Node 20. |
406
425
  | Public surface import smoke (all 21 root `exports` default targets) | 20.20.2 | ✅ all import cleanly. |
407
426
  | Full core test suite | 20.20.2 | 1311/1312 — the single failure is `examples_demos_run_to_completion_and_emit_no_secret`, which executes `examples/*.ts` via Node's native TypeScript stripping (Node 22.6+). This is a test-harness capability, not an SDK runtime incompatibility, and is exactly why CI scopes Node 20 to build + import smoke. |
408
427
 
409
- **CI enforcement** (`.github/workflows/release.yml`): the `verify` job runs `npm run sdk:ready` on Node 24; `node20-compat` runs `npm ci`, `npm run build`, and the public-import smoke on Node 20; `supply-chain` runs audit, SPDX/license checks, SBOM, and source-secret scans; `publish` `needs:` all of `verify`, `node20-compat`, `postgres-integration`, `codeql-release`, and `supply-chain`, so nothing publishes unless every leg — including the audit/SBOM gates — passes.
428
+ **CI enforcement** (`.github/workflows/release.yml`): the `verify` job runs `npm run sdk:ready` on Node 24; `node22-compat` runs `npm ci`, `npm run build`, and the public-import smoke on Node 22; `supply-chain` runs audit, SPDX/license checks, SBOM, and source-secret scans; `publish` `needs:` all of `verify`, `node22-compat`, `postgres-integration`, `codeql-release`, and `supply-chain`, so nothing publishes unless every leg — including the audit/SBOM gates — passes.
410
429
 
411
430
  **Process for a major-upgrade PR:** (1) bump exactly one dependency major in its own branch; (2) `npm run sdk:ready` green; (3) packed-install evidence (`npm run pack:dry-run`, or a scratch `npm install <tarball>` import smoke for native deps like `better-sqlite3`); (4) review lockfile churn line-by-line; (5) the `supply-chain` job supplies audit/SBOM; (6) confirm no build-time regression beyond measured noise on the matrix above; (7) merge separately from any feature work.
412
431
 
413
432
  ## Release checklist
414
433
 
415
434
 
416
- Every release gate maps to an exact enforcement test or command, so the checklist is executable rather than manual. Run `npm run sdk:ready` for the full local SDK readiness gate: `npm run typecheck`, `npm run lint`, `npm run format:check`, network-free `npm test`, `npm run test:coverage`, `npm run pack:dry-run`, and `npm run release:gate`. `npm run release:dry-run` is an alias for the same gate. The GitHub Actions `verify` job runs `npm ci` and `npm run sdk:ready` on Node 24; `node20-compat` runs `npm ci`, `npm run build`, and public export imports on Node 20; `postgres-integration` runs the opt-in PostgreSQL adapter suite against a CI Postgres service.
435
+ Every release gate maps to an exact enforcement test or command, so the checklist is executable rather than manual. Run `npm run sdk:ready` for the full local SDK readiness gate: `npm run typecheck`, `npm run lint`, `npm run format:check`, network-free `npm test`, `npm run test:coverage`, `npm run pack:dry-run`, and `npm run release:gate`. `npm run release:dry-run` is an alias for the same gate. The GitHub Actions `verify` job runs `npm ci` and `npm run sdk:ready` on Node 24; `node22-compat` runs `npm ci`, `npm run build`, and public export imports on Node 22; `postgres-integration` runs the opt-in PostgreSQL adapter suite against a CI Postgres service.
417
436
 
418
437
  | Gate | Enforcement |
419
438
  | --- | --- |
420
439
  | Docs coverage for persistence/runtime/migration surfaces | `docs.test.ts` enrolls every API page in `apiPages` (heading + index-link + bare-specifier + secret-scan checks); dedicated section assertions pin `database-persistence.md`, `runs-and-usage.md`, `session-stores-and-branching.md`, `migration.md`, `agent-definitions.md`, `performance.md`, and the Phase 41 `external_app_example_*` / `phase41_external_app_surfaces_*` gates. |
421
- | Package exports/subpaths resolve to built output | `public-export-contract.test.ts` asserts every `exports`/`main`/`types`/`bin` target resolves to a built file under `dist/` with a sibling `.d.ts` (`dist/index.js` + `dist/index.d.ts` for a root package), and no target escapes `dist/` (no `src/` or `examples/` leak). CI `node20-compat` also imports every public root `exports` default target on Node 20. |
440
+ | Package exports/subpaths resolve to built output | `public-export-contract.test.ts` asserts every `exports`/`main`/`types`/`bin` target resolves to a built file under `dist/` with a sibling `.d.ts` (`dist/index.js` + `dist/index.d.ts` for a root package), and no target escapes `dist/` (no `src/` or `examples/` leak). CI `node22-compat` also imports every public root `exports` default target on Node 22. |
422
441
  | Public-API drift | `public-export-contract.test.ts` `phase39_public_protocol_exports_and_types_do_not_drift` pins the runtime protocol (`providerToolCallDelta`, `ToolCallDeltaContent`), the `/testing/provider-conformance` subpath shape, and the observational-memory runtime `.d.ts` surface. |
423
442
  | 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`. |
424
443
  | 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. |
@@ -427,10 +446,13 @@ Every release gate maps to an exact enforcement test or command, so the checklis
427
446
  | NeuralWatt package/docs/examples release gate | `packaging.test.ts` pins `@arnilo/prism-providers/neuralwatt` package exports/type declarations and `@arnilo/prism-providers` family 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. |
428
447
  | Enterprise PostgreSQL package/docs/example gate | Packaging/install/public-contract tests include `@arnilo/prism-core/enterprise/postgres`; `docs.test.ts` pins its API page, four-store migration/ownership/unknown-outcome/async-router guidance, and `examples/enterprise-postgres-state.ts`; `npm run test:postgres` exercises migration, restart, contention, and cleanup with an explicit database URL. |
429
448
  | 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. |
449
+ | Release version claims have one source | `currentVersion()` (`scripts/package-truth.mjs`) reads the root manifest, and `scripts/version-literal-gate.test.mjs` fails when any surface that claims the release version disagrees with it: all 10 manifests, every internal `@arnilo/*` caret range, `package-lock.json`, the `src/index.ts` version constant, the `docs/index.md` current-line banner, the `release.yml` tag list, and the generated `scripts/package-truth.json`. Each stale surface is named in one pre-flight (with a positive control for a half-finished cut), and the release-line suites (`packaging.test.ts`, `docs.test.ts`, `release.test.ts`, `phase24-truth`, `phase34-freeze`) derive their expectations from the manifest instead of pinning the cut. |
430
450
  | Pre-publish compatibility gates | `release:gate` (in `sdk:ready`) fails on removed/changed `.d.ts` exports vs `scripts/compat-baseline/` (unless `--allow-break` + migration note), version-range/lockfile drift, and tarball deny-list violations (`plans/`, `code-reviews/`, `docs/review-coverage-*`, `*.map`, `__tests__/`); unit-tested in `scripts/release-gate.test.mjs`. |
431
451
  | Legacy registry markers (plan 054 Task 7) | `scripts/phase54-legacy-registry.mjs --dry-run` verifies every retired name's final published version exists and `latest` is unchanged, and that each deprecation URL anchor exists in `docs/migrate-to-0.4.md`, without mutating the registry; `--apply --confirm` pre-flights all 54 entries and fails closed (zero mutations) on any mismatch, then idempotently adds the `legacy` dist-tag and `<0.4.0` deprecation warning (already-correct entries skipped; per-entry status in `release-artifacts/legacy-registry-plan.json` for safe resume). `packaging.test.ts` asserts the generated plan covers all 54 retired names with uniform messages and valid guide anchors; the offline fixture suite `scripts/phase54-legacy-registry.test.mjs` proves the dry-run/apply/resume behavior without network or tokens. |
432
452
  | Formatting, linting, and coverage thresholds | `npm run lint` and `npm run format:check` run Biome (single root `biome.json`, workspaces inherit) and fail on any lint error or unformatted file; `npm run test:coverage` uses Node's built-in `--experimental-test-coverage` with enforced minimums (lines 60 / functions 70 / branches 75) and no third-party service. All three run inside `sdk:ready`. |
433
453
  | 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. |
454
+ | Release secret scan covers the tracked release set | `scripts/phase27-release.test.mjs` enumerates `git ls-files` (plus built `packages/prism-core/dist` when present) and passes that explicit list to the unchanged `scanSecrets` — the same tracked set CI scans (`git ls-files -z \| xargs -0 node scripts/scan-secrets.mjs` in `release.yml`/`security.yml`), so no untracked or gitignored working-tree file can fail the gate or mask a tracked finding; a bare `node scripts/scan-secrets.mjs <path>` still walks everything for pre-commit use, and the gate reports the mode, file count, and untracked-but-unignored findings as a note without failing on them. |
455
+ | Workflow and script references resolve | `scripts/workflow-liveness.test.mjs` resolves every `-w <pkg>` / `--workspace <pkg>` target in `.github/workflows/*.yml` against the live workspace inventory and every named npm script against that package's manifest (root scripts included for a bare `npm run x`), resolves every `@arnilo/*` specifier in `scripts/**/*.mjs` against the live package and its `exports` subpaths, and rejects any `uses:` reference that is not a full 40-hex commit SHA — the drift class that left `sandbox-browser.yml` building four retired packages, `scripts/fixtures/phase26-coding-journey.mjs` packing `packages/coding-agent`/`-security` and `scripts/benchmark-scenarios/phase11-auth.mjs` importing `@arnilo/prism-openapi-tools`/`-server` after plan 054 folded them, with a positive control for each. |
434
456
  | Network-free + offline test budget | `network-free-guard.test.ts` keeps the default suite network-free; budget pinned `< 60s` (measured baseline above). Install-smoke is offline (`--offline --no-audit --no-fund`, zero registry fetches). |
435
457
  | Core security invariants reaffirmed | Runtime/docs tests hold the trust boundary: **no built-in app tools** (hosts register tools; the core ships only the mock provider and contract helpers), **no hidden provider/credential globals** (providers/credentials are host-owned `AgentConfig` fields, resolved via explicit `providerSource`/`CredentialResolver`), **no auto package discovery** (provider/tool/skill packages are opt-in and individually installed; contribution discovery is realpath-contained and emits inert envelopes the host registers), and **no secret persistence in core** (redaction applies before any `RunLedger`/`SessionStore` append; the ledger gate asserts each message event is written exactly once and redacted). |
436
458
 
@@ -19,7 +19,7 @@ APIs:
19
19
 
20
20
  Configure `AgentConfig.runLedger` when you want every run of an agent to be persisted. Override it per run with `RunOptions.runLedger` if a single run needs a different adapter or no adapter at all. Use `runLedger` whenever you need durable observability, billing, audit replay, or run-scoped analytics.
21
21
 
22
- Do not use `RunLedger` as a replacement for `SessionStore` — messages, branches, and session entries continue to go through `SessionStore.append()`. Do not use it for live streaming; subscribers still receive `AgentEvent` through `session.subscribe()`.
22
+ Do not use `RunLedger` as a replacement for `SessionStore` — messages, branches, and session entries continue to go through `SessionStore.append()`. Do not use it for live streaming; subscribers still receive `AgentEvent` through `session.subscribe()`. Realtime voice tokens settle through `ModelRouter.recordUsage` with `kind: "generation"` (see [Realtime voice](realtime-voice.md)); missing usage stays unknown, never zero.
23
23
 
24
24
  ## Inputs / request
25
25
 
@@ -298,7 +298,8 @@ console.log(cacheUsageReport(aggregate?.usage));
298
298
  - Adapters that need upsert semantics can use `RunRecord.id` (== `runId`) as the stable key.
299
299
  - Use `cacheUsageReport(record.usage, model)` for cache diagnostics from normalized usage. It works when a provider reports `cacheReadTokens` without `cacheWriteTokens`; missing write tokens are reported as `0`, and unavailable hit rate/savings stay `undefined`.
300
300
  - **Provider-specific telemetry is package-owned.** Core `Usage` carries token counts and `cost`/`currency`; it has no energy or detailed cost-breakdown fields. Providers that surface extra telemetry (e.g. `@arnilo/prism-providers/neuralwatt` exposes `neuralWattEventsWithTelemetry()`, `parseNeuralWattComment()`, and `mapNeuralWattTelemetry()` for `: energy`/`: cost` SSE comments and non-streaming top-level fields) keep that data in package-specific helpers/types. Telemetry never enters `RunLedger` usage rows unless the host explicitly copies it in; it carries usage/cost numbers only — never prompts, API keys, or headers. Account-level quota is likewise package-owned: `@arnilo/prism-providers/neuralwatt` exports an explicit `getNeuralWattQuota()` helper that the host calls on demand (never during generation); NeuralWatt rate-limits that endpoint to 1 request per second per customer, so the caller owns throttling.
301
- - **Live timing metadata.** `provider_turn_*` events and `ToolExecutionMetadata` on terminal `tool_execution_*` events expose latency, retry `attempt`, and tool `durationMs` for subscribers and ledger replay — see [Observability](observability.md).
301
+ - **Governed provider lifecycle and reservation reconciliation.** For invocation-level accounting outside of or in addition to `RunLedger`, wrap providers with `createGovernedProvider` or `router.createGovernedProvider` from `@arnilo/prism-core/governance/model-router`. The adapter handles atomic admission reservations, bounds streaming, and guarantees explicit settlement: missing actual usage on an interrupted or EOF stream is committed as reserved liability (`unknownUsage: true`) rather than zero, avoiding budget leakages or unmetered oversubscriptions. See [Model routing](model-routing.md).
302
+ - **Aggregate task/tenant accounting across all paid work.** Complex agent tasks often span retries, model fallbacks, delegated children, background compactions, embedding jobs, and paid tools. Passing `taskId` and `kind` (`"generation" | "embedding" | "compaction" | "tool"`) coordinates all related calls under a single atomic task-level reservation and budget scope. Committed usage decomposes into separate `byModel` and `byKind` attributions (`router.readBudget({ identity, taskId })`) while preventing double-charging across parent/child boundaries or replayed events. Long-running holds can be safely renewed via `router.renewBudget({ ... })` before expiry without prematurely releasing live liability. See [Model routing](model-routing.md) and [Enterprise PostgreSQL state](enterprise-postgres-state.md).
302
303
 
303
304
  ## Security and performance notes
304
305
 
package/docs/server.md CHANGED
@@ -8,7 +8,7 @@ No listener starts on import. Empty `agents`/`workflows` maps expose nothing. Au
8
8
 
9
9
  ## When to use it
10
10
 
11
- Use it when a Node 20, serverless, worker, or framework host already speaks Web `Request`/`Response` and needs a small Prism API boundary. Wrap it in the platform's native adapter rather than adding Express, Fastify, Hono, Koa, Nest, or Next to Prism.
11
+ Use it when a Node 22, serverless, worker, or framework host already speaks Web `Request`/`Response` and needs a small Prism API boundary. Wrap it in the platform's native adapter rather than adding Express, Fastify, Hono, Koa, Nest, or Next to Prism.
12
12
 
13
13
  Use `AgentSession` or workflow APIs directly for in-process applications. Do not treat this package as an auth provider, user database, firewall, durable agent-result store, or public listener.
14
14
 
@@ -45,7 +45,7 @@ At least one non-empty ownership field must come from `authorize()`. Request JSO
45
45
  | `POST /prism/agents/:id/runs` | `agent.run` | `{ "input": string | Message | Message[] }` |
46
46
  | `POST /prism/agents/:id/stream` | `agent.stream` | same; SSE response |
47
47
  | `GET /prism/agents/:id/runs/:runId` | `agent.status` | none; redacted public state/version only |
48
- | `POST /prism/agents/:id/runs/:runId/resume` | `agent.resume` | `{ "decision": "approve" | "deny", "expectedVersion": number }` |
48
+ | `POST /prism/agents/:id/runs/:runId/resume` | `agent.resume` | `{ "decision": "approve" | "deny", "expectedVersion": number, "modifiedArguments"?, "approvalId"?, "reason"? }` or `{ "decisions": [...], "expectedVersion": number }` |
49
49
  | `GET /prism/agents/:id/runs/:runId/events?cursor=` | `agent.events` | none; durable SSE, also accepts `Last-Event-ID` |
50
50
  | `POST /prism/workflows/:id/runs` | `workflow.run` | `{ "input": unknown, "runId"?: string }` |
51
51
  | `POST /prism/workflows/:id/stream` | `workflow.stream` | same; SSE response |
@@ -109,7 +109,7 @@ const handler = createPrismHandler({
109
109
  - Workflow exposure requires its existing `WorkflowCheckpointAdapter`; no server-owned database exists.
110
110
  - Schedule exposure is optional and may be one service or an authorization-selected resolver. Returned service ownership must exactly match authorized tenant/account/user scope; otherwise request is forbidden.
111
111
  - `PrismWorkflowExposure.runOptions` can supply agent/tool/policy/resume-validator wiring. Server-owned ownership, signal, checkpoint, redactor, run ID, and event bus fields cannot be overridden.
112
- - The agent resume endpoint (`/prism/agents/{id}/runs/{runId}/resume`) accepts `{ decision: "approve" | "deny" }` or `{ decisions: [{ approvalId, outcome, reason?, modifiedArguments?, elicitation? }] }` next to `expectedVersion` — exactly one of `decision`/`decisions`. Entries are validated at the boundary (count ≤ 128, four outcomes, bounded reason/payloads) and core applies them atomically under the run's CAS; unknown ids, stale versions, and malformed batches fail closed without touching the run.
112
+ - The agent resume endpoint (`/prism/agents/{id}/runs/{runId}/resume`) accepts `{ decision: "approve" | "deny", modifiedArguments?, approvalId?, reason? }` or `{ decisions: [{ approvalId, outcome, reason?, modifiedArguments?, elicitation? }] }` next to `expectedVersion` — exactly one of `decision`/`decisions`. When `modifiedArguments` is passed with `decision: "approve"`, omitting `approvalId` correlates the run's single pending decision (multiple pending decisions without `approvalId` fail closed). Entries are validated at the boundary (count ≤ 128, four outcomes, bounded reason/payloads, schema validation) and core applies them atomically under the run's CAS; unknown ids, stale versions, deny with edits, and malformed batches fail closed without touching the run.
113
113
  - Host/origin checks and CORS headers activate only when their allow-lists are configured. Hosts still own reverse-proxy trust and canonical host handling.
114
114
 
115
115
  Default/hard ceilings:
@@ -224,7 +224,8 @@ Compose beside `createPrismHandler` — Prism starts no listener, container orch
224
224
  | Helper | Role |
225
225
  | --- | --- |
226
226
  | `createPrismHealthHandler` | `GET /health`, `/livez`, `/readyz`. Minimal JSON; `?detail=1` requires `authorizeDetail`. No secrets/tenant payloads by default. Ready fails while draining. |
227
- | `createPrismDrainController` | `beginDrain()` rejects admit ops (`agent.run`/`stream`/`resume`, workflow run/stream/enqueue/resume/replay, schedule create/trigger) with `503 ERR_PRISM_SERVER_DRAINING`. Status/cancel/list stay open. |
227
+ | `createPrismDrainController` | `beginDrain()` rejects admit ops (`agent.run`/`stream`/`resume`, workflow run/stream/enqueue/resume/replay, schedule create/trigger) with `503 ERR_PRISM_SERVER_DRAINING`. Status/cancel/list stay open. Snapshot includes finite `deadlineAt` / `expired`. |
228
+ | `createPrismOperatorHandler` | Authenticated `/ops/queue`, `/suspended`, `/failed`, `/unknown`, `POST /ops/cancel`, `POST /ops/reconcile`. Ownership-scoped. Reconcile accepts only `completed` / `failed_terminal` plus evidence — never retries unknown effects or unlocks leases. |
228
229
  | `rateLimit` on handler | Host adapter after authorize, before session create. Return denial `{ retryAfterMs, code, message }` → `429` + optional `Retry-After`. `createMemoryRateLimiter` is single-process only. |
229
230
  | `createPrismAgentEventReplay` | Shared `AgentEventSource` page/follow semantics for exact-owned runs. |
230
231
  | `createPrismEventReplay` / `createPrismReplayHandler` | Compatible ownership-scoped legacy `queryEvents` pages (`redacted: true`). Does not re-run work. Unauthorized replay denies. |
@@ -259,6 +260,7 @@ A2A routes are not added to `createPrismHandler()`. Install `@arnilo/prism-core/
259
260
  - [Performance](performance.md): capacity notes for concurrent runs and deployment probes.
260
261
  - [Agent/session runtime](agent-session-runtime.md): direct result and event stream semantics.
261
262
  - [Workflows](workflows.md): durable checkpoints, status, cancellation, exact-once resume, and `createWorkflowCoordinator` workers.
263
+ - [Operations runbook](operations.md): fair admission, drain deadline, operator queue/cancel/reconcile.
262
264
  - [MCP client and server exposure](mcp-tools.md): selected MCP capabilities and web-standard MCP transport.
263
265
  - [Host security guide](host-security.md): remote-boundary checklist.
264
266
  - [A2A interoperability](a2a.md): separately mounted A2A 1.0 handler/client.
@@ -31,7 +31,7 @@ Public helpers:
31
31
  | Helper | Purpose |
32
32
  | --- | --- |
33
33
  | `createSessionEntry(options)` | Build a `SessionEntry` with generated `id`/`timestamp` when omitted. |
34
- | `createMemorySessionStore(initialEntries?, options?)` | Built-in in-memory `SessionStore`. `options.sessionSearchMode`: `"linear"` (default) or `"unsupported"` (throws `SessionSearchUnsupportedError`). |
34
+ | `createMemorySessionStore(initialEntries?, options?: CreateMemorySessionStoreOptions)` | Built-in in-memory `SessionStore`. `options.sessionSearchMode`: `"linear"` (default) or `"unsupported"` (throws `SessionSearchUnsupportedError`); `options.search` may override the linear scan caps (`maxLinearSessions` / `maxLinearEntries` / `maxLinearBytes`), each bounded by its `HARD_MAX_SESSION_SEARCH_LINEAR_*` value and validated at construction (`TypeError` below 1 or above the hard cap). |
35
35
  | `resolveSessionSearchQuery(query)` | Validate/clamp search limits (page, query bytes, snippet, cursor, linear/FTS caps). |
36
36
  | `SessionIndex` | Narrow search seam (`search(query)`); adapters may expose this instead of `SessionStore.searchSessions`. |
37
37
  | `getSessionBranchEntries(entries, options)` | Return root-to-leaf entries for a leaf id (sync array path). |
@@ -124,6 +124,8 @@ const page = await store.searchSessions!({
124
124
  limit: 20,
125
125
  });
126
126
  // Opt out: createMemorySessionStore([], { sessionSearchMode: "unsupported" })
127
+ // Raise the in-process scan caps for a small but large-query session set (defaults are the contract caps):
128
+ const wide = createMemorySessionStore([], { search: { maxLinearSessions: 5_000, maxLinearEntries: 50_000 } });
127
129
  ```
128
130
 
129
131
  Finite caps (defaults / hard): page 20/100; query string 4 KiB/16 KiB; snippet 512 B/4 KiB; cursor 1 KiB/4 KiB; memory linear sessions 1000/5000, entries 10000/50000, bytes 8 MiB/64 MiB; DB FTS candidates 1000/5000. Overflow fails closed via `resolveSessionSearchQuery`. See [Phase 6 evidence](_evidence/review-coverage-2026-07-22-phase-6.md).
package/docs/speech.md CHANGED
@@ -120,6 +120,8 @@ await runSpeechConformance({
120
120
  - [Realtime sessions](public-contracts.md): `RealtimeSession` for interactive
121
121
  bidirectional voice; `RealtimeEvent.transcript_delta` is this contract's
122
122
  naming anchor.
123
+ - [Realtime voice](realtime-voice.md): governed bridge from a Realtime session
124
+ into host tool dispatch, barge-in, and transcript privacy.
123
125
  - [Provider conformance](provider-conformance.md): `runSpeechConformance` /
124
126
  `runTranscriptionConformance` and the offline conformance matrix.
125
127
  - [Provider packages](provider-packages.md): subpath import rules for
@@ -1,5 +1,7 @@
1
1
  # SQLite persistence
2
2
 
3
+ > **Optional peer install:** `better-sqlite3` — see [Optional peer dependencies](peer-dependencies.md).
4
+
3
5
  ## What it does
4
6
 
5
7
  The optional `@arnilo/prism-core/sessions/sqlite` package ships a production-oriented SQLite adapter that implements: