@arnilo/prism 0.0.96 → 0.1.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 (203) hide show
  1. package/CHANGELOG.md +285 -2
  2. package/README.md +17 -3
  3. package/dist/agent-definitions.js +2 -3
  4. package/dist/agent-event-source.d.ts +11 -0
  5. package/dist/agent-event-source.js +512 -0
  6. package/dist/agent-loops.d.ts +5 -0
  7. package/dist/agent-loops.js +99 -14
  8. package/dist/agent-run-lifecycle.d.ts +5 -2
  9. package/dist/agent-run-lifecycle.js +18 -2
  10. package/dist/agent-run-state.d.ts +27 -1
  11. package/dist/agent-run-state.js +113 -7
  12. package/dist/agents.d.ts +3 -1
  13. package/dist/agents.js +1255 -129
  14. package/dist/artifacts.d.ts +132 -0
  15. package/dist/artifacts.js +44 -0
  16. package/dist/cache-helpers.js +18 -9
  17. package/dist/checkpoints.d.ts +4 -0
  18. package/dist/checkpoints.js +17 -9
  19. package/dist/cli-init.js +3 -7
  20. package/dist/cli-runner.d.ts +2 -6
  21. package/dist/cli-runner.js +71 -33
  22. package/dist/compaction.js +5 -4
  23. package/dist/config.js +7 -4
  24. package/dist/content.js +26 -24
  25. package/dist/context-budget.d.ts +67 -0
  26. package/dist/context-budget.js +288 -0
  27. package/dist/contracts.d.ts +590 -8
  28. package/dist/contracts.js +142 -1
  29. package/dist/contribution-parsing.js +6 -2
  30. package/dist/contributions.d.ts +2 -0
  31. package/dist/contributions.js +3 -0
  32. package/dist/conversations.d.ts +50 -0
  33. package/dist/conversations.js +98 -0
  34. package/dist/credentials.d.ts +22 -2
  35. package/dist/credentials.js +18 -3
  36. package/dist/devices.d.ts +94 -0
  37. package/dist/devices.js +138 -0
  38. package/dist/event-multiplexer.js +18 -4
  39. package/dist/extensions.d.ts +18 -1
  40. package/dist/extensions.js +79 -6
  41. package/dist/feedback.js +12 -10
  42. package/dist/guardrails.d.ts +1 -1
  43. package/dist/guardrails.js +26 -17
  44. package/dist/identity.d.ts +92 -0
  45. package/dist/identity.js +265 -0
  46. package/dist/index.d.ts +94 -72
  47. package/dist/index.js +48 -36
  48. package/dist/input.d.ts +10 -1
  49. package/dist/input.js +152 -52
  50. package/dist/instruction-injection.d.ts +1 -1
  51. package/dist/middleware.js +9 -1
  52. package/dist/models.d.ts +2 -0
  53. package/dist/models.js +3 -0
  54. package/dist/node/agent-definitions.js +16 -8
  55. package/dist/node/contribution-discovery.d.ts +1 -2
  56. package/dist/node/contribution-discovery.js +3 -3
  57. package/dist/node/session-store-jsonl.js +13 -7
  58. package/dist/node/settings.d.ts +1 -1
  59. package/dist/node/settings.js +1 -1
  60. package/dist/node/system-project-prompts.js +2 -4
  61. package/dist/node/trust.js +1 -1
  62. package/dist/persistence-lifecycle.d.ts +103 -0
  63. package/dist/persistence-lifecycle.js +202 -0
  64. package/dist/provider-events.d.ts +1 -0
  65. package/dist/provider-events.js +6 -1
  66. package/dist/provider-request-policy.js +3 -4
  67. package/dist/providers/media.d.ts +1 -1
  68. package/dist/providers/openai-compatible.d.ts +46 -1
  69. package/dist/providers/openai-compatible.js +123 -53
  70. package/dist/providers/openai-primitives.js +10 -7
  71. package/dist/providers/transport.d.ts +6 -0
  72. package/dist/providers/transport.js +21 -0
  73. package/dist/providers.d.ts +2 -0
  74. package/dist/providers.js +3 -0
  75. package/dist/redaction.d.ts +1 -0
  76. package/dist/redaction.js +26 -9
  77. package/dist/resources.d.ts +2 -2
  78. package/dist/resources.js +2 -2
  79. package/dist/retry.d.ts +5 -0
  80. package/dist/retry.js +8 -1
  81. package/dist/rpc.js +55 -11
  82. package/dist/run-ledger.d.ts +6 -0
  83. package/dist/run-ledger.js +16 -13
  84. package/dist/run-limits.js +49 -10
  85. package/dist/secure-agent.js +8 -2
  86. package/dist/security.js +7 -2
  87. package/dist/session-stores.d.ts +7 -2
  88. package/dist/session-stores.js +195 -21
  89. package/dist/skill-disclosure.d.ts +35 -0
  90. package/dist/skill-disclosure.js +101 -0
  91. package/dist/skill-load.d.ts +25 -0
  92. package/dist/skill-load.js +112 -0
  93. package/dist/structured-output.d.ts +5 -1
  94. package/dist/structured-output.js +20 -2
  95. package/dist/system-prompts.js +7 -2
  96. package/dist/testing/agent-event-source-conformance.d.ts +4 -0
  97. package/dist/testing/agent-event-source-conformance.js +54 -0
  98. package/dist/testing/compaction-conformance.js +5 -1
  99. package/dist/testing/extension-conformance.js +15 -3
  100. package/dist/testing/feedback.d.ts +1 -3
  101. package/dist/testing/feedback.js +1 -1
  102. package/dist/testing/persistence-schema.d.ts +2 -2
  103. package/dist/testing/persistence-schema.js +280 -35
  104. package/dist/testing/provider-conformance.js +3 -3
  105. package/dist/testing/run-ledger-conformance.js +1 -1
  106. package/dist/testing/session-store-conformance.d.ts +6 -0
  107. package/dist/testing/session-store-conformance.js +37 -2
  108. package/dist/testing/tool-conformance.js +30 -5
  109. package/dist/testing/tool-effect-store-conformance.d.ts +9 -0
  110. package/dist/testing/tool-effect-store-conformance.js +85 -0
  111. package/dist/thinking.js +4 -1
  112. package/dist/tool-effects.d.ts +15 -0
  113. package/dist/tool-effects.js +352 -0
  114. package/dist/tool-result-fold.d.ts +40 -0
  115. package/dist/tool-result-fold.js +176 -0
  116. package/dist/tools.d.ts +8 -3
  117. package/dist/tools.js +248 -13
  118. package/docs/0.1.0-readiness.md +202 -0
  119. package/docs/a2a.md +33 -2
  120. package/docs/acp.md +126 -0
  121. package/docs/ag-ui-adoption.md +77 -0
  122. package/docs/ag-ui.md +225 -0
  123. package/docs/agent-events.md +34 -3
  124. package/docs/agent-identity.md +144 -0
  125. package/docs/agent-loops.md +17 -2
  126. package/docs/agent-session-runtime.md +21 -4
  127. package/docs/browser-automation.md +5 -0
  128. package/docs/caveman.md +129 -0
  129. package/docs/cli-rpc.md +3 -6
  130. package/docs/coding-agent-tools.md +229 -25
  131. package/docs/coding-security.md +77 -11
  132. package/docs/compaction-and-retry.md +5 -2
  133. package/docs/compaction-llm.md +20 -1
  134. package/docs/compaction-observational-memory.md +52 -8
  135. package/docs/context-and-skills.md +94 -7
  136. package/docs/contribution-registries.md +1 -0
  137. package/docs/conversations.md +135 -0
  138. package/docs/credential-storage.md +34 -1
  139. package/docs/credentials-and-redaction.md +11 -1
  140. package/docs/database-persistence.md +27 -7
  141. package/docs/device-adapters.md +97 -0
  142. package/docs/enterprise-postgres-state.md +178 -0
  143. package/docs/evaluations.md +14 -1
  144. package/docs/extensions.md +4 -1
  145. package/docs/forge-integration.md +113 -0
  146. package/docs/guardrails.md +16 -2
  147. package/docs/host-security.md +35 -4
  148. package/docs/index.md +69 -37
  149. package/docs/input-and-prompt-assembly.md +8 -7
  150. package/docs/language-intelligence.md +162 -0
  151. package/docs/mcp-tools.md +62 -5
  152. package/docs/middleware-hooks.md +2 -2
  153. package/docs/migration.md +423 -2
  154. package/docs/model-routing.md +111 -0
  155. package/docs/multimodal-content.md +8 -5
  156. package/docs/node-jsonl-session-store.md +1 -1
  157. package/docs/observability.md +2 -0
  158. package/docs/openapi-tools.md +56 -0
  159. package/docs/performance.md +282 -0
  160. package/docs/policy-and-audit.md +171 -0
  161. package/docs/ponytail.md +127 -0
  162. package/docs/postgres-persistence.md +8 -4
  163. package/docs/process-sessions.md +147 -0
  164. package/docs/provider-caching.md +13 -1
  165. package/docs/provider-conformance.md +29 -5
  166. package/docs/provider-packages.md +43 -2
  167. package/docs/provider-request-policies.md +2 -0
  168. package/docs/providers/ai-sdk.md +24 -7
  169. package/docs/providers/alibaba.md +179 -0
  170. package/docs/providers/anthropic.md +93 -0
  171. package/docs/providers/azure.md +74 -0
  172. package/docs/providers/bedrock.md +72 -0
  173. package/docs/providers/google.md +89 -0
  174. package/docs/providers/ollama.md +166 -0
  175. package/docs/providers/openai-compatible.md +31 -2
  176. package/docs/providers/openai.md +24 -5
  177. package/docs/providers/openrouter.md +2 -0
  178. package/docs/providers/vertex.md +71 -0
  179. package/docs/public-contracts.md +61 -4
  180. package/docs/rag.md +41 -12
  181. package/docs/release-and-install.md +323 -206
  182. package/docs/resource-loading.md +3 -0
  183. package/docs/runs-and-usage.md +3 -0
  184. package/docs/server.md +44 -6
  185. package/docs/session-store-conformance.md +2 -0
  186. package/docs/session-stores.md +41 -2
  187. package/docs/sqlite-persistence.md +11 -3
  188. package/docs/structured-output.md +7 -1
  189. package/docs/supervisors.md +8 -0
  190. package/docs/tool-effects.md +95 -0
  191. package/docs/tools.md +5 -0
  192. package/docs/work-artifacts-and-review.md +102 -0
  193. package/docs/work-connectors.md +32 -0
  194. package/docs/work-tools.md +137 -0
  195. package/docs/workflows.md +6 -0
  196. package/docs/working-and-semantic-memory.md +40 -7
  197. package/package.json +30 -8
  198. package/templates/init/providers.json +22 -0
  199. package/docs/review-coverage-2026-07-14.md +0 -260
  200. package/docs/review-coverage-2026-07-15.md +0 -193
  201. package/docs/review-coverage-2026-07-17-provider-validation.md +0 -192
  202. package/docs/review-coverage-2026-07-19-phase-3.md +0 -174
  203. package/docs/review-coverage-2026-07-20-phase-4.md +0 -175
@@ -0,0 +1,202 @@
1
+ # 0.1.0 / 1.0 Readiness Gates
2
+
3
+ Status: **0.1.0** is the current release line (Phase 12 release-candidate hardening; plan 012); **1.0** readiness remains operator-gated, not automatic.
4
+
5
+ This page distills runnable readiness gates into one command-per-gate table.
6
+ The **Last evidence** column records the 0.1.0-tree snapshot (plan 012 Tasks
7
+ 0–7, Node v24.18.0, Linux x86_64) with the 2026-07-26 **0.0.16** values kept
8
+ as the historical floor where the baseline predates it. Re-run each gate on
9
+ the release tree before cutting 1.0. The decision to cut 1.0 stays with the
10
+ operator after operator-gated legs run in a protected environment and Phase
11
+ 12 demand evidence exists.
12
+
13
+ Evidence trail: [`docs/review-coverage-2026-07-26-phase-11.md`](./review-coverage-2026-07-26-phase-11.md)
14
+ (addenda 0–9), [`docs/release-and-install.md`](./release-and-install.md),
15
+ [`docs/migration.md`](./migration.md), [`docs/performance.md`](./performance.md),
16
+ [`docs/public-contracts.md`](./public-contracts.md) (frozen 0.1.x contract).
17
+ Historical release lines (0.0.16 floor → 0.0.27 Phase 10 ACP interop → 0.1.0)
18
+ keep their per-phase evidence in the pages above; this page records the 0.1.0 snapshot.
19
+
20
+ ## Current line (0.1.0)
21
+
22
+ | Item | Status |
23
+ |---|---|
24
+ | Published graph | **48** publishable manifests at exact **0.1.0** (root + 48 workspace packages; `docs/release-and-install.md`) |
25
+ | Phase 12 RC hardening | Freeze manifest (`scripts/phase12-freeze-manifest.json`): no new packages/exports/migrations/dependencies, additive-only compat promise vs `scripts/compat-baseline`; compatibility/support matrix machine-checked (Node 20+24 measured, PostgreSQL 16, linux-x64, protocol SDK pins) |
26
+ | Upgrade path | `docs/migration.md` `0.0.28 → 0.1.0` (no migration) + full `0.0.17 → 0.1.0` upgrade matrix (compatible / tested migration / tested refusal per release line) |
27
+ | Packed-install e2e journeys | enterprise + coding journeys install the exact packed 0.1.0 manifest graph into fresh consumers (`scripts/e2e-*-journey.test.mjs`, in `npm test`) |
28
+ | Protected restart-recovery evidence | `npm run test:postgres` includes `scripts/phase12-restart-recovery.test.mjs` (multi-replica kill/resume, unknown-outcome window, DB restart during streaming, reconnect/contention p95 vs frozen ceilings) |
29
+ | Capacity envelopes | `scripts/benchmark-0.1.0.json` — 24 network-free + 16 protected p95 rows under the frozen 0.1.0 contract, re-gated on every `npm test` |
30
+ | Security policy | `npm audit --audit-level=moderate` enforced in workflows; named threat-suites leg (`npm run security:threat-suites`); supply-chain negative fixtures in `scripts/release-gate.test.mjs` |
31
+ | Docs freeze | every public page, package README, and changelog consistent with 0.1.0 behavior; tripwires green (121/121) |
32
+ | Readiness table below | **0.0.16 measured values** remain the historical network-free floor; 0.1.0 evidence is recorded per row |
33
+
34
+ ## Gate table
35
+
36
+ | Gate | Command | Last evidence (0.1.0 tree; 0.0.16 floor where noted) | Owner |
37
+ |---|---|---|---|
38
+ | Full quality gate | `npm run sdk:ready` | RC=0 at 0.1.0: typecheck (+examples), lint 0, format clean, full test, coverage, pack, release:gate (clean-checkout run is part of the operator release checklist) | CI |
39
+ | Exact version graph | `node scripts/release.mjs check --version 0.1.0` | pass at 0.1.0: exact versions/ranges/lockfile/access + registry-collision check, **49** manifests | CI + operator |
40
+ | Frozen public API surface + compat gate | `node scripts/release.mjs gate` | 0 breaks / 0 errors vs checked-in baselines (`scripts/compat-baseline/`); additive-only delta (empty at the 0.0.28 → 0.1.0 bump) | CI |
41
+ | Migration coverage + docs tripwires | `node --test dist/__tests__/docs.test.js` | 121/121 at 0.1.0; `docs/migration.md` sections tripwired per release line | Maintainer |
42
+ | Deterministic artifact budget | `node --test dist/__tests__/budget-gate.test.mjs` | root 713.5 kB packed / 2.1 MB unpacked / 295 files within +5% of the regenerated 0.1.0 baseline; startup < 250 ms | CI (in `npm test`) |
43
+ | **0.1.0 capacity envelope (frozen performance contract)** | `node --test scripts/benchmark-0.1.0.test.mjs` | **`scripts/benchmark-0.1.0.json`** re-gated on every `npm test`: 24 network-free p95 rows ≤ frozen ceilings, 16 protected PostgreSQL rows ≤ budgets.json ceilings (50/100 ms), startup 41.7 ms < 250 ms, root pack within ±5%; regenerate with `node scripts/benchmark-0.1.0.mjs --out scripts/benchmark-0.1.0.json` (+ `PRISM_TEST_POSTGRES_URL` for protected legs) | CI (in `npm test`) |
44
+ | Performance benchmark medians | `node scripts/benchmark-0.1.0.mjs --out scripts/benchmark-0.1.0.json` (+ `PRISM_TEST_POSTGRES_URL` for the 16 protected rows) | envelope re-recorded at 0.1.0 (see capacity-envelope row above); historical phase medians remain in `docs/performance.md` | On-demand release evidence |
45
+ | Secret scan | `node scripts/scan-secrets.mjs` | 0.1.0 tree: 0 findings (3,095-file 0.0.16 floor) | CI |
46
+ | License / SBOM | `node scripts/verify-sbom.mjs` | 0.1.0 tree: 317 locked packages, allow-listed licenses (227/12 at 0.0.16 floor) | CI |
47
+ | Dependency audit | `npm audit --audit-level=moderate` | rc=0 (0 moderate+, 2 moderate at 0.0.16 baseline); 0 vulns at every severity for the 0.1.0 tree | CI |
48
+ | Whitespace hygiene | `git diff --check` | clean | CI |
49
+ | Publish order + tarball validation | `node scripts/release.mjs publish --version 0.1.0 --dry-run --allow-dirty --allow-untagged` | 49/49 packages `dry-run` twice with byte-identical reports, deterministic dependency order, no failures (Task 7) | Operator (dry-run), CI |
50
+ | Node 20 compatibility | CI `node20-compat` (build + public-import smoke) | all 21 root exports import cleanly on Node 20.20.2 | CI |
51
+ | PostgreSQL suite | `PRISM_TEST_POSTGRES_URL="$DATABASE_URL" npm run test:postgres` | 0.1.0: Phase 7 conformance + Phase 12 restart-recovery + 74 workspace checks green against PostgreSQL 16 (Task 4 recording, re-run green at 0.1.0 on 2026-08-09); operator-gated | Operator |
52
+ | Keychain suite | `PRISM_TEST_KEYCHAIN=1 npm test --workspace @arnilo/prism-credentials-node` (protected) | 28/28 green incl. native keychain round-trip against the OS secret-service backend (gnome-keyring, 2026-08-09) | Operator host |
53
+ | Live-provider suites | `npm run test:live` (protected) | **operator-gated** (requires credentials; `live-canaries.yml` blocked gate, `canary-report.json` retained) | Operator |
54
+ | SAST | GitHub CodeQL | **operator-gated** (runs in CI workflow) | CI |
55
+ | Signed, provenance publication | `npm run release:publish` (clean tagged tree, OIDC) | **operator-gated** (see "Remaining for 1.0") | Operator |
56
+
57
+ ## Frozen public API surface
58
+
59
+ The compat gate diffs every package's generated `.d.ts` export surface against
60
+ checked-in baselines in `scripts/compat-baseline/` (one file per package,
61
+ regenerated at 0.1.0). It fails on any **removed** export or changed
62
+ declaration; additive exports are allowed. `scripts/release-gates.mjs` also
63
+ enforces a tarball deny list (no reviews/plans/maps/tests/binaries/credential
64
+ material in published artifacts) and exact version-range drift. A genuine break
65
+ requires `--allow-break` **and** a `docs/migration.md` entry mentioning the
66
+ version. The frozen 0.1.x contract (declaration/exports, events, protocol
67
+ payloads, migration checksums, patch-release compatibility promise) is
68
+ published in [docs/public-contracts.md](public-contracts.md).
69
+
70
+ **Baseline maintenance:** `scripts/compat-baseline/` must stay committed.
71
+ Regenerate only after review with `node scripts/release.mjs gate --update-baseline`,
72
+ having first confirmed zero removed exports (the gate's order-sensitive
73
+ signatures can drift on a TypeScript bump without any real API change).
74
+
75
+ ## Migration coverage
76
+
77
+ `docs/migration.md` carries release migration sections tripwired by
78
+ `docs.test.ts` (headings and key phrases). A missing or gutted section fails
79
+ the suite. **0.0.19** adds observational-memory lifecycle and nested settings in
80
+ `@arnilo/prism-compaction-observational-memory` — see `0.0.18 → 0.0.19 observational memory lifecycle`.
81
+ **0.0.18** adds intentional pre-1.0 breaks (`repo_search` literal-only,
82
+ `cache_aware` default layout, oldest-first history eviction, atomic write/edit
83
+ durability, MCP SDK bump) — see `0.0.17 → 0.0.18 restore integrity`.
84
+
85
+ ## Budget table
86
+
87
+ Deterministic budgets (CI gate, `scripts/budget-gate.test.mjs`):
88
+
89
+ | Metric | Baseline | Tolerance | 0.1.0 measured |
90
+ |---|---|---|---|
91
+ | Root packed bytes | 713,454 (regenerated 0.1.0, dev-001) | +5% | 713.5 kB (within) |
92
+ | Root unpacked bytes | 2,388,118 | +5% | within |
93
+ | Root file count | 293 (regenerated 0.1.0, dev-001) | +5% | 295 (within) |
94
+ | Cold-startup import | 41.7 ms | ceiling 250 ms | within |
95
+
96
+ Baselines are the 0.1.0 snapshot (`scripts/budgets.json`, amended once by
97
+ freeze deviation dev-001 for the Task 1–5 evidence scripts); raise them only
98
+ after a deliberate reviewed performance change.
99
+
100
+ ## Live-suite matrix (operator-gated)
101
+
102
+ | Suite | Command | Environment |
103
+ |---|---|---|
104
+ | PostgreSQL persistence | `npm run test:postgres` | live PostgreSQL |
105
+ | Keychain credentials | protected live suite | OS keychain |
106
+ | Provider live-canary (OpenAI/Anthropic/Google/Kimi/Ollama/…) | protected live-canary matrix | vendor credentials |
107
+ | RAG / memory / workflows live journeys | protected live-canary matrix | vendor + DB credentials |
108
+ | Enterprise adapters live canary (Phase 11: real OIDC IdP/JWKS, real OPA endpoint, real MCP OAuth authorization server, S3-compatible object store) | protected live-canary matrix | IdP / policy / object-store credentials |
109
+
110
+ These do not run on a contributor machine; their evidence is recorded in the
111
+ protected environment, never faked. Phase 11 live-endpoint evidence is a
112
+ **blocked release gate, not a passing skip**: `npm test` proves the seams
113
+ against network-free fake servers (`scripts/phase11-conformance.test.mjs`),
114
+ and the live matrix above stays blocked until the protected environment
115
+ records it.
116
+
117
+ ## Packed-install e2e journeys (plan 012 Task 3)
118
+
119
+ | Journey | Command | Environment |
120
+ |---|---|---|
121
+ | Enterprise: OIDC identity → OPA policy decision → agent run with durable events → batched approval → OpenAPI side effect with idempotency → artifact upload + signed delivery | `npm test` (scripts/e2e-enterprise-journey.test.mjs) | network-free (memory stores, loopback fake servers); PostgreSQL leg when `PRISM_TEST_POSTGRES_URL` is set |
122
+ | Coding: 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 | `npm test` (scripts/e2e-coding-journey.test.mjs) | network-free (fake GitHub + git runner) |
123
+
124
+ Both install the exact packed manifest graph into a fresh consumer (`npm pack`
125
+ tarballs, never workspace paths) and run the journey against only public
126
+ exports. Each fixture ends with a success marker (`ENTERPRISE JOURNEY OK` /
127
+ `CODING JOURNEY OK`) that the test asserts. Runtime is bounded by
128
+ `e2eJourneyFixtureMsCeiling` in `scripts/phase12-freeze-manifest.json` (120 s
129
+ per fixture).
130
+
131
+ ## Protected restart-recovery evidence (plan 012 Task 4)
132
+
133
+ | Leg | Command | Environment |
134
+ |---|---|---|
135
+ | Multi-replica kill/resume: replica A runs a durable agent (PostgreSQL checkpoints + durable events), suspends on a batched tool approval, and is SIGKILLed; replica B resumes with no event gap/duplicate, exactly-once durable tool effects, partial-approval re-suspend with CAS, and ownership rechecks | `npm run test:postgres` (scripts/phase12-restart-recovery.test.mjs) | live PostgreSQL 16 |
136
+ | Tool-effect unknown-outcome window: a dispatched-and-expired claim replays as `ERR_PRISM_TOOL_EFFECT_UNKNOWN` (reconciliation demanded), never a silent double-apply | `npm run test:postgres` (same suite) | live PostgreSQL 16 |
137
+ | Database restart during streaming: terminated LISTEN backend recovers by polling (missed event delivered, no gap) | `npm run test:postgres` (Phase 7 + Phase 12 legs) | live PostgreSQL 16 |
138
+ | Reconnect p95 + append contention p95 recorded against frozen ceilings (`reconnectP95Ms`, `pointOpP95Ms` in `scripts/phase12-freeze-manifest.json`) | `npm run test:postgres`; evidence in `scripts/phase12-restart-recovery.json` | live PostgreSQL 16 |
139
+
140
+ Missing `PRISM_TEST_POSTGRES_URL` is a **named, visible blocked gate**: `npm run
141
+ test:postgres` fails at `scripts/require-postgres-url.mjs`, and running the
142
+ suite directly records a `BLOCKED GATE` failure instead of a passing skip.
143
+ Durable ACP session registries and sandbox process sessions stay host-owned
144
+ by design (Prism provides the durable agent-run lifecycle underneath); the
145
+ coding journey and Phase 9/10 conformance suites cover their in-process
146
+ semantics, and the legs above prove the durable restart classes.
147
+
148
+ ## Security matrix
149
+
150
+ | Control | Command / source | 0.0.16 baseline |
151
+ |---|---|---|
152
+ | Secret scan | `node scripts/scan-secrets.mjs` | 3095 files / 0 findings |
153
+ | License / SBOM | `node scripts/verify-sbom.mjs` | 227 packages / 12 licenses, allow-listed |
154
+ | Dependency audit | `npm audit --audit-level=moderate` | 0 high (2 moderate) at 0.0.16; **0 vulnerabilities at every severity for the 0.1.0 tree** (317 locked deps; MCP SDK 1.30.0 fix baseline) |
155
+ | SAST | GitHub CodeQL workflow | CI-gated |
156
+ | Sandbox / protocol / tenant threat suites | `npm test` (coding-security, MCP, policy, guardrail suites) | green at 0.0.16 |
157
+ | **0.1.0 threat-suites leg** | `npm run security:threat-suites` (Phase 8–11 conformance) + `npm run test:postgres` (Phase 7 tenant leg, blocked gate without URL) | 28/28 network-free at 0.1.0 recording |
158
+ | **Supply-chain negative fixtures** | `scripts/release-gate.test.mjs` | tampered tarball content, unexpected file types/credential material, and suppressed-provenance-in-CI all detected |
159
+ | Signed deterministic publication | `release.mjs publish` on clean tagged tree | operator-gated |
160
+
161
+ ## Remaining for 1.0 (operator / protected environment)
162
+
163
+ Exact prerequisites that must be satisfied before cutting 1.0 (the 0.1.0
164
+ publication itself is the same list minus the 1.0-specific items):
165
+
166
+ 1. **Signed tag + commits:** create and sign `v1.0.0` on a clean tree;
167
+ `release.mjs publish` refuses real publication with `--allow-dirty`
168
+ or `--allow-untagged` (verified: the 0.1.0 dry-run proceeds only with
169
+ both flags, the real run always refuses).
170
+ 2. **npm authentication + OIDC provenance/attestation:** publish with
171
+ `--provenance` and `--access public` from the protected registry identity
172
+ (the 0.1.0 publication is the first exercise of this operator step;
173
+ `publishArgs` derives `--provenance` from `GITHUB_ACTIONS` and the
174
+ release workflow holds `id-token: write` + `attestations: write`).
175
+ 3. **Protected live-canary matrix green:** provider/RAG/memory/workflows live
176
+ journeys pass with real credentials (`live-canaries.yml` — blocked gate,
177
+ never a silent skip).
178
+ 4. **PostgreSQL + keychain protected suites green.**
179
+ 5. **CodeQL SAST green** on the release commit.
180
+ 6. **`scripts/compat-baseline/` committed** (frozen 0.1.x baselines are
181
+ already checked in).
182
+ 7. **Phase 12 demand evidence** (below) recorded for any capability that 1.0
183
+ is expected to anchor.
184
+ 8. **0.1.0 lifecycle gates green** on the release candidate (docs suite,
185
+ audit at moderate, coding-tool durability, layout/eviction defaults) —
186
+ recorded in this page at 0.1.0.
187
+
188
+ ## Phase 12 demand-evidence entry criteria
189
+
190
+ Phase 12 (demand-gated 0.1.x) promotes no capability on comparison-table parity
191
+ alone. Each candidate must present, before it becomes a numbered plan:
192
+
193
+ - **Named user** (a concrete person/team who will use it),
194
+ - **Concrete integration** (the real system it connects to),
195
+ - **Operational owner** (who runs and pages for it),
196
+ - **Measurable acceptance criteria** (scale/cost/latency/storage budgets that
197
+ do not expand default core/install/runtime cost),
198
+ - then the pipeline: demand evidence → primitive review → threat model →
199
+ optional package/service → conformance → release gate.
200
+
201
+ The readiness gates above are the stable API/compat/budget/security floor that
202
+ Phase 12 capabilities must consume and must not regress.
package/docs/a2a.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- `@arnilo/prism-supervisor` implements bounded A2A 1.0 over the JSON-RPC/HTTPS binding. Supported operations: `SendMessage`, `SendStreamingMessage`, `GetTask`, `ListTasks`, `CancelTask`, `SubscribeToTask`, push-notification-config create/get/list/delete, and `GetExtendedAgentCard`. Agent Cards retain explicit ES256 verification. gRPC, HTTP+JSON, discovery registries, automatic JWK/OAuth fetching, and an internal task worker/store are absent.
5
+ `@arnilo/prism-supervisor` implements bounded A2A 1.0 over the JSON-RPC/HTTPS binding. Supported operations: `SendMessage`, `SendStreamingMessage`, `GetTask`, `ListTasks`, `CancelTask`, `SubscribeToTask`, push-notification-config create/get/list/delete, and `GetExtendedAgentCard`. `client.streamMessage()` additionally exposes verified rich task/message events for frontend adapters while legacy `stream()` remains text-compatible. Agent Cards retain explicit ES256 verification. gRPC, HTTP+JSON, discovery registries, automatic JWK/OAuth fetching, and an internal task worker/store are absent.
6
6
 
7
7
  ## When to use it
8
8
 
@@ -39,6 +39,30 @@ const handler = createA2AHandler({
39
39
 
40
40
  Parts, messages, artifacts, histories, metadata, and aggregate responses are untrusted. Rich content remains in A2A task/message/artifact contracts for host mapping; it is never promoted to system instructions or automatically loaded as a Prism resource.
41
41
 
42
+ ## AG-UI server-side exposure (Task 13, 0.0.26)
43
+
44
+ `createAgUiA2AServer()` in `@arnilo/prism-ag-ui` fronts one host-selected **local AG-UI agent** as an A2A 1.0 server, the reverse direction of `createAgUiA2AAdapter()`: remote A2A clients start and stream local runs through the same AG-UI input allow-list and event mapper as the AG-UI SSE path (same projection, redaction, and byte caps). It reuses this package's `createA2AHandler` transport/lifecycle; it creates no second runtime, task store, or worker. Requires the optional `@arnilo/prism-supervisor` peer (imported lazily; plain `@arnilo/prism-ag-ui` imports keep working without it).
45
+
46
+ ```ts
47
+ import { createAgentEventSourceAgUiReplay, createAgUiA2AServer } from "@arnilo/prism-ag-ui";
48
+
49
+ const server = await createAgUiA2AServer({
50
+ card: agentCard, // A2A agent card (streaming: true)
51
+ authorize: (input) => authorizeA2A(input), // A2A auth → { ownership } (also the AG-UI authorization)
52
+ sessionFactory: ({ threadId, authorization, signal, input }) =>
53
+ createAgUiSession(authorization, input), // same shape as createAgUiHandler
54
+ input: { project: projectAgUiInput }, // AG-UI full-input allow-list
55
+ projection, redactor, a2ui, limits, // AG-UI mapper options
56
+ durable: { // optional: GetTask/SubscribeToTask after a run finishes
57
+ source: persistence.events, // durable AgentEventSource
58
+ resolveTask: async ({ id, authorization }) => ({ task, run }), // host-owned task→run correlation
59
+ },
60
+ });
61
+ // host mounts: new Request(url, init) → server(request)
62
+ ```
63
+
64
+ Semantics: `SendMessage` runs the local agent to completion and returns a terminal task with collected text artifacts; `SendStreamingMessage` (client `returnImmediately: true`) streams text/activity/state as bounded A2A artifact updates, then a terminal task. `agent_suspended` closes the stream with `TASK_STATE_INPUT_REQUIRED`; continuation stays host-owned (AG-UI resume). `GetTask`/`ListTasks`/`CancelTask` cover a bounded in-memory registry of tasks started on this instance; with `durable`, `SubscribeToTask`/`GetTask` also resolve host-correlated runs and replay the durable source with cursor event ids (at-least-once; clients dedupe by `eventId`). Text parts become the AG-UI user message; raw/data/url parts stay disabled unless `parts` selects them, and then arrive only in `forwardedProps.a2a` for `input.project`. Task ids default to `task-<uuid>`; hosts may own them via `selectTaskId`. `tasks` may be supplied to replace the built-in lifecycle entirely. A2A remains separately mounted — no route is added to `createPrismHandler()`.
65
+
42
66
  ## Implementation example
43
67
 
44
68
  ```ts
@@ -59,12 +83,15 @@ Streams use ordered SSE frames with `id:` and JSON-RPC `result` containing one `
59
83
  Client APIs:
60
84
 
61
85
  - `send()` / `stream()` preserve text-to-`AgentRunResult` compatibility.
86
+ - `streamMessage(message)` exposes bounded verified `A2AStreamEvent` task/message records without discarding artifact/data parts.
62
87
  - `sendMessage()` returns rich/durable `A2ATask`.
63
88
  - `getTask()`, `listTasks()`, `cancelTask()`, `subscribeToTask()` operate on durable tasks.
64
89
  - `createPushConfig()`, `getPushConfig()`, `listPushConfigs()`, `deletePushConfig()` expose declared push config operations.
65
90
 
66
91
  Every protocol request sends/negotiates `A2A-Version: 1.0`. Client endpoint/card URLs require exact allow-listed HTTPS and `redirect: "error"`. Cards are parsed then optionally verified against host-pinned keys; no key URL is fetched.
67
92
 
93
+ `createA2AAgentEventSource({ source, resolveTask, map })` supplies only the durable `subscribe` seam for a host-owned `A2ATaskLifecycle`. It resolves task→exact Prism run under authorization, consumes `AgentEventSource.subscribe()`, and uses each opaque source cursor as stable A2A `eventId`. With no cursor, the first mapped update must be a full Task, matching A2A streaming rules. It creates no task store or worker. Standard `SubscribeToTask` has no `afterEventId`; Prism retains that bounded field as an explicitly documented reconnect extension.
94
+
68
95
  ## Request/response example
69
96
 
70
97
  ```json
@@ -73,13 +100,14 @@ Every protocol request sends/negotiates `A2A-Version: 1.0`. Client endpoint/card
73
100
 
74
101
  ## Extension and configuration notes
75
102
 
76
- Handler requires `card.capabilities.pushNotifications` to exactly match supplied `push`; mismatch fails construction, preserving signed-card integrity and preventing false capability claims. Streaming remains available for direct text invocation. Push adapter owns exact-owner persistence, signing/auth credentials, and network transport. Host explicitly calls `deliverA2APushEvent()` from its durable update path; helper bounds event, timeout (10s default/60s hard), attempts (1 default/3 hard), and passes stable event ID as idempotency key to host `A2APushDelivery`. It starts no hidden sender and performs no network itself. Config handling validates IDs/count/bytes and requires same explicit URL policy used for URL parts. Returned push configs omit token and authentication credentials.
103
+ Handler requires `card.capabilities.pushNotifications` to exactly match supplied `push`; mismatch fails construction, preserving signed-card integrity and preventing false capability claims. `createAgUiA2AAdapter({ client, select, correlate, projectPart })` in `@arnilo/prism-ag-ui` fronts one host-selected verified client: host selects new/follow task mode, persists exact run/thread/task correlation before output, and may project non-text/tool/A2UI parts. It never discovers agents, opens a local session, or replaces this direct A2A API. Streaming remains available for direct text invocation. Push adapter owns exact-owner persistence, signing/auth credentials, and network transport. Host explicitly calls `deliverA2APushEvent()` from its durable update path; helper bounds event, timeout (10s default/60s hard), attempts (1 default/3 hard), and passes stable event ID as idempotency key to host `A2APushDelivery`. It starts no hidden sender and performs no network itself. Config handling validates IDs/count/bytes and requires same explicit URL policy used for URL parts. Returned push configs omit token and authentication credentials.
77
104
 
78
105
  Defaults/hard caps include: request 64 KiB/1 MiB; response 1/8 MiB; event 64 KiB/1 MiB; stream 10/64 MiB and 10k/100k events; replay 1k/10k events; concurrency 16/256; timeout 120s/30m; IDs 256/4096 B; parts 32/256; part/raw 1/8 MiB; data 256 KiB/4 MiB; artifacts 32/256; history/page 100/1000; cursor 4/16 KiB; push configs 10/100. Hosts may narrow limits.
79
106
 
80
107
  ## Security and performance notes
81
108
 
82
109
  - Authorize every operation; lifecycle/push adapters enforce exact owner again at durable storage boundary. Missing and foreign tasks/configs share `-32001`.
110
+ - Optional `A2AAuthorization.identity` is host-verified; the handler asserts activity/ownership match and forwards identity into `session.run`. Cross-tenant or widened scopes fail closed.
83
111
  - URL policy must reject private, loopback, link-local, rebound, redirected, or otherwise disallowed destinations. Package never fetches file URLs. Host push delivery must repeat equivalent checks for every attempt/redirect and process event IDs idempotently.
84
112
  - Push token/auth credentials are accepted only into host adapter input and removed from protocol reads/responses. Keep them out of task parts, events, telemetry, ledgers, and errors.
85
113
  - Known-secret redaction applies before handler JSON/SSE output. Client redacts mapped text/errors. Raw/data/url content remains explicitly untrusted.
@@ -88,7 +116,10 @@ Defaults/hard caps include: request 64 KiB/1 MiB; response 1/8 MiB; event 64 KiB
88
116
 
89
117
  ## Related APIs
90
118
 
119
+ - [Agent identity](agent-identity.md)
91
120
  - [Supervisor delegation](supervisors.md)
92
121
  - [Agent/session runtime](agent-session-runtime.md)
93
122
  - [Workflows](workflows.md)
94
123
  - [Host security](host-security.md)
124
+ - [Frontend interoperability (AG-UI and ACP)](ag-ui.md): browser/editor protocol adapters over a Prism session; not an A2A card, task lifecycle, or remote-agent transport.
125
+ - [AG-UI adoption evaluation](ag-ui-adoption.md): official AG-UI A2A fronting assessment and shipped explicit adapter.
package/docs/acp.md ADDED
@@ -0,0 +1,126 @@
1
+ # Agent Client Protocol (ACP) coding-host interop
2
+
3
+ ## What it does
4
+
5
+ `@arnilo/prism-ag-ui/acp` (stable ACP **v1**, `@agentclientprotocol/sdk@1.3.0` root exports only) exposes two adapters:
6
+
7
+ - `createPrismAcpAgent(options)` — serves ACP as an **agent**: an editor/AI client connects through the SDK transport and drives host-owned Prism sessions with `session/new`, `session/load`, `session/resume`, `session/prompt`, `session/set_mode`, `session/set_config_option`, `session/list`, `session/delete`, `session/close`, and `session/cancel`. The agent is a thin protocol adapter: every capability, decision, and byte cap is wired from host seams, and there is **no second policy engine** on the agent side.
8
+ - `createAcpEventMapper(options)` — maps a Prism `AgentEvent` stream (or `CoWorkEvent`) to ACP `SessionUpdate`s for hosts that stream through their own transport.
9
+
10
+ The adapter builds on the Phase 8/9 shared machinery: redacted event projection (`AgUiProjection`), the durable pending-decision batch model (`allow_once` / `allow_for_run` / `reject_once` / `reject_for_run`), `AgentRunLifecycle` resume, `CodingLifecycleEvent` emission, and the AG-UI/ACP package caps. It never ships experimental ACP v2 or UNSTABLE fields (`providers`, `nes`, `positionEncoding`, `sessionCapabilities.fork`, `mcpCapabilities.acp/auth`, `elicitation` is consumed client-side only and never advertised).
11
+
12
+ ## When to use it
13
+
14
+ Use `createPrismAcpAgent` when an editor/AI client already speaks ACP and you want it to reach host-owned Prism runs: text streaming, safe tool status, usage, four-outcome approvals, session persistence, modes, config options, and — when the client advertises them — editor-buffer filesystem (`fs/read_text_file`, `fs/write_text_file`) and terminal (`terminal/create` … `terminal/kill`) client methods, plus prompt media (`image`, `audio`, `embeddedContext`) and `elicitation` decisions.
15
+
16
+ Do **not** use it when the host needs a browser/TUI Web endpoint (use [AG-UI](ag-ui.md)), remote agent-to-agent tasks ([A2A](a2a.md)), or a full editor integration — ACP is a protocol adapter, not an editor, a TUI, or a credential provider.
17
+
18
+ ## Inputs / request
19
+
20
+ `createPrismAcpAgent(options: CreatePrismAcpAgentOptions)` — every field is host-supplied:
21
+
22
+ | Option | Shape | Effect |
23
+ |---|---|---|
24
+ | `authorize` | `(input) => AcpAuthorization \| Promise` | **Required.** Ownership/identity gate for every inbound call, scoped by `sessionId`; unknown sessions fail. |
25
+ | `sessionFactory` | `(input) => AcpSessionBinding \| Promise` | **Required.** Builds the Prism `AgentSession` for `session/new`. Input carries `authorization`, `cwd`, `additionalDirectories`, `mcpServers` (policy-checked), `signal`, optional pre-generated `sessionId`, and `coding` (built client fs/terminal adapters when the client advertised them). |
26
+ | `lifecycle` | `AgentRunLifecycle` | **Required.** `status`/`resume`/`resumeStream` for durable `session/load` and `session/resume`. |
27
+ | `sessions?` | `AcpSessionStoreSeams` | `load` (advertises `sessionCapabilities.loadSession`), `list` (list), `delete` (delete), `resume` (resume), `additionalDirectories` (policy narrowing of `additionalDirectories`). `close` is always advertised. |
28
+ | `mcp?` | `AcpMcpSeams` | `transports: ("http" \| "sse")[]` and `select({ servers, signal })` — **required** for any client-supplied MCP server; select must approve before the bridge connects. Advertises `mcpCapabilities.http`/`sse` per transport. |
29
+ | `modes?` | `{ modes: AcpSessionMode[], defaultModeId? }` | `AcpSessionMode { id, name, description?, apply? }`; `apply({ sessionId?, fromModeId?, modeId, signal })` is the host hook run on switch. Advertised in `SessionModeState` on new/load/resume; enables `session/set_mode`. |
30
+ | `configOptions?` | `{ options: AcpConfigOption[], onChange? }` | `boolean`/`select` options with `defaultValue`; enables `session/set_config_option` (requires the client to advertise `session.configOptions.boolean`). |
31
+ | `capabilities?` | `AcpCapabilitiesOptions` | `prompt.media`/`prompt.embedded` policy seams, re-checked **live at prompt time**; presence advertises `promptCapabilities.image`/`audio`/`embeddedContext`. |
32
+ | `coding?` | `AcpCodingSeams` | `filesystem(client, sessionId)` / `processes(client, sessionId)` factories building `AcpClientFilesystem` / `AcpClientTerminals` over client methods; `lifecycle?: CodingLifecycleEmitter` subscribes `CodingLifecycleEvent`s into ACP updates. |
33
+ | `name?` | `string` | `agentInfo.name` (default `"Prism"`). |
34
+
35
+ Client capabilities are read at `initialize` and gate **client-method use**, not advertisement: `fs.readTextFile`/`writeTextFile` gate the fs seam, `terminal` the processes seam, `session.configOptions.boolean` the config path, `elicitation` the elicitation route.
36
+
37
+ ## Outputs / response / events
38
+
39
+ `initialize` returns `{ protocolVersion, agentCapabilities, agentInfo }`; `agentInfo.version` comes from the package manifest. Advertised capability = a host seam is wired (pure function, no hand-maintained matrix): `loadSession`/`sessionCapabilities.*` iff the matching `sessions` seam exists (`close` always), `promptCapabilities.*` iff the matching `capabilities.prompt` seam exists, `mcpCapabilities.*` iff `mcp.select` + the transport are wired. Unadvertised agent methods fail naturally with JSON-RPC `-32601`; unadvertised client methods are never called.
40
+
41
+ In-stream `SessionUpdate`s:
42
+
43
+ | Prism event | ACP update |
44
+ |---|---|
45
+ | Assistant text | `agent_message_chunk` |
46
+ | Tool lifecycle | `tool_call` / `tool_call_update` (title/status/content) |
47
+ | Tool result, projected | `tool_call_update` with `locations` (≤ `acpLocationsPerUpdate`) and/or a `diff` block (≤ `acpDiffBytes`) — only from `AgUiProjection.toolLocations`/`toolDiff` allow-lists, at `finish()` |
48
+ | Provider usage / errors | `usage_update`, `error` |
49
+ | Durable suspension | `session/request_permission` with the four outcomes `allow_once` / `allow_for_run` / `reject_once` / `reject_for_run`; cancel, unknown options, and request failure deny. Sticky decisions expire at run end. |
50
+ | Elicitation suspension (all-elicitation batch + client advertised `elicitation`) | `elicitation/create` (form mode, bounded schema, redacted reason); `accept` → `allow_once` with the typed payload as `RunDecision.elicitation`, `decline`/`cancel` → `reject_once`. Otherwise falls back to the shared four-option permission path. |
51
+ | `file_changed` lifecycle | `tool_call_update` with `locations: [{ path }]` (needs a `toolCallId`; diff only from `fileDiff` allow-list, capped + redacted) |
52
+ | `worktree_changed` / process events | Projection-gated `agent_message_chunk` (deny-by-default: no `lifecycle` projection hook = no update) |
53
+ | `permission_denied` lifecycle | `tool_call_update` status `failed` (never raw args; synthesized id `prism:denied:<approvalId>` when no `toolCallId`) |
54
+ | `configuration_changed` lifecycle | `config_option_update` with the full current set, per streaming session |
55
+ | Session mode/config switch | `current_mode_update` / `config_option_update` |
56
+
57
+ Frozen caps (default / hard, from the Phase 10 freeze manifest): sessions 32/128, additional directories 8/32 (path 4 KiB/16 KiB), MCP servers 8/32 (config 16 KiB/256 KiB, header values 4 KiB/64 KiB), modes 16/64, config options 16/64, list page 20/100, diff bytes 64 KiB/1 MiB, locations per update 32/128, prompt media parts 16/64 and media bytes 64 KiB/1 MiB (shared AG-UI caps), terminal output chunks 51200 B/1 MiB (Phase 9 `process.outputChunkBytes`), stream events/bytes per AG-UI budgets. `session/load`/`session/resume` of a still-registered session rejects with `ERR_PRISM_ACP_INPUT` ("ACP session already exists"); model reconnect as resume of a pre-seeded stored session.
58
+
59
+ Errors surface as `AcpError` with codes `ERR_PRISM_ACP_INPUT` (malformed), `ERR_PRISM_ACP_LIMIT` (caps), `ERR_PRISM_ACP_POLICY` (host denied), `ERR_PRISM_ACP_CAPABILITY` (not advertised), `ERR_PRISM_ACP_MCP` (MCP bridging). Over the wire they become JSON-RPC `-32603` with the message in `data.details` (SDK behavior).
60
+
61
+ ## Request/response example
62
+
63
+ ```json
64
+ // initialize → agentCapabilities (all seams wired)
65
+ {
66
+ "protocolVersion": 1,
67
+ "agentCapabilities": {
68
+ "loadSession": {},
69
+ "sessionCapabilities": { "list": {}, "delete": {}, "additionalDirectories": {}, "resume": {}, "close": {} },
70
+ "promptCapabilities": { "image": true, "audio": true, "embeddedContext": true },
71
+ "mcpCapabilities": { "http": true, "sse": true }
72
+ },
73
+ "agentInfo": { "name": "Prism", "version": "0.0.27" }
74
+ }
75
+
76
+ // session/new response (modes + configOptions wired)
77
+ { "sessionId": "acp-9f1c…", "modes": { "currentModeId": "edit", "availableModes": [{ "id": "edit", "name": "Edit" }] },
78
+ "configOptions": [{ "type": "boolean", "id": "verbose", "name": "Verbose", "defaultValue": false, "currentValue": false }] }
79
+ ```
80
+
81
+ ## Implementation example
82
+
83
+ See [`examples/acp-coding-host.ts`](../examples/acp-coding-host.ts) (runs in the demo gate). The host owns all state and policy:
84
+
85
+ ```ts
86
+ import { createPrismAcpAgent } from "@arnilo/prism-ag-ui/acp";
87
+
88
+ const agent = createPrismAcpAgent({
89
+ authorize: ({ sessionId }) => (sessionId ? hostSessions.has(sessionId) : true)
90
+ ? { ownership: { userId: "host-user" } }
91
+ : false,
92
+ sessionFactory: (input) => ({ session: hostSessionFor(input) }), // Prism AgentSession
93
+ lifecycle: { status, resume, resumeStream }, // durable
94
+ sessions: { load, list, delete, resume, additionalDirectories }, // capability seams
95
+ mcp: { transports: ["http", "sse"], select: ({ servers }) => approve(servers) },
96
+ modes: { modes: [{ id: "edit", name: "Edit" }, { id: "review", name: "Review", apply: narrow }], defaultModeId: "edit" },
97
+ configOptions: { options: [{ type: "boolean", id: "verbose", name: "Verbose", defaultValue: false }] },
98
+ capabilities: { prompt: { media: async () => true, embedded: async () => false } },
99
+ coding: { lifecycle, filesystem: clientFsAdapter, processes: clientTerminalAdapter },
100
+ });
101
+ // serve over the host's ACP transport: agent.connect(stream)
102
+ ```
103
+
104
+ ## Extension and configuration notes
105
+
106
+ - **Seam = capability.** Wiring `sessions.load` advertises `loadSession`; removing it withdraws the method. There is no separate capability flag to keep in sync — the freeze manifest's advertise-when matrix is enforced by construction and asserted by `scripts/phase10-conformance.test.mjs`.
107
+ - **Client fs/terminal are adapters, not a second implementation.** `AcpClientFilesystem` / `AcpClientTerminals` wrap the client's `fs/*` and `terminal/*` methods behind the Phase 9 `ProcessSession`-flavored interfaces; the agent pre-generates the session id so terminal requests can carry it. Host repo operations remain default when the client fs is absent.
108
+ - **Modes and config options are a pure host overlay.** The agent stores only a thin per-session registry; `apply`/`onChange` hooks narrow the host's own behavior. Mode switches can narrow or host-authorized widen — never a parallel policy evaluator, never a client-enabled tool.
109
+ - **Lifecycle wiring.** Pass your `createCodingLifecycleEmitter()` as `coding.lifecycle`; `file_changed` etc. then flow to streaming sessions. `configuration_changed` broadcasts `config_option_update` (agent-message fallback if the SDK rejects the kind).
110
+ - **Stream budgets.** Every lifecycle update counts against the same per-run stream event/byte budget as prompt updates; overflowing closes the update, never the run.
111
+
112
+ ## Security and performance notes
113
+
114
+ - **Untrusted client input.** Client-supplied paths, `additionalDirectories`, MCP server configs, terminal env/args, and media are validated at the boundary: count/byte caps, ownership-scoped sessions, path policy via the `sessions.additionalDirectories` seam, MCP servers only through host `select` (never auto-connected), UNSTABLE `acp` transport always rejected.
115
+ - **Deny-closed by default.** Unknown mode ids, unadvertised methods, unprojected lifecycle events, oversize diffs/locations/media, thrown projection hooks, and failed elicitation all fail closed. Raw tool arguments/results are never sent unless a projection allow-list says otherwise.
116
+ - **No secrets.** Updates carry no raw file bodies, terminal output is capped by the Phase 9 chunk budget, and the shared redactor is applied before anything leaves the host. `permission_denied` never includes raw args.
117
+ - **Performance.** The adapter is O(1) per update with no unbounded buffering; p95 targets (fs round trip 250 ms, mode switch 250 ms, terminal chunk ack 1000 ms, prompt first update 2000 ms, prompt end 30 s) are recorded by `scripts/benchmark-0.0.27.mjs` and gated in `scripts/budgets.json` `phase10`.
118
+
119
+ ## Related APIs
120
+
121
+ - [AG-UI](ag-ui.md): sibling frontend protocol; shared projection/redaction/caps and the same pending-decision model. This page is the full ACP reference.
122
+ - [Coding agent tools](coding-agent-tools.md): the `CodingLifecycleEvent` source mapped here; `@arnilo/prism-coding-agent` `process.outputChunkBytes` caps terminal chunks.
123
+ - [Agent events](agent-events.md): the durable `AgentEventSource`/replay story behind `session/load` and `session/resume`.
124
+ - [Host security guide](host-security.md): fail-closed checklist rows for ACP boundaries (authorize, ownership, redaction, untrusted MCP).
125
+ - [Migration guide](migration.md): 0.0.26 → 0.0.27 advertise/surface changes for hosts that parsed the old `initialize`.
126
+ - [AG-UI adoption evaluation](ag-ui-adoption.md): the underlying input/event/capability matrix.
@@ -0,0 +1,77 @@
1
+ # AG-UI adoption evaluation
2
+
3
+ ## What it does
4
+
5
+ This page records Prism's compatibility review against official AG-UI `@ag-ui/core` **0.0.57** and the official repository at commit [`a40b5c0`](https://github.com/ag-ui-protocol/ag-ui/commit/a40b5c0824564eb2f9ab9edf2be43f355f42a3b8). It separates shipped transport/replay support from remaining work needed to claim full AG-UI support, including AG-UI fronting MCP and A2A agents.
6
+
7
+ Official material reviewed:
8
+
9
+ - [Events](https://docs.ag-ui.com/concepts/events), [messages](https://docs.ag-ui.com/concepts/messages), [tools](https://docs.ag-ui.com/concepts/tools), [state](https://docs.ag-ui.com/concepts/state), [reasoning](https://docs.ag-ui.com/concepts/reasoning), [interrupts](https://docs.ag-ui.com/concepts/interrupts), [capabilities](https://docs.ag-ui.com/concepts/capabilities), [serialization](https://docs.ag-ui.com/concepts/serialization), [server quickstart](https://docs.ag-ui.com/quickstart/server), and [protocol architecture](https://docs.ag-ui.com/concepts/architecture).
10
+ - Official [MCP/A2A/AG-UI relationship](https://docs.ag-ui.com/agentic-protocols), [integrations](https://docs.ag-ui.com/integrations), [`@ag-ui/mcp-middleware`](https://github.com/ag-ui-protocol/ag-ui/tree/main/middlewares/mcp-middleware), [`@ag-ui/mcp-apps-middleware`](https://github.com/ag-ui-protocol/ag-ui/tree/main/middlewares/mcp-apps-middleware), [`@ag-ui/a2ui-middleware`](https://github.com/ag-ui-protocol/ag-ui/tree/main/middlewares/a2ui-middleware) (Prism ships an in-package opt-in painter with frozen caps; no runtime dependency), [`@ag-ui/a2a`](https://github.com/ag-ui-protocol/ag-ui/tree/main/integrations/a2a/typescript), and [`@ag-ui/a2a-middleware`](https://github.com/ag-ui-protocol/ag-ui/tree/main/middlewares/a2a-middleware).
11
+ - A2A [current specification](https://a2a-protocol.org/latest/specification/) and [streaming rules](https://a2a-protocol.org/latest/topics/streaming-and-async/).
12
+ - MCP Apps [SEP-1865](https://modelcontextprotocol.io/seps/1865-mcp-apps-interactive-user-interfaces-for-mcp) and the [`io.modelcontextprotocol/ui` draft specification](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx).
13
+
14
+ ## When to use it
15
+
16
+ Use this matrix when selecting Prism for an AG-UI client or planning protocol work. Tasks 3A and 3B complete full AG-UI 0.0.57 request/event compatibility plus explicit hardened MCP, MCP Apps, and remote A2A fronting. These are opt-in adapters over existing Prism clients, not an alternate runtime or discovery path.
17
+
18
+ ## Inputs / request
19
+
20
+ Official `RunAgentInput` fields—lineage, all message roles/history, state, tools, context, props, media, and resume—are schema/bound checked then have no authority until `input.project` returns host-selected messages. Client tools remain client handoffs; state/props/media never grant identity, ownership, or server tools. Resume is exact `${runId}:${version}` CAS; edited arguments deny.
21
+
22
+ ## Outputs / response / events
23
+
24
+ Prism emits current standard lifecycle, step, text, tool, state, messages, activity, reasoning, raw, and custom families when its mapper or an explicit projector can prove them. Deprecated `THINKING_*` and convenience chunk output are intentionally absent. SSE is baseline; capabilities truthfully narrow to configured replay/projectors/lifecycle, and source cursors remain bounded `prismCursor` metadata for reconnect.
25
+
26
+ ## Request/response example
27
+
28
+ ```json
29
+ {
30
+ "type": "TEXT_MESSAGE_CONTENT",
31
+ "messageId": "message-1",
32
+ "delta": "hello",
33
+ "prismEventId": "event-42",
34
+ "prismCursor": "opaque-owner-run-bound-cursor"
35
+ }
36
+ ```
37
+
38
+ ## Implementation example
39
+
40
+ ```ts
41
+ import { createAgentEventSourceAgUiReplay, createAgUiHandler } from "@arnilo/prism-ag-ui";
42
+
43
+ const replay = createAgentEventSourceAgUiReplay(persistence.events, {
44
+ resolveRun: hostResolveProtocolRun,
45
+ ownership: (authorization) => authorization.ownership,
46
+ });
47
+
48
+ const handle = createAgUiHandler({ authorize, sessionFactory, lifecycle, resolveRun, replay });
49
+ ```
50
+
51
+ ## Extension and configuration notes
52
+
53
+ ### A2A adoption
54
+
55
+ A2A stays separately mounted. `createA2AAgentEventSource()` maps durable runs to task events; `afterEventId` remains Prism-only.
56
+
57
+ `createAgUiA2AAdapter({ client, select, correlate, projectPart })` fronts one verified host-selected client: task text/status becomes AG-UI text/activity, correlation persists before output, and non-text/tool/A2UI needs a schema-validated projector. It uses streaming when declared; fallback accepts only a terminal task. Client origin/card/auth/bounds/abort checks remain active.
58
+
59
+ ### MCP adoption through AG-UI
60
+
61
+ Prism adapts its hardened MCP bridge; no official middleware or second runtime. `connectMcpTools({ mcpApps: true })` requires `io.modelcontextprotocol/ui` acknowledgement, retains nested UI metadata over deprecated flat metadata, hides app-only tools, and bounds linked `ui://` HTML through `bridge.apps`. `createAgUiMcpAdapter()` selects model-visible tools for normal core dispatch; `createAgUiMcpAppHandler()` reauthorizes one-bridge initialize/ping/logging/tool/resource calls with approval and visibility; sandbox helper returns fixed iframe/CSP constraints. No generic proxy, cross-server call, raw HTML rendering, or automatic mutation retry.
62
+
63
+ ## Security and performance notes
64
+
65
+ - Every replay/reconnect reauthorizes, then source access uses exact host ownership and host-resolved internal run IDs. Cursor content never selects ownership.
66
+ - Durable streams are at-least-once. Clients deduplicate `prismEventId`; source cursors resume strictly after a durable record.
67
+ - Client tools, state, context, forwarded properties, media URLs/data, remote A2A parts, MCP metadata, HTML, iframe messages, and reasoning blobs are untrusted. Projectors must use existing Prism media URL/SSRF/MIME policy before any resolution.
68
+ - `input.project` and all output projectors are allow-lists; all generic JSON has byte/depth/property/array caps and prototype-pollution keys fail before host callbacks. Tool handoffs are client-only and cannot widen identity, ownership, permissions, or active server tools.
69
+ - MCP Apps requires sandbox-origin separation, restrictive CSP, declared-domain ceilings, audited JSON-RPC, app/tool visibility checks, and user approval for UI-initiated mutations. The shipped proxy does not retry those mutations; Task 4 adds generic durable effect recovery.
70
+
71
+ ## Related APIs
72
+
73
+ - [Frontend interoperability](ag-ui.md): shipped Prism AG-UI/ACP API.
74
+ - [Agent events](agent-events.md): source events and durable delivery.
75
+ - [Web-standard server](server.md): SSE `Last-Event-ID` reconnect route.
76
+ - [A2A interoperability](a2a.md): separately mounted A2A lifecycle and durable source adapter.
77
+ - [MCP bridge/server](mcp-tools.md): hardened MCP transport and capability boundary reused by future AG-UI MCP support.