@arnilo/prism 0.11.0 → 0.12.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 (89) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +28 -27
  3. package/dist/cli-dev.js +1 -1
  4. package/dist/cli-init.js +4 -4
  5. package/dist/cli-provider-add.js +2 -2
  6. package/dist/field-evidence.d.ts +53 -0
  7. package/dist/field-evidence.js +143 -0
  8. package/dist/index.d.ts +3 -1
  9. package/dist/index.js +2 -1
  10. package/dist/run-bundle.js +2 -2
  11. package/docs/acp-agent.md +2 -2
  12. package/docs/ag-ui.md +1 -1
  13. package/docs/attention-compiler.md +1 -1
  14. package/docs/cli-rpc.md +2 -2
  15. package/docs/coding-tools.md +3 -3
  16. package/docs/compaction-observational-memory.md +13 -3
  17. package/docs/computer-use-linux.md +2 -2
  18. package/docs/core.md +9 -10
  19. package/docs/dev-inspector.md +1 -1
  20. package/docs/disaster-recovery.md +1 -1
  21. package/docs/document-extraction.md +140 -0
  22. package/docs/evaluations.md +1 -1
  23. package/docs/execution-timeline.md +30 -0
  24. package/docs/guardrails.md +53 -0
  25. package/docs/history/130-cyclic-workflows-primitive-review.md +293 -0
  26. package/docs/history/132-document-ingestion-primitive-review.md +124 -0
  27. package/docs/history/README.md +2 -0
  28. package/docs/history/migrate-to-0.12.0.md +57 -0
  29. package/docs/history/retire-node-runtime.md +59 -0
  30. package/docs/hooks.md +1 -1
  31. package/docs/host-compositions.md +2 -2
  32. package/docs/host-security.md +1 -1
  33. package/docs/index.md +30 -25
  34. package/docs/live-testing.md +1 -1
  35. package/docs/mcp-tools.md +2 -2
  36. package/docs/messaging-channels.md +1 -1
  37. package/docs/migrate-to-0.7.md +1 -1
  38. package/docs/migrate-to-0.8.md +2 -2
  39. package/docs/migrate-to-0.9.md +1 -1
  40. package/docs/migration.md +2 -2
  41. package/docs/model-registry.md +1 -1
  42. package/docs/model-routing.md +21 -0
  43. package/docs/multi-agent-patterns.md +77 -4
  44. package/docs/obscura.md +1 -1
  45. package/docs/openapi-tools.md +1 -1
  46. package/docs/operations.md +2 -2
  47. package/docs/peer-dependencies.md +18 -17
  48. package/docs/performance.md +32 -32
  49. package/docs/prompt-registry.md +1 -1
  50. package/docs/provider-packages.md +23 -21
  51. package/docs/providers/decisions.md +134 -0
  52. package/docs/providers/laya.md +116 -0
  53. package/docs/providers/typesafe.md +148 -0
  54. package/docs/rag.md +17 -5
  55. package/docs/release-and-install.md +119 -113
  56. package/docs/run-bundle.md +4 -0
  57. package/docs/runs-and-usage.md +1 -1
  58. package/docs/signal-channel.md +1 -1
  59. package/docs/sqlite-persistence.md +5 -5
  60. package/docs/synapta-integration-review.md +238 -0
  61. package/docs/telegram-channel.md +1 -1
  62. package/docs/testing.md +33 -14
  63. package/docs/wiki.md +12 -11
  64. package/docs/work-sandbox.md +2 -0
  65. package/docs/work-tools.md +3 -3
  66. package/docs/workflows.md +213 -11
  67. package/package.json +22 -21
  68. package/templates/business-worker/README.md.tmpl +3 -3
  69. package/templates/business-worker/package.json.tmpl +4 -5
  70. package/templates/business-worker/src/tests/agent.test.ts.tmpl +1 -1
  71. package/templates/business-worker/tsconfig.json.tmpl +2 -1
  72. package/templates/deep-research/README.md.tmpl +4 -4
  73. package/templates/deep-research/package.json.tmpl +4 -5
  74. package/templates/deep-research/src/tests/research.test.ts.tmpl +1 -1
  75. package/templates/deep-research/tsconfig.json.tmpl +2 -1
  76. package/templates/init/README.md.tmpl +3 -3
  77. package/templates/init/optional/evals-example.ts.tmpl +1 -1
  78. package/templates/init/optional/workflows-example.ts.tmpl +1 -1
  79. package/templates/init/package.json.tmpl +4 -5
  80. package/templates/init/src/tests/agent.test.ts.tmpl +1 -1
  81. package/templates/init/tsconfig.json.tmpl +2 -1
  82. package/templates/personal-assistant/README.md.tmpl +3 -3
  83. package/templates/personal-assistant/package.json.tmpl +4 -5
  84. package/templates/personal-assistant/src/tests/agent.test.ts.tmpl +1 -1
  85. package/templates/personal-assistant/tsconfig.json.tmpl +2 -1
  86. package/templates/provider/README.md.tmpl +2 -2
  87. package/templates/provider/package.json.tmpl +3 -4
  88. package/templates/provider/src/tests/provider.test.ts.tmpl +1 -1
  89. package/templates/provider/tsconfig.json.tmpl +1 -1
package/docs/index.md CHANGED
@@ -1,15 +1,16 @@
1
1
  # Prism Docs
2
2
 
3
- Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credentials, storage, and behavior; Prism supplies contracts, registries, events, and replaceable runtime primitives.
3
+ Prism is a TypeScript agent harness for the Bun runtime. Hosts own providers, tools, credentials, storage, and behavior; Prism supplies contracts, registries, events, and replaceable runtime primitives.
4
4
 
5
- ## Current line (0.11.0)
5
+ ## Current line (0.12.0)
6
6
 
7
7
  - **Memory-store branch reads**: the built-in memory session store implements `readBranchPath`. A snapshot walks the branch once and clones each kept entry once.
8
8
  - **JSONL parse cache**: a read after an in-process append reuses the parsed file when size and mtime match. A same-size write inside one filesystem timestamp tick can still look unchanged.
9
9
  - **Idempotency window**: memory and JSONL stores remember the latest 4,096 dedup keys. Replaying an older key appends a new entry instead of rejecting the write.
10
10
  - **In-memory lease sweep**: expired lease rows are deleted once the map reaches 1,024. A swept key starts its next fence at 1. A released key still in the map keeps `fencingToken + 1`. SQLite and Postgres adapters still keep the counter on the row.
11
11
  - **Shared text token estimate**: plain-text estimates use one `ceil(length/4)` helper. Message and entry estimates are unchanged.
12
- - **12 publishable packages** at current **0.11.0** lockstep, with the migration guide reachable from the release section below — inventory below.
12
+ - **System One decision models**: `@arnilo/prism-providers/typesafe` (hosted Jev) and `@arnilo/prism-providers/laya` (self-hosted `laya-serve`) answer only `options.structuredOutput` requests, one `POST /v1/systemone` round trip, no tools or streaming; `@arnilo/prism-providers/decisions` adds a typed host call that preserves raw probabilities, confidence, the responding checkpoint, usage, and timing.
13
+ - **12 publishable packages** at current **0.12.0** lockstep, with the migration guide reachable from the release section below — inventory below.
13
14
 
14
15
  ### Carried from the 0.10.0 line
15
16
 
@@ -47,7 +48,7 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
47
48
 
48
49
  ### Carried from the 0.6.0 line
49
50
 
50
- - **Node 22 floor**: `engines.node` is `>=22` in all eleven publishable packages, the `node20-compat` CI leg becomes `node22-compat`, and `@types/node` moves to `^22.20.0` (plan 071; Node 20 is upstream EOL since 2026-04-30).
51
+ - **Node 22 floor (retired in 0.12.0)**: the 0.6.0 line set `engines.node` to `>=22` in all eleven then-publishable packages, turned the `node20-compat` CI leg into `node22-compat`, and moved `@types/node` to `^22.20.0` (plan 071; Node 20 is upstream EOL since 2026-04-30). The 0.12.0 line declares `engines.bun >=1.4.2` instead — see the [Node retirement record](history/retire-node-runtime.md).
51
52
  - **Folded 0.5.7 content**: the 0.5.7 cut was never published — its durable-tool-round and strict-tool-result fixes, host knobs, peer/options truth, and dependency floors ship in 0.6.0 (migration guide below).
52
53
  - **Release-truth gates**: one forward-claim version-literal gate (manifests, internal ranges, lockfile, version constant, index banner, workflow tags), a workflow-liveness gate (every script target and action reference resolves, actions SHA-pinned), and a load-tolerant startup budget ratio (plan 071).
53
54
  - **Self-describing coverage failures**: a failing coverage child prints its redacted output tail and records `status`/`exitCode`/`tail` on its artifact row (plan 071).
@@ -83,7 +84,7 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
83
84
  - [Agent definitions](agent-definitions.md): declarative `AgentDefinition` resolution and `AGENT.md` bundle discovery, fail-closed activation.
84
85
  - [Agent loops](agent-loops.md): replaceable loops with `limits.maxToolRounds` budgets and durable revision/restore hooks.
85
86
  - [Hooks](hooks.md): the hook model — stop hooks with bounded continuation, session/compaction boundary seams, and the Claude Code / Codex event map plus the `hooks.json` adapter.
86
- - [Guardrails](guardrails.md): typed fail-closed input/output/tool checks with redacted decision records.
87
+ - [Guardrails](guardrails.md): typed fail-closed input/output/tool checks with redacted decision records, plus an opt-in tool-input field-evidence verifier for proposal-shaped calls.
87
88
  - [Agent events](agent-events.md): `turn_started`/`tool_call_delta` stream plus durable page/resume sources for reconnect.
88
89
  - [Observability](observability.md): OTel GenAI span hierarchy, workflow spans, cockpit aggregations, RAG span tree, bounded trace linkage, exporter isolation.
89
90
  - [Execution timeline](execution-timeline.md): execution timeline projection and cockpit summaries for host dashboards and trajectory evals.
@@ -99,7 +100,7 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
99
100
 
100
101
  - [Compaction and retry policies](compaction-and-retry.md): host-replaceable summarize/retry policies with deprecated-option removals fail closed.
101
102
  - [LLM compaction subpath](compaction-llm.md): provider-backed summarization with finite `model.parameters.maxTokens` and coding handoff strategy.
102
- - [Observational memory compaction subpath](compaction-observational-memory.md): source-backed observations/reflections, an optional work-scope index for the current working set, and exact-id recall; `invalidatedIds` withhold derived injection.
103
+ - [Observational memory compaction subpath](compaction-observational-memory.md): source-backed observations/reflections, coverage-safe admission that retains or defers on unobserved prefixes, an optional work-scope index for the current working set, and exact-id recall; `invalidatedIds` withhold derived injection.
103
104
  - [Working and semantic memory](working-and-semantic-memory.md): working-memory store, semantic recall, pgvector path, consent lifecycle, lineage invalidation, parent-child share grants.
104
105
  - [Memory fabric](memory-fabric.md): opt-in typed notes (fact/procedure/file/working/episode) with validity windows over the existing vector and working stores.
105
106
  - [Scoped memory](scoped-memory.md): workspace-scope guard, gated writes, promotion ladder, decay reads, audit mirror (`@arnilo/prism-memory/scoped`).
@@ -109,7 +110,7 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
109
110
  - [Work artifacts and review](work-artifacts-and-review.md): artifact attach, revision compare, evidence-bound citations, approve/reject, expiring delivery links.
110
111
  - [Session stores and branching](session-stores-and-branching.md): branch-semantics helper reference (compatibility stub for session-stores.md).
111
112
  - [Database persistence](database-persistence.md): production persistence contracts, migrations, retention, and adapter conformance harnesses.
112
- - [SQLite persistence](sqlite-persistence.md): optional `better-sqlite3` adapter with FTS search and verified migrations.
113
+ - [SQLite persistence](sqlite-persistence.md): built-in `bun:sqlite` adapter with FTS search and verified migrations.
113
114
  - [PostgreSQL persistence](postgres-persistence.md): optional pooled `pg` adapter with advisory-locked migrations and live conformance.
114
115
  - [Enterprise PostgreSQL state](enterprise-postgres-state.md): durable governance/router/ERP state, outbox/inbox messaging, approval records.
115
116
  - [Migration guide](migration.md): the era index of migration cuts with replacement tables and rollback notes.
@@ -131,7 +132,8 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
131
132
  - [Use-case model selection](use-case-model-selection.md): bind models for compaction, memory, and other non-session LLM jobs.
132
133
  - [Provider request policies](provider-request-policies.md): kernel request-option defaults with host `ProviderRequestPolicy` overlays.
133
134
  - [Provider packages](provider-packages.md): all adapters as `@arnilo/prism-providers/<adapter>` subpaths; tool_result and event wire shapes stay provider-neutral.
134
- - First-party adapters: [`openai`](providers/openai.md), [`anthropic`](providers/anthropic.md), [`google`](providers/google.md), [`opencode-go`](providers/opencode-go.md), [`openrouter`](providers/openrouter.md), [`zai`](providers/zai.md), [`deepseek`](providers/deepseek.md), [`xai`](providers/xai.md), [`clinepass`](providers/clinepass.md), [`hyper`](providers/hyper.md), [`commandcode`](providers/commandcode.md), [`kimi`](providers/kimi.md), [`alibaba`](providers/alibaba.md), [`ollama`](providers/ollama.md), [`neuralwatt`](providers/neuralwatt.md), plus the cross-vendor `model-discovery` listing adapters on the same page.
135
+ - First-party adapters: [`openai`](providers/openai.md), [`anthropic`](providers/anthropic.md), [`google`](providers/google.md), [`opencode-go`](providers/opencode-go.md), [`openrouter`](providers/openrouter.md), [`zai`](providers/zai.md), [`deepseek`](providers/deepseek.md), [`xai`](providers/xai.md), [`clinepass`](providers/clinepass.md), [`hyper`](providers/hyper.md), [`commandcode`](providers/commandcode.md), [`kimi`](providers/kimi.md), [`alibaba`](providers/alibaba.md), [`ollama`](providers/ollama.md), [`neuralwatt`](providers/neuralwatt.md), [`typesafe`](providers/typesafe.md), [`laya`](providers/laya.md), plus the cross-vendor `model-discovery` listing adapters on the same page.
136
+ - [System One decisions](providers/decisions.md): typed host decision call over the shared `POST /v1/systemone` client, preserving raw probabilities/confidence/legend, the responding checkpoint, usage, and timing with pre-fetch bounds and deadline/abort composition.
135
137
  - Enterprise cloud (workload identity): [`azure`](providers/azure.md) (Entra/Foundry), [`bedrock`](providers/bedrock.md) (IAM/SigV4; OpenAI-compatible or native Converse route), [`vertex`](providers/vertex.md) (ADC/Vertex).
136
138
  - Optional AI SDK adapter: [`ai-sdk`](providers/ai-sdk.md) maps host-owned pinned `LanguageModelV4` models onto Prism streams.
137
139
  - [OpenAI-compatible provider](providers/openai-compatible.md): base Chat Completions subpath with strict-completion default and vendor hooks.
@@ -146,8 +148,8 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
146
148
  - [Versioned prompt registry](prompt-registry.md): immutable content-hashed prompt assets with durable stores and bounded diff.
147
149
  - [Instruction injection](instruction-injection.md): package injectors layer redacted instructions without granting capabilities.
148
150
  - [Context and skills](context-and-skills.md): ordered context providers, progressive skill disclosure, fail-closed activation. `@arnilo/prism-work` ships `docx`, `xlsx`, `powerpoint`, `pdf`.
149
- - [LLM Wiki](wiki.md): optional knowledge compiler emitting OKF bundles, with `/wiki-ingest` raw staging (text, file, image, or URL via a host `fetchUrl` hook) and on-device hybrid search.
150
- - [Retrieval-augmented generation](rag.md): bounded source lifecycle, hybrid retrieval, permission-trimmed query legs, reranking, evidence-backed citations, inert injection.
151
+ - [LLM Wiki](wiki.md): optional knowledge compiler emitting OKF bundles, with `/wiki-ingest` raw staging (text, file, image, or URL via a host `fetchUrl` hook). A set `extractDocument` hook owns PDF and CSV; image OCR is opt-in.
152
+ - [Retrieval-augmented generation](rag.md): bounded source lifecycle, hybrid retrieval, permission-trimmed query legs, reranking, evidence-backed citations, inert injection. Host parsers may convert documents; failed OCR is not indexed.
151
153
  - [Knowledge synchronization](knowledge-sync.md): paged enterprise-source import with a Drive connector, checkpointed change cursors, and host-owned ACL mapping.
152
154
 
153
155
  ## Tools
@@ -181,6 +183,7 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
181
183
  ## Documents, sheets, and diagrams
182
184
 
183
185
  - [Documents, spreadsheets, and presentations](documents.md): OOXML generation, parsing, import fidelity reports, patching, structural diffs, and bounded preview for Office formats.
186
+ - [Document extraction](document-extraction.md): optional local Markdown conversion for Office, OpenDocument, CSV, and text PDFs. Scanned PDFs fail closed unless the host runs the packaged Docling worker; never hosted OCR.
184
187
  - [Spreadsheets and CSV data](sheets.md): fail-closed XLSX/CSV ingestion with decimal-safety guarantees.
185
188
  - [Diagrams and mxGraph embed](diagrams.md): origin-enforced draw.io embed client with XXE-safe XML validation.
186
189
 
@@ -250,10 +253,12 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
250
253
  - [Telegram channel](telegram-channel.md): official `@arnilo/prism-channels/telegram` long polling and mountable webhook ingress with durable offset/lease handling, approval callbacks, opt-in granted group/topic text, bounded media with optional voice transcription/synthesis, and opt-in streaming drafts.
251
254
  - [Signal channel (experimental)](signal-channel.md): `@arnilo/prism-channels/signal` pinned signal-cli v0.14.8 private-socket manual receive, explicit policy gate, UUID DM filtering and bounded ambiguous delivery.
252
255
  - [Messaging channel operations](messaging-channel-operations.md): durable journal, restart and reconciliation contract, lease fencing, retention and the operator runbook.
256
+ - [Synapta → Prism integration review](synapta-integration-review.md): host-integration findings, the F1–F4 fixes, the remediation tasks that shipped them, and the authorities that stay with the host.
253
257
 
254
258
  ## Release and install
255
259
 
256
- - [Release and install](release-and-install.md): install rules, package graph, and deterministic resumable publication.
260
+ - [Release and install](release-and-install.md): Bun install rules and the runtime matrix, the package graph, and deterministic resumable publication.
261
+ - [Migrate 0.11 → 0.12](history/migrate-to-0.12.0.md): Bun `>=1.4.2`, `bun:sqlite`, and optional local document extraction.
257
262
  - [Migrate 0.10 → 0.11](migrate-to-0.11.md): idempotency window, in-memory lease fence reset, and the persona/graft subpath removals.
258
263
  - [Migrate 0.8 → 0.9](migrate-to-0.9.md): the four behavior deltas inside existing surfaces (limit-death stream order, turn-trace metadata, cache-stable disclosure, labeled usage estimates), every new option with its sizing line, and 0.9.0 host migration steps.
259
264
  - [Migrate 0.7 → 0.8](migrate-to-0.8.md): work-family import map, messaging channels, connected apps, durable runs, and 0.8.0 host migration steps.
@@ -265,23 +270,23 @@ Prism is a TypeScript/Node.js agent harness. Hosts own providers, tools, credent
265
270
 
266
271
  ## Package inventory
267
272
 
268
- The generated inventory below derives from [`scripts/package-truth.json`](../scripts/package-truth.json) — regenerate with `node scripts/package-truth.mjs --emit-docs`, never hand-edit.
273
+ The generated inventory below derives from [`scripts/package-truth.json`](../scripts/package-truth.json) — regenerate with `bun scripts/package-truth.mjs --emit-docs`, never hand-edit.
269
274
 
270
275
  <!-- generated:package-truth:inventory begin -->
271
- **12 publishable manifests** — root `@arnilo/prism` plus 11 workspace packages (4 `prism-*` family packages, 7 capability packages). Generated by `node scripts/package-truth.mjs --emit-docs` — do not hand-edit.
276
+ **12 publishable manifests** — root `@arnilo/prism` plus 11 workspace packages (4 `prism-*` family packages, 7 capability packages). Generated by `bun scripts/package-truth.mjs --emit-docs` — do not hand-edit.
272
277
 
273
278
  | package | version | notes |
274
279
  | --- | --- | --- |
275
- | `@arnilo/prism` | 0.11.0 | core — runtime, CLI/RPC, templates, docs |
276
- | `@arnilo/prism-channels` | 0.11.0 | family — transport-neutral messaging runtime, durable journal, pairing and one-use approvals; official /telegram (private DMs, opt-in granted groups/topics) and experimental pinned signal-cli /signal |
277
- | `@arnilo/prism-coding-tools` | 0.11.0 | family — /agent, /security, /openapi, /computer-use-linux, /dev, /impeccable subpaths |
278
- | `@arnilo/prism-core` | 0.11.0 | family — /runtime, /sessions, /governance, /credentials, /enterprise, /validation subpaths |
279
- | `@arnilo/prism-providers` | 0.11.0 | family — all provider adapters as `/<adapter>` subpaths |
280
- | `@arnilo/prism-acp-agent` | 0.11.0 | capability — ACP adapter |
281
- | `@arnilo/prism-ag-ui` | 0.11.0 | capability — AG-UI/A2A/A2UI adapter |
282
- | `@arnilo/prism-hooks` | 0.11.0 | capability — Claude/Codex-compatible hooks.json adapter compiled onto middleware, guardrail, injector, and stop-hook seams |
283
- | `@arnilo/prism-mcp` | 0.11.0 | capability — MCP client/server/OAuth interop |
284
- | `@arnilo/prism-memory` | 0.11.0 | capability — memory plus /rag, /compaction/*, /fabric, /wiki subpaths |
285
- | `@arnilo/prism-web-tools` | 0.11.0 | capability — Brave/Exa/Firecrawl plus peer-gated /browser and /obscura subpaths |
286
- | `@arnilo/prism-work` | 0.11.0 | capability — /connectors, /documents, /sheets, /diagrams, /document-reader, /sandbox, /skills, /tools subpaths |
280
+ | `@arnilo/prism` | 0.12.0 | core — runtime, CLI/RPC, templates, docs |
281
+ | `@arnilo/prism-channels` | 0.12.0 | family — transport-neutral messaging runtime, durable journal, pairing and one-use approvals; official /telegram (private DMs, opt-in granted groups/topics) and experimental pinned signal-cli /signal |
282
+ | `@arnilo/prism-coding-tools` | 0.12.0 | family — /agent, /security, /openapi, /computer-use-linux, /dev, /impeccable subpaths |
283
+ | `@arnilo/prism-core` | 0.12.0 | family — /runtime, /sessions, /governance, /credentials, /enterprise, /validation subpaths |
284
+ | `@arnilo/prism-providers` | 0.12.0 | family — all provider adapters as `/<adapter>` subpaths |
285
+ | `@arnilo/prism-acp-agent` | 0.12.0 | capability — ACP adapter |
286
+ | `@arnilo/prism-ag-ui` | 0.12.0 | capability — AG-UI/A2A/A2UI adapter |
287
+ | `@arnilo/prism-hooks` | 0.12.0 | capability — Claude/Codex-compatible hooks.json adapter compiled onto middleware, guardrail, injector, and stop-hook seams |
288
+ | `@arnilo/prism-mcp` | 0.12.0 | capability — MCP client/server/OAuth interop |
289
+ | `@arnilo/prism-memory` | 0.12.0 | capability — memory plus /rag, /compaction/*, /fabric, /wiki subpaths |
290
+ | `@arnilo/prism-web-tools` | 0.12.0 | capability — Brave/Exa/Firecrawl plus peer-gated /browser and /obscura subpaths |
291
+ | `@arnilo/prism-work` | 0.12.0 | capability — /connectors, /documents, /sheets, /diagrams, /document-extraction, /document-reader, /sandbox, /skills, /tools subpaths |
287
292
  <!-- generated:package-truth:inventory end -->
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- Prism ships three network-free test tiers by default (`npm test`, per-package `node --test` suites, and packed-consumer journeys) plus an opt-in **live matrix** that runs the same public surface against real credentials. This page documents how to run the live matrix, which credentials each suite needs, and the guarantees the harness gives you: a missing credential skips its suite (never fails), and secrets never enter the repo, logs, or reports.
5
+ Prism ships three network-free test tiers by default (`bun run test`, per-package `bun test` suites, and packed-consumer journeys) plus an opt-in **live matrix** that runs the same public surface against real credentials. This page documents how to run the live matrix, which credentials each suite needs, and the guarantees the harness gives you: a missing credential skips its suite (never fails), and secrets never enter the repo, logs, or reports.
6
6
 
7
7
  ## When to use it
8
8
 
package/docs/mcp-tools.md CHANGED
@@ -32,7 +32,7 @@ const app = await bridge.apps!.readResource("ui://weather/card");
32
32
 
33
33
  `bridge.apps` exposes reviewed UI metadata, linked bounded `ui://` HTML, and same-server app tools for a host renderer/proxy; it never creates an iframe or executes HTML.
34
34
 
35
- **Conformance and verification record (plan 063 task 7):** the official `@modelcontextprotocol/conformance` suite runs against the dual-era serving stack via `node scripts/mcp-conformance-2026.mjs` — the 20 expressible scenarios pass and the 14 scenarios requiring surface Prism does not expose (server-initiated sampling/elicitation/logging/progress from tool callbacks, `resources/subscribe`, completion capability, session-based SSE polling, non-text tool content blocks) are recorded as documented boundaries in `scripts/mcp-conformance-2026-baseline.yaml`. The CLI publishes scenarios only up to spec version 2025-11-25; the run is repeated when 2026-07-28 scenarios ship upstream. Measured on the loopback fixture (single process): legacy connect ~60ms, auto connect (with the one discovery probe) ~40ms, pinned modern connect ~20ms, steady-state bridge tool call ~4ms, uncached list walk ~5ms, cached list refresh ~2ms — the only added connect cost versus 1.x is the single negotiation probe plus SDK codec work. Security regression coverage lives in the package suites: malformed envelopes/headers, auth mix-up (`ERR_PRISM_MCP_OAUTH_ORIGIN`), SSRF/DNS-rebinding, oversized JSON/schema/results, MRTR round/replay, subscription exhaustion caps, cross-principal cache/session isolation, timeouts, cancellation, and redaction.
35
+ **Conformance and verification record (plan 063 task 7):** the official `@modelcontextprotocol/conformance` suite runs against the dual-era serving stack via `bun scripts/mcp-conformance-2026.mjs` — the 20 expressible scenarios pass and the 14 scenarios requiring surface Prism does not expose (server-initiated sampling/elicitation/logging/progress from tool callbacks, `resources/subscribe`, completion capability, session-based SSE polling, non-text tool content blocks) are recorded as documented boundaries in `scripts/mcp-conformance-2026-baseline.yaml`. The CLI publishes scenarios only up to spec version 2025-11-25; the run is repeated when 2026-07-28 scenarios ship upstream. Measured on the loopback fixture (single process): legacy connect ~60ms, auto connect (with the one discovery probe) ~40ms, pinned modern connect ~20ms, steady-state bridge tool call ~4ms, uncached list walk ~5ms, cached list refresh ~2ms — the only added connect cost versus 1.x is the single negotiation probe plus SDK codec work. Security regression coverage lives in the package suites: malformed envelopes/headers, auth mix-up (`ERR_PRISM_MCP_OAUTH_ORIGIN`), SSRF/DNS-rebinding, oversized JSON/schema/results, MRTR round/replay, subscription exhaustion caps, cross-principal cache/session isolation, timeouts, cancellation, and redaction.
36
36
 
37
37
  **Extension status (revalidated 2026-09-05 against the modular SDK v2, plan 063 task 6):** MCP Apps (`io.modelcontextprotocol/ui`) is the only extension Prism negotiates — on both the 2025 legacy handshake and 2026-07-28 (modern capabilities ride per request in `params._meta`); resource reads/pagination now go through SDK v2 `listResources`/`readResource` with the same per-descriptor byte bounds, item caps, cursor-loop detection, and linked-HTML validation as before. **Tasks (`io.modelcontextprotocol/tasks`) is intentionally not advertised and not supported in this release**: neither the bridge client nor `createPrismMcpServer` declares it, draft-era `task` members on tool results fail closed (`McpBridgeError` surfaced as a `ToolResult.error`, never read as tool output; modern `resultType: "task"` fails SDK decode), and task handles are not accepted without a supported extension codec plus a durable ownership model. Re-evaluate Tasks when the official TypeScript client/server extension codec supports task result dispatch, polling/update/cancel, and subscription notifications with green conformance.
38
38
 
@@ -298,7 +298,7 @@ Official Exa/Firecrawl MCP servers may be tested only as explicit hardened proto
298
298
  An operator-gated smoke drives `createPrismMcpServer` through the real `@modelcontextprotocol/client` SDK over a real stdio subprocess — the same shape a production MCP host uses:
299
299
 
300
300
  ```bash
301
- PRISM_TEST_MCP_CLIENT=1 node scripts/mcp-client-smoke.mjs
301
+ PRISM_TEST_MCP_CLIENT=1 bun scripts/mcp-client-smoke.mjs
302
302
  ```
303
303
 
304
304
  The scenario stays sandboxed (read-only echo tool, authorize-gated denial, no policy bypass) and covers: modern auto + legacy handshakes, `tools/list` of registered capabilities, `tools/call` round-trip, the authorize gate enforced over the wire, and malformed-frame fail-closed (the transport tears the connection down instead of answering garbage). Server-initiated `elicitation/create` is a documented Prism boundary (`scripts/mcp-conformance-2026-baseline.yaml`); the bridge-side MRTR elicitation round-trip is covered over real HTTP by the package's modern-bridge tests. Registered in `scripts/live-matrix.json` as `mcp/client-smoke`.
@@ -17,7 +17,7 @@ Use when a host already operates a chat bot (or plans to) and wants selected Pri
17
17
  Install the required `@arnilo/prism` peer plus this package. `createMessagingRuntime` takes `MessagingRuntimeOptions`: `authorize`, `resolveAgent`, `deliver`, optional `limits` (`ChannelLimits`), `redactor`, `checkpoints`, `leases`, and `resolveBinding`. Durable writers are also constructed with `ChannelStateStoreOptions`, `ChannelDeliveryJournalOptions`, and `ChannelPairingStoreOptions`.
18
18
 
19
19
  ```bash
20
- npm install @arnilo/prism @arnilo/prism-channels
20
+ bun add @arnilo/prism @arnilo/prism-channels
21
21
  ```
22
22
 
23
23
  ## Request/response example
@@ -329,7 +329,7 @@ Additive. `@arnilo/prism-providers/bedrock` now ships a native route next to the
329
329
  3. Re-check each §4–§17 item your host touches: they are behavioral tightenings inside existing surfaces (accounting, drafts, authorization, narrowing, fidelity), not new opt-ins.
330
330
  4. Adopt the opt-in additions only where they matter: §18 attention compiler, §19 memory fabric, §20 work scopes, §21 spawn tools.
331
331
  5. Build and run your suite. No persisted-data migration exists or is needed: the 0.7.0 additions write through existing stores (working/vector records, checkpoints, observational-memory entries) under the same schema, and stores still fail closed on unknown or newer schema versions rather than rewriting data.
332
- 6. Optional: re-run `npm run release:gate` locally to reproduce the release evidence matrix.
332
+ 6. Optional: re-run `bun run release:gate` locally to reproduce the release evidence matrix.
333
333
 
334
334
  ## Rollback
335
335
 
@@ -98,7 +98,7 @@ Identity-bound MCP connected-app sessions admit host-selected transports and reg
98
98
 
99
99
  ## Operator / release honesty (not a host API break)
100
100
 
101
- - `npm run test:postgres` writes gitignored `scripts/postgres-evidence.json` bound to `git rev-parse HEAD`. `release:gate` reports the Postgres surface as pass only when that evidence matches this tree. A stale phase baseline is **blocked**.
101
+ - `bun run test:postgres` writes gitignored `scripts/postgres-evidence.json` bound to `git rev-parse HEAD`. `release:gate` reports the Postgres surface as pass only when that evidence matches this tree. A stale phase baseline is **blocked**.
102
102
  - Coverage artifact keys must equal live workspace package names (`@arnilo/prism-work`, not `@arnilo/prism-office`).
103
103
 
104
104
  ## Upgrade steps
@@ -108,7 +108,7 @@ Identity-bound MCP connected-app sessions admit host-selected transports and reg
108
108
  3. Adopt §6–§9 only where the host wants channels, connected apps, durable-run checkpoints, or the work sandbox. Omitted, request bytes and tool lists stay 0.7.0.
109
109
  4. Re-read §2–§5 if the host runs observational-memory workers, messaging channels, AG-UI, or inspects checkpoint ownership errors.
110
110
  5. Build and run the host suite. No new session-store schema version ships in 0.8.0; channel journals and work HTTP state are new stores a 0.7.0 host never opened.
111
- 6. Optional: `PRISM_TEST_POSTGRES_URL=… npm run test:postgres` then `npm run release:gate` to reproduce this-tree Postgres evidence.
111
+ 6. Optional: `PRISM_TEST_POSTGRES_URL=… bun run test:postgres` then `bun run release:gate` to reproduce this-tree Postgres evidence.
112
112
 
113
113
  ## Rollback
114
114
 
@@ -196,7 +196,7 @@ Sizing: the local reranker declares no inference dependency — the built-in loa
196
196
  3. Re-read §1–§4 if the host tails durable agent events, parses provider-turn metadata, uses progressive disclosure or prompt caching, or bills usage for vendors that report no usage.
197
197
  4. Adopt §5–§13 only where the host wants the new surfaces. Omitted, request bytes, stores, and tool lists stay 0.8.
198
198
  5. Run the new migration 004 on SQLite/Postgres stores if the host wants indexed session search; existing tables and columns are untouched, and 0.8 stores open unchanged.
199
- 6. Optional: `PRISM_TEST_POSTGRES_URL=… npm run test:postgres` then `npm run release:gate` to reproduce this-tree Postgres evidence.
199
+ 6. Optional: `PRISM_TEST_POSTGRES_URL=… bun run test:postgres` then `bun run release:gate` to reproduce this-tree Postgres evidence.
200
200
 
201
201
  ## Rollback
202
202
 
package/docs/migration.md CHANGED
@@ -85,7 +85,7 @@ What a 0.6.0 host must check before upgrading:
85
85
 
86
86
  What a 0.5.x host must check before upgrading:
87
87
 
88
- - **Runtime.** Move the host process and any container image to Node 22.6+ (the docs/test harness strips TypeScript natively from 22.6; Node 22 LTS or later is the supported answer). `engines.node` is now `>=22`, so `npm install` fails closed on older runtimes with `engine-strict` enabled.
88
+ - **Runtime.** Move the host process and any container image to Node 22.6+ (the docs/test harness strips TypeScript natively from 22.6; Node 22 LTS or later is the supported answer). `engines.node` is now `>=22`, so `npm install` fails closed on older runtimes with `engine-strict` enabled. (The Node floor retired in 0.12.0 — the manifests declare `engines.bun >=1.4.2`; see [history/retire-node-runtime.md](history/retire-node-runtime.md).)
89
89
  - **CI legs.** The release workflow's compatibility leg is renamed `node20-compat` → `node22-compat` and runs on `node-version: "22"`; branch-protection required-check lists that name the old job id must be updated.
90
90
  - **Development types.** `@types/node` (dev) moves `^20.19.0` → `^22.20.0` in the root and `@arnilo/prism-coding-tools`, tracking the declared floor. Hosts building Prism from source should not pin their own `@types/node` below 22 while the floor is `>=22`.
91
91
  - **No migration step for Prism itself.** No import path, store schema, event shape, or public signature changed for the floor; it is one of the two host-visible deltas in this cut (`scripts/phase12-freeze-manifest.json` deviation `dev-006`), the other being the third-party peer floors and the removed `@arnilo/prism-office` `playwright-core` peer listed in [migrate-to-0.6.md](migrate-to-0.6.md#3-arniloprim-office-is-peer-free).
@@ -106,7 +106,7 @@ The 0.5.7 cut was never published, so its content ships in 0.6.0. Third-party ra
106
106
  Dev-tooling and release-gate changes in the same cut (no host action required):
107
107
 
108
108
  - **`@types/node` dev `^26.1.1` → `^20.19.0` at the 0.5.7 cut, then `^22.20.0` here.** Development types track the declared runtime floor, so a Node-22+-only API fails the build instead of compiling clean against a newer type surface. `docs/release-and-install.md` records the policy: the types package tracks the floor, and raising the floor is a support-matrix change (freeze manifest + CI legs), not a dependency bump. The `^20.19.0` pin immediately caught four runnable examples using `import.meta.main` (Node ≥22.18/≥24.2) on a Node-20 floor — they now use the house `import.meta.url === \`file://${process.argv[1]}\`` guard, so they no longer silently no-op below Node 22.18.
109
- - **Node 20 floor removed in 0.6.0.** The never-published 0.5.7 deliberately kept `engines.node >=20` because dropping a supported line is a host-breaking support-matrix change that does not belong in a patch release; the 0.6.0 minor is the right vehicle (Node 22 is maintenance LTS to 2027-04-30, Node 24 active LTS to 2028-04-30).
109
+ - **Node 20 floor removed in 0.6.0.** The never-published 0.5.7 deliberately kept `engines.node >=20` (both Node floors retired in 0.12.0) because dropping a supported line is a host-breaking support-matrix change that does not belong in a patch release; the 0.6.0 minor is the right vehicle (Node 22 is maintenance LTS to 2027-04-30, Node 24 active LTS to 2028-04-30).
110
110
  - **Internal first-party ranges are gated at the cut version exactly.** `release.mjs validateRelease` (lockstep mode, which `release.mjs gate --lockstep --version` and the publish path both use) requires every `@arnilo/*` range to be the cut version (exact `0.6.0` or caret `^0.6.0`). A range that merely *satisfies* it — `^0.5.5` alongside `^0.5.6`, which is what the pre-cut tree carried — now fails the gate closed, because it lets two installs of the same release line resolve different first-party minors.
111
111
 
112
112
  ## 0.5.3 → 0.5.4 (export-shape break in `@arnilo/prism`)
@@ -157,7 +157,7 @@ The `@arnilo/prism-providers/model-discovery` adapters have an opt-in live leg t
157
157
 
158
158
  ```bash
159
159
  PRISM_LIVE_PROVIDER_TESTS=1 OPENAI_API_KEY=... # or GEMINI_API_KEY for the Google route
160
- node --test packages/prism-providers/dist/model-discovery/__tests__/live.test.js
160
+ bun test packages/prism-providers/dist/model-discovery/__tests__/live.test.js
161
161
  ```
162
162
 
163
163
  Chooses the OpenAI-compatible or Google route based on which key is present; neither → skip.
@@ -192,6 +192,27 @@ The adapter executes an explicit six-stage lifecycle for every call:
192
192
  - Usage recording errors: Propagate out on success so persistence failures are not concealed.
193
193
  - Invokes `onSettlement` callback with `GovernedInvocationSettlement` telemetry.
194
194
 
195
+ ### Aggregate budgets across host step loops
196
+
197
+ A host that runs one business step per `session.run()` can keep one aggregate liability pool by
198
+ supplying the **same `taskId`** to every call: reservations and usage aggregate at the task/owner
199
+ level, so a per-run token cap is never a per-run reset. The model stays pinned (configure one fixed
200
+ `model` and no fallbacks) — this is policy-preserving accounting, not model routing. Run three
201
+ sequential calls plus auxiliary paid work (for example a compaction attempt admitted through
202
+ `router.resolve`) and read `router.readBudget({ identity, taskId })` for the remaining aggregate;
203
+ never represent that number by faking a context-window or attention threshold.
204
+
205
+ - **Hold renewal fencing**: renew a long hold with `router.renewBudget()` or
206
+ `governedProvider.renewBudget()`. The fencing token advances and the pre-renewal handle fails
207
+ closed with `ERR_PRISM_MODEL_ROUTER_STATE` instead of committing twice.
208
+ - **Unknown liability**: a provider that reports no usage settles the *reserved* amount as
209
+ `unknownUsage: true` (never zero), visible on `GovernedInvocationSettlement` and in diagnostics.
210
+ - **Durability boundary**: without a `stateStore` the pool is process-local; surviving worker
211
+ restarts needs a durable store (for example [enterprise PostgreSQL state](enterprise-postgres-state.md)).
212
+
213
+ Runnable composition: [`examples/model-router-aggregate-budgets.ts`](../examples/model-router-aggregate-budgets.ts)
214
+ (offline, three `session.run()` calls plus one auxiliary call on a fixed pin).
215
+
195
216
  ### Synchronous facade (`providerSource`) governance matrix
196
217
 
197
218
  The synchronous `router.providerSource(model)` facade is strictly intended for simple synchronous resolution where allow-lists and residency checks are sufficient. Any configuration requiring asynchronous state or multi-candidate evaluations fails closed at call time:
@@ -1,11 +1,12 @@
1
- # Multi-agent patterns: handoff, crew, supervisor, spawn tool, A2A
1
+ # Multi-agent patterns: handoff, crew, supervisor, spawn tool, A2A, event-driven swarm
2
2
 
3
3
  ## What it does
4
4
 
5
- Maps five Prism answers for "more than one agent" onto one decision table. All five compose existing seams — none introduces a new runtime:
5
+ Maps six Prism answers for "more than one agent" onto one decision table. All six compose existing seams — none introduces a new runtime:
6
6
 
7
7
  - **In-session handoff (swarm)** — agent A transfers control of the ongoing conversation to agent B by calling a host-built `handoff` tool; the host resolves the target `AgentDefinition` with `resolveAgentDefinition` and opens the specialist against the same session (same store + session id, previous run's `leafId`). One transcript, no new session. No helper primitive ships; the tool factory lives in [`examples/handoff-swarm.ts`](../examples/handoff-swarm.ts).
8
8
  - **Hierarchical crew** — a manager agent decomposes a goal into typed tasks (`{ tasks: [{ role, instruction }] }`) via structured output ([`Artifact*`](structured-output.md)), fans out to parallel role specialists with bounded `maxFanOut` ([`fanOutNode`](workflows.md)), aggregates deliverables with host reduce ([`joinNode`](workflows.md)), and validates outputs with conditional routing to completion or revision ([`conditionalNode`](workflows.md)). The entire process is a deterministic DAG workflow with zero new runtime primitives. Live demo in [`examples/crew-hierarchy.ts`](../examples/crew-hierarchy.ts).
9
+ - **Event-driven swarm topology** — autonomous specialist agents communicate dynamically over a shared event router node using topic subscriptions ([`defineSwarmWorkflow`](workflows.md#declarative-event-driven-swarm-topology), [`swarmRouterNode`](workflows.md#declarative-event-driven-swarm-topology), [`publishSwarmEvent`](workflows.md#declarative-event-driven-swarm-topology)), per-node scoped working memory ([`withNodeScope`](workflows.md#scoped-per-node-state-and-subgraph-isolation)), and wave-based cyclic supersteps. Runnable proof: [`examples/cyclic-swarm-topology.ts`](../examples/cyclic-swarm-topology.ts).
9
10
  - **Supervisor delegation** — `@arnilo/prism-core/runtime/supervisor` `delegate()` invokes allow-listed child agents as bounded runs and returns their result to the parent. Separate child transcripts, hooks, budgets, narrowing.
10
11
  - **In-process spawn tool** — `createSpawnAgentTool({ supervisor })` gives a parent model non-exclusive sync or bounded async `spawn_agent` calls over that same host-owned supervisor catalog; `wait_agent` / `cancel_agent` join or abort local handles. It is an API adapter, not a runtime.
11
12
  - **A2A 1.0** — cross-service interop over the JSON-RPC/HTTPS binding; the remote peer's lifecycle is host-owned behind `A2ATaskLifecycle`.
@@ -16,11 +17,12 @@ Maps five Prism answers for "more than one agent" onto one decision table. All f
16
17
  | --- | --- | --- | --- | --- |
17
18
  | In-session handoff | One host, one ongoing conversation; the model decides **when** to transfer; specialists are alternate definitions of the same app | One continuous transcript chain (same store, session id, `leafId`) | Same session scope; give the specialist its own identity via its definition (`AgentConfig.identity` / `RunOptions.identity`) | Attribution is per-run: each `session.run()`'s events/result belong to the active definition — record the swap in host bookkeeping; no `delegated_agent_step` event exists for in-process swaps |
18
19
  | Hierarchical crew | A goal requires dynamic decomposition by a manager LLM, parallel execution by role specialists, host aggregation, and conditional validation/revision loop | Workflow DAG execution — each specialist executes a bounded child task session; final deliverable returns to host | Workflow tenant/ownership scopes propagate; specialists activate only their own narrowed `tools` | Workflow node events (`node_started`/`node_finished`/`agent_event`); task attribution per role in the aggregated deliverable |
20
+ | Event-driven swarm | Multiple specialist agents collaborate asynchronously by publishing and subscribing to topic events; decentralized cyclic workflow | Workflow cyclic supersteps — agents run in waves triggered by matching event topics; state isolated per agent scope | Workflow tenant/ownership scopes propagate; each agent updates only its scoped slice of state and emits topic events | Wave-level checkpoints with `node_started`/`node_finished`/`agent_event` pairs per iteration; published swarm events recorded in state |
19
21
  | Supervisor delegation | Host code dynamically selects a bounded child run | Separate runs; child result returns to the host | Parent identity/effectStore propagate; child factories receive derived resource/thread ids and AND-composed permission | Dedicated `delegation_started/finished/rejected/error` events, projectable through observability `handleDelegation()`; opt-in `delegation_child_event` passthrough |
20
22
  | In-process spawn tool | Parent model needs an allow-listed child as a non-exclusive tool call | Separate runs; sync result returns through `spawn_agent`, async handle joins through `wait_agent` | Host owns catalog, tools, scopes, limits, and local handles; schema accepts only child ID/input/thread ID/mode plus policy args the host ceiling allows | Same supervisor `delegation_*` events; with host opt-in, `child_milestone` / `delegation_child_event` (redacted, capped, rate-coalesced) |
21
23
  | A2A 1.0 | The other agent is owned by a **different service/deployment**; cross-org or cross-cluster; needs durable task lifecycle, push configs, streaming | Protocol boundary (JSON-RPC/HTTPS agent card); replay/reconnect via host-owned task adapter | Exact-origin verified client, `A2AAuthorization` per operation, principal-scoped push configs | Host-owned task adapter records the remote lifecycle; Prism creates no worker/store |
22
24
 
23
- Rule of thumb: same conversation → handoff; dynamic task decomposition + parallel execution → hierarchical crew; host-selected same-process subtask → supervisor delegation; model-requested allow-listed subtask → in-process spawn tool; different deployment/trust boundary → A2A.
25
+ Rule of thumb: same conversation → handoff; dynamic task decomposition + parallel execution → hierarchical crew; decentralized asynchronous event routing → event-driven swarm; host-selected same-process subtask → supervisor delegation; model-requested allow-listed subtask → in-process spawn tool; different deployment/trust boundary → A2A.
24
26
 
25
27
  ## How in-session handoff works
26
28
 
@@ -138,7 +140,78 @@ Live demo: [`examples/crew-hierarchy.ts`](../examples/crew-hierarchy.ts) — man
138
140
  | **Process (Sequential / Hierarchical)** | Workflow DAG ([`defineWorkflow`](workflows.md) / Edges) | Edges define data and execution dependencies; no unconstrained agent-to-agent loops. |
139
141
  | **Task Output Aggregation** | Join Node ([`joinNode`](workflows.md) + `reduce`) | Host-controlled reduction aggregating specialist outputs and computing per-role attribution. |
140
142
  | **Validation & Quality Review** | Conditional Node ([`conditionalNode`](workflows.md)) | Deterministic branch routing to `complete` or `revise` based on validation criteria. |
141
- | **Process Revision Loop** | Node Retries / DAG Branching / Loop Node ([`loopNode`](workflows.md)) | Bounded retry/revision path or bounded in-graph loop iteration. |
143
+ | **Process Revision Loop** | Node Retries / DAG Branching / Loop Node ([`loopNode`](workflows.md)) | Bounded retry/revision path, in-graph loop iteration, or cyclic workflow reflection loops with back-edges under `limits.maxSupersteps`. |
144
+
145
+ ## How event-driven swarm topology works
146
+
147
+ In an event-driven swarm topology, autonomous specialist agents collaborate asynchronously by publishing typed topic events to a central router node (`swarmRouterNode`). The router matches published topics against declared subscriptions and activates matching subscriber agents in wave-based cyclic supersteps:
148
+
149
+ ```mermaid
150
+ flowchart TD
151
+ Event["Swarm Event Stream (__swarmEvents)"] --> Router["Swarm Router Node (routeNode)"]
152
+ Router -- "incident:new" --> Triage["Triage Specialist (withNodeScope)"]
153
+ Router -- "research:security" --> Researcher["Security Researcher (withNodeScope)"]
154
+ Router -- "verify:patch" --> Verifier["Patch Verifier (withNodeScope)"]
155
+ Triage -. "publishSwarmEvent(research:security)" .-> Router
156
+ Researcher -. "publishSwarmEvent(verify:patch)" .-> Router
157
+ Verifier -. "No further events (Idle Drain)" .-> Success["Workflow Succeeded"]
158
+ ```
159
+
160
+ ```ts
161
+ import {
162
+ defineSwarmWorkflow,
163
+ functionNode,
164
+ getSwarmEvents,
165
+ publishSwarmEvent,
166
+ runWorkflow,
167
+ withNodeScope,
168
+ } from "@arnilo/prism-core/runtime/workflows";
169
+
170
+ // 1. Specialist agents wrapped with withNodeScope maintain isolated working memory
171
+ const triage = withNodeScope("triage", functionNode({
172
+ execute: async (ctx) => {
173
+ const events = getSwarmEvents(ctx);
174
+ const incident = events.find((e) => e.topic === "incident:new");
175
+ await ctx.updateState({ incidentId: (incident?.payload as { id?: string })?.id });
176
+
177
+ // Publish event for downstream specialists
178
+ await publishSwarmEvent(ctx, {
179
+ topic: "research:security",
180
+ sender: "triage",
181
+ payload: { query: "Analyze CVE impact" },
182
+ });
183
+ return "triaged";
184
+ },
185
+ }));
186
+
187
+ // 2. Define the swarm with cyclic topic subscriptions and a wave limit
188
+ const swarm = defineSwarmWorkflow({
189
+ id: "security-swarm",
190
+ revision: "1",
191
+ maxSupersteps: 12,
192
+ agents: { triage, researcher, verifier },
193
+ subscriptions: {
194
+ "incident:new": ["triage"],
195
+ "research:*": ["researcher"],
196
+ "verify:*": ["verifier"],
197
+ },
198
+ initialState: {
199
+ __swarmEvents: [
200
+ { topic: "incident:new", sender: "gateway", payload: { id: "INC-8802" } },
201
+ ],
202
+ },
203
+ });
204
+
205
+ const result = await runWorkflow(swarm, null);
206
+ ```
207
+
208
+ Live demo: [`examples/cyclic-swarm-topology.ts`](../examples/cyclic-swarm-topology.ts) — complete triage → security research → patch verification cycle with per-agent state scoping and clean idle-drain termination.
209
+
210
+ ### Core swarm properties
211
+ - **Topic Subscriptions**: Match exact strings (`"ticket:billing"`) or wildcard prefix patterns (`"ticket:*"` or `"*"`).
212
+ - **Two-Phase Queueing**: Pending events are promoted to `__swarmActiveEvents` during the active superstep wave, while newly published events accumulate in `__swarmEvents` for the next wave.
213
+ - **Scoped Working Memory**: `withNodeScope` guarantees agents only read/write their dedicated state slice without risking key collisions across concurrent or cyclic steps.
214
+ - **Deterministic Termination**: The cycle drains cleanly to `status: "succeeded"` as soon as no more events are emitted, protected by `limits.maxSupersteps`.
142
215
 
143
216
  ## How the in-process spawn tool works
144
217
 
package/docs/obscura.md CHANGED
@@ -13,7 +13,7 @@ the package at it.
13
13
  ## Install
14
14
 
15
15
  ```bash
16
- npm install @arnilo/prism-web-tools @arnilo/prism-mcp
16
+ bun add @arnilo/prism-web-tools @arnilo/prism-mcp
17
17
  ```
18
18
 
19
19
  ## Process lifecycle (`spawnObscuraProcess`)
@@ -53,7 +53,7 @@ Defaults and hard caps (frozen in `scripts/phase11-freeze-manifest.json`): `maxD
53
53
  A live wire probe compiles the real public Warnely OpenAPI 3.1 spec (petstore serves 3.0 — the compiler requires 3.1) and drives real GET operations against it:
54
54
 
55
55
  ```bash
56
- PRISM_LIVE_OPENAPI_TOOLS=1 node --test packages/prism-coding-tools/dist/openapi/__tests__/live.test.js
56
+ PRISM_LIVE_OPENAPI_TOOLS=1 bun test packages/prism-coding-tools/dist/openapi/__tests__/live.test.js
57
57
  ```
58
58
 
59
59
  3 requests total against the allow-listed public host: spec compile, a real 200 tool call, and a real 404 mapped to a status-carrying untrusted result; a missing-argument case proves validation fails closed locally (zero wire calls). Skips (never fails) when `PRISM_LIVE_OPENAPI_TOOLS` is unset. Registered in `scripts/live-matrix.json` as `coding-tools/openapi-live`.
@@ -47,7 +47,7 @@ await stores.leases.releaseLease({ namespace: "erp.ops", key: "invoice-42", owne
47
47
  # Protected two-replica drill (requires PRISM_TEST_POSTGRES_URL; Docker image
48
48
  # postgres:16-alpine is the local stand-in). Recorded evidence lands in
49
49
  # docs/_evidence/phase27-ha-evidence.json.
50
- `PRISM_TEST_POSTGRES_URL` set to the protected connection string (locally a disposable `postgres:16-alpine` container): `node --test scripts/phase27-ha.test.mjs`
50
+ `PRISM_TEST_POSTGRES_URL` set to the protected connection string (locally a disposable `postgres:16-alpine` container): `bun test scripts/phase27-ha.test.mjs`
51
51
  ```
52
52
 
53
53
  The drill: worker A acquires, heartbeats, commits the charge effect into the
@@ -109,7 +109,7 @@ The outbound webhook notifier has an operator-gated live probe against a receive
109
109
 
110
110
  ```bash
111
111
  PRISM_TEST_WEBHOOK_URL=https://ops.example.com/hooks/prism \
112
- PRISM_TEST_WEBHOOK_SECRET=<at-least-32-byte-shared-key> npm test -w @arnilo/prism-core -- webhooks-live
112
+ PRISM_TEST_WEBHOOK_SECRET=<at-least-32-byte-shared-key> bun run --filter @arnilo/prism-core test
113
113
  ```
114
114
 
115
115
  Probes: one signed delivery to your receiver (verify `x-prism-signature: sha256=<hex>` over the raw body) and a retry-after-5xx leg over a local loopback receiver (500 then 200, signature verified, retries recorded). Bounded to 1 real request + ≤ 2 loopback requests. Registered in `scripts/live-matrix.json` as `core/webhooks-live`.
@@ -11,7 +11,7 @@ Lists every third-party peer a Prism package declares, what importing that peer
11
11
  - Debugging a "peer not installed" error from a gated subpath.
12
12
  - Auditing which of your already-installed packages a Prism surface will reuse.
13
13
 
14
- Internal `@arnilo/*` peers are not listed here: every first-party package declares a required `@arnilo/prism` peer, and the release gate keeps all internal ranges locked to the cut version. This page covers the **12 third-party declarations across 6 packages**.
14
+ Internal `@arnilo/*` peers are not listed here: every first-party package declares a required `@arnilo/prism` peer, and the release gate keeps all internal ranges locked to the cut version. This page covers the **10 third-party declarations across 6 packages**.
15
15
 
16
16
  ## Matrix
17
17
 
@@ -19,16 +19,16 @@ One row per declaration. `Unlocks` names the subpath whose import reaches the pe
19
19
 
20
20
  | Peer | Declared range | Optional | Declared by | Unlocks | Install | Network |
21
21
  | --- | --- | --- | --- | --- | --- | --- |
22
- | `zod` | `^3.25.0 \|\| ^4.0.0` | no | `@arnilo/prism-ag-ui` | `./acp` | `npm i zod` | no |
23
- | `mammoth` | `^1.8.0` | yes | `@arnilo/prism-work` | `./document-reader` | `npm i mammoth` | no |
24
- | `pdf-parse` | `^2.4.5` | yes | `@arnilo/prism-work` | `./document-reader` | `npm i pdf-parse` | no |
25
- | `e2b` | `2.49.1` | yes | `@arnilo/prism-coding-tools` | `./security` | `npm i e2b@2.49.1` | yes |
26
- | `better-sqlite3` | `^13.0.3` | yes | `@arnilo/prism-core` | `./sessions/sqlite`, `./governance/prompts` | `npm i better-sqlite3` | no |
27
- | `pg` | `^8.23.0` | yes | `@arnilo/prism-core` | `./sessions/postgres`, `./enterprise/postgres`, `./governance/prompts` | `npm i pg` | yes |
28
- | `@nats-io/jetstream` | `^3.4.0` | yes | `@arnilo/prism-core` | `./sessions/nats` | `npm i @nats-io/jetstream @nats-io/transport-node` | yes |
29
- | `@nats-io/transport-node` | `^3.4.0` | yes | `@arnilo/prism-core` | `./sessions/nats` | `npm i @nats-io/transport-node` | yes |
30
- | `@ai-sdk/provider` | `4.0.13` | yes | `@arnilo/prism-providers` | `./ai-sdk` | `npm i @ai-sdk/provider@4.0.13` | no |
31
- | `playwright-core` | `1.63.0` | yes | `@arnilo/prism-web-tools` | `./browser`, `./obscura` | `npm i playwright-core@1.63.0` | yes |
22
+ | `zod` | `^3.25.0 \|\| ^4.0.0` | no | `@arnilo/prism-ag-ui` | `./acp` | `bun add zod` | no |
23
+ | `@firecrawl/anydoc` | `0.2.4` | yes | `@arnilo/prism-work` | `./document-extraction` | `bun add @firecrawl/anydoc@0.2.4` | no |
24
+ | `mammoth` | `^1.8.0` | yes | `@arnilo/prism-work` | `./document-reader` | `bun add mammoth` | no |
25
+ | `pdf-parse` | `^2.4.5` | yes | `@arnilo/prism-work` | `./document-reader` | `bun add pdf-parse` | no |
26
+ | `e2b` | `2.49.1` | yes | `@arnilo/prism-coding-tools` | `./security` | `bun add e2b@2.49.1` | yes |
27
+ | `pg` | `^8.23.0` | yes | `@arnilo/prism-core` | `./sessions/postgres`, `./enterprise/postgres`, `./governance/prompts` | `bun add pg` | yes |
28
+ | `@nats-io/jetstream` | `^3.4.0` | yes | `@arnilo/prism-core` | `./sessions/nats` | `bun add @nats-io/jetstream @nats-io/transport-node` | yes |
29
+ | `@nats-io/transport-node` | `^3.4.0` | yes | `@arnilo/prism-core` | `./sessions/nats` | `bun add @nats-io/transport-node` | yes |
30
+ | `@ai-sdk/provider` | `4.0.13` | yes | `@arnilo/prism-providers` | `./ai-sdk` | `bun add @ai-sdk/provider@4.0.13` | no |
31
+ | `playwright-core` | `1.63.0` | yes | `@arnilo/prism-web-tools` | `./browser`, `./obscura` | `bun add playwright-core@1.63.0` | yes |
32
32
 
33
33
  ## Exact pins and why
34
34
 
@@ -37,6 +37,7 @@ Two peers are pinned to an exact version instead of a range, because the pin is
37
37
  - **`playwright-core@1.63.0`** (`@arnilo/prism-web-tools/browser`, `/obscura`). Browser automation rides Playwright's CDP transport and accessibility snapshot shapes, which move between minors. Prism never launches, downloads, or bundles a browser: the host supplies the binary, the image, and the cache, and must match the pinned client. See [Browser automation](browser-automation.md).
38
38
  - **`@ai-sdk/provider@4.0.13`** (`@arnilo/prism-providers/ai-sdk`). The adapter consumes deterministic specification-versioned types (`LanguageModelV4`) and gates on an exact supported-version matrix at construction, so an unlisted version fails closed instead of silently mis-mapping. See [AI SDK provider](providers/ai-sdk.md).
39
39
  - **`e2b@2.49.1`** (`@arnilo/prism-coding-tools/security`). Pause `keepMemory`, `Sandbox.connect` auto-resume, and `ServiceBusyError` 503 semantics are version-specific. Hosts may inject `{ client }` instead of installing the peer. See [Hosted sandboxes](hosted-sandboxes.md).
40
+ - **`@firecrawl/anydoc@0.2.4`** (`@arnilo/prism-work/document-extraction`). Error codes and the wrapper's optional third argument were checked against this release. The wrapper can upload a PDF when `ocr` is `'hosted'`; the Prism subpath never passes that argument and does not read an API key.
40
41
 
41
42
  `zod` is the only **required** third-party peer. `@agentclientprotocol/sdk` — a hard dependency of `@arnilo/prism-ag-ui` — declares `zod: ^3.25.0 || ^4.0.0` as its own peer, so `@arnilo/prism-ag-ui` re-declares the same range to keep the install tree satisfiable; the range is deliberately identical to the SDK's. Nothing in Prism imports zod directly.
42
43
 
@@ -45,7 +46,7 @@ Two peers are pinned to an exact version instead of a range, because the pin is
45
46
  `pg`, `@nats-io/jetstream`, `@nats-io/transport-node`, `playwright-core`, and `e2b` open sockets. For a supply-chain review of those five:
46
47
 
47
48
  - **Connection targets are host-owned.** Every one of them is passed a host-supplied connection string, endpoint list, browser instance, API key, or service URL. Prism holds no default endpoint, and no peer is reachable from the root import.
48
- - **Bytes stay local otherwise.** `better-sqlite3`, `mammoth`, and `pdf-parse` are filesystem/process peers; the remaining two (`zod`, `@ai-sdk/provider`) are pure types/schemas.
49
+ - **Bytes stay local otherwise.** `mammoth`, `pdf-parse`, and `@firecrawl/anydoc` (as called by Prism) are filesystem/process peers; the remaining two (`zod`, `@ai-sdk/provider`) are pure types/schemas. SQLite is the runtime's `bun:sqlite`, not a peer. The anydoc package also ships a hosted-OCR option; `@arnilo/prism-work/document-extraction` does not call it.
49
50
  - **No secrets are read by the peers.** Prism resolves credentials through host providers and redacts them at the boundary; peers only ever receive a resolved connection string or model object. See [Credentials and redaction](credentials-and-redaction.md) and [Host security guide](host-security.md).
50
51
  - **Nothing is installed implicitly.** Optional peers are never auto-installed by npm; a missing one fails closed at the call site with a typed error naming the peer and the subpath. Required peers (today only `zod`) are installed by npm with the package.
51
52
 
@@ -55,16 +56,16 @@ Test-only dependencies are *not* peers. `playwright-core` appears in `@arnilo/pr
55
56
 
56
57
  ```bash
57
58
  # Browser automation: pinned client, host-owned browser binary
58
- npm i @arnilo/prism-web-tools playwright-core@1.63.0
59
+ bun add @arnilo/prism-web-tools playwright-core@1.63.0
59
60
 
60
61
  # PostgreSQL session store: pool driver only
61
- npm i @arnilo/prism-core pg
62
+ bun add @arnilo/prism-core pg
62
63
 
63
64
  # NATS JetStream event source: transport + jetstream together
64
- npm i @arnilo/prism-core @nats-io/transport-node @nats-io/jetstream
65
+ bun add @arnilo/prism-core @nats-io/transport-node @nats-io/jetstream
65
66
 
66
67
  # Document reader: pick the parser you need (both are independent)
67
- npm i @arnilo/prism-work pdf-parse mammoth
68
+ bun add @arnilo/prism-work pdf-parse mammoth
68
69
  ```
69
70
 
70
71
  ```ts
@@ -91,4 +92,4 @@ const tools = await createBrowserTools({ browser });
91
92
 
92
93
  - [Release and install](release-and-install.md): install profiles that pair with each peer.
93
94
  - [Configuration options index](options-index.md): the option surfaces each peer unlocks.
94
- - Package-level detail: [Coding tools](coding-tools.md), [Core runtime](core.md), [Session stores](session-stores.md), [Browser automation](browser-automation.md), [Document reader](document-reader.md), [Provider packages](provider-packages.md), [Messaging channels](messaging-channels.md).
95
+ - Package-level detail: [Coding tools](coding-tools.md), [Core runtime](core.md), [Session stores](session-stores.md), [Browser automation](browser-automation.md), [Document reader](document-reader.md), [Document extraction](document-extraction.md), [Provider packages](provider-packages.md), [Messaging channels](messaging-channels.md).