@arnilo/prism 0.0.5 → 0.0.6

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 (57) hide show
  1. package/CHANGELOG.md +28 -1
  2. package/dist/agent-loops.d.ts +1 -0
  3. package/dist/agent-loops.js +26 -16
  4. package/dist/agents.js +2 -3
  5. package/dist/contracts.d.ts +2 -0
  6. package/dist/ids.d.ts +2 -0
  7. package/dist/ids.js +6 -0
  8. package/dist/index.d.ts +5 -1
  9. package/dist/index.js +3 -1
  10. package/dist/session-stores.js +2 -3
  11. package/dist/testing/persistence-schema.d.ts +45 -7
  12. package/dist/testing/persistence-schema.js +138 -24
  13. package/dist/thinking.d.ts +42 -0
  14. package/dist/thinking.js +92 -0
  15. package/dist/tools.js +2 -3
  16. package/dist/use-case-model.d.ts +63 -0
  17. package/dist/use-case-model.js +52 -0
  18. package/docs/a2a.md +4 -2
  19. package/docs/agent-events.md +10 -15
  20. package/docs/agent-loops.md +11 -8
  21. package/docs/coding-agent-tools.md +33 -12
  22. package/docs/coding-security.md +2 -2
  23. package/docs/compaction-llm.md +17 -7
  24. package/docs/compaction-observational-memory.md +28 -4
  25. package/docs/credential-storage.md +58 -9
  26. package/docs/credentials-and-redaction.md +1 -1
  27. package/docs/database-persistence.md +8 -3
  28. package/docs/host-security.md +10 -6
  29. package/docs/index.md +23 -20
  30. package/docs/mcp-tools.md +26 -10
  31. package/docs/migration.md +146 -2
  32. package/docs/node-filesystem-config.md +1 -0
  33. package/docs/node-jsonl-session-store.md +5 -4
  34. package/docs/postgres-persistence.md +3 -3
  35. package/docs/provider-caching.md +16 -4
  36. package/docs/provider-conformance.md +39 -1
  37. package/docs/provider-packages.md +60 -3
  38. package/docs/providers/ai-sdk.md +36 -0
  39. package/docs/providers/kimi.md +124 -61
  40. package/docs/providers/neuralwatt.md +19 -13
  41. package/docs/providers/openai.md +56 -13
  42. package/docs/providers/opencode-go.md +118 -30
  43. package/docs/providers/openrouter.md +105 -35
  44. package/docs/providers/zai.md +94 -45
  45. package/docs/release-and-install.md +47 -49
  46. package/docs/review-coverage-2026-07-17-provider-validation.md +192 -0
  47. package/docs/runs-and-usage.md +1 -1
  48. package/docs/sqlite-persistence.md +2 -2
  49. package/docs/structured-output.md +1 -1
  50. package/docs/thinking-and-reasoning.md +98 -0
  51. package/docs/tool-execution-primitives.md +3 -3
  52. package/docs/tools.md +15 -0
  53. package/docs/use-case-model-selection.md +109 -0
  54. package/docs/workflow-orchestration-primitives.md +1 -0
  55. package/docs/workflows.md +17 -10
  56. package/docs/working-and-semantic-memory.md +1 -0
  57. package/package.json +2 -2
@@ -27,6 +27,20 @@ Memory records use `SessionEntry.kind: "custom"` with `entry.data.type` markers:
27
27
 
28
28
  Ids are known, source-backed 12-character lowercase hex strings matching `^[a-f0-9]{12}$`.
29
29
 
30
+ Worker limits are finite positive safe integers:
31
+
32
+ | Runtime option | Default | Hard cap | Scope |
33
+ | --- | ---: | ---: | --- |
34
+ | `maxWorkerTurns` | 16 | 64 | Provider turns per observer/reflector/dropper run; overrides settings `agentMaxTurns` |
35
+ | `maxWorkerToolCallsPerTurn` | 32 | 256 | Calls retained from one provider response |
36
+ | `maxWorkerToolCalls` | 128 | 1,024 | Calls across all turns in one worker run |
37
+ | `maxWorkerArgumentBytes` | 64 KiB | 1 MiB | Each raw and redacted JSON argument object |
38
+ | `maxWorkerResultBytes` | 64 KiB | 1 MiB | Full tool result and replayed value/error payload |
39
+ | `maxWorkerMessageBytes` | 1 MiB | 8 MiB | System/prompt plus assistant-call/tool-result transcript |
40
+ | `maxWorkerErrorBytes` | 1 KiB | 8 KiB | Provider/tool/runtime error text after exact known-secret redaction |
41
+
42
+ Direct `runObserver()` / `runReflector()` / `runDropper()` calls retain required `maxTurns` and accept the corresponding shorter worker fields (`maxToolCalls`, `maxResultBytes`, etc.). Named default/hard constants and `resolveMemoryWorkerLimits()` are exported.
43
+
30
44
  ## Outputs / response / events
31
45
 
32
46
  Key exports:
@@ -78,7 +92,12 @@ const memory = createObservationalMemoryRuntime({
78
92
  session,
79
93
  appendEntry: (entry) => store.append(entry),
80
94
  workerProvider,
81
- workerModel: { provider: "mock", model: "memory" },
95
+ sessionModel: agent.config.model, // fallback when workerModel unset
96
+ // workerModel: { provider: "mock", model: "memory" }, // optional override
97
+ maxWorkerTurns: 8,
98
+ maxWorkerToolCalls: 64,
99
+ maxWorkerResultBytes: 64 * 1024,
100
+ overrides: { thinkingLevel: "low" },
82
101
  });
83
102
  await memory.flush();
84
103
  await session.compact({ strategy: createObservationalMemoryCompactionStrategy({ keepRecentEntries: 8 }) });
@@ -92,9 +111,9 @@ await kernel.load([createObservationalMemoryExtension({ recallTool: { getEntries
92
111
 
93
112
  ## Extension and configuration notes
94
113
 
95
- Settings are read from the `observational-memory` key only when a host calls `resolveObservationalMemorySettings()` or `runtime.flush()`. Defaults are `observeAfterTokens: 10000`, `reflectAfterTokens: 20000`, `compactAfterTokens: 81000`, `observationsPoolMaxTokens: 20000`, `observationsPoolTargetTokens: 10000`, `agentMaxTurns: 16`, `passive: false`, and `debugLog: false`.
114
+ Settings are read from the `observational-memory` key only when a host calls `resolveObservationalMemorySettings()` or `runtime.flush()`. Defaults are `observeAfterTokens: 10000`, `reflectAfterTokens: 20000`, `compactAfterTokens: 81000`, `observationsPoolMaxTokens: 20000`, `observationsPoolTargetTokens: 10000`, `agentMaxTurns: 16`, `passive: false`, and `debugLog: false`. `agentMaxTurns` now rejects non-integer/non-finite/out-of-range input (hard 64) instead of flooring/falling back. Runtime `maxWorkerTurns` takes precedence.
96
115
 
97
- The runtime requires host-supplied `session`, an `appendEntry` callback bound to that session's owning store/branch, `workerProvider`, and `workerModel`. It no longer accepts a separate `store` option because mismatched session/store pairs can append memory entries outside the active branch. After each memory append, the runtime checks the appended entry is visible at the session leaf and fails closed/restores the previous checkout if the callback points elsewhere. Optional credential resolution is explicit; missing requested credentials skip worker execution.
116
+ The runtime requires host-supplied `session`, an `appendEntry` callback bound to that session's owning store/branch, and `workerProvider`. Model selection uses [use-case model selection](use-case-model-selection.md): pass optional `workerModel` (or settings `workerModel`) to override, and `sessionModel: agent.config.model` so workers fall back to the session model when no worker model is configured. `requireExplicitModel: true` restores the historical `missing_model` skip when no explicit worker model is set. It no longer accepts a separate `store` option because mismatched session/store pairs can append memory entries outside the active branch. After each memory append, the runtime checks the appended entry is visible at the session leaf and fails closed/restores the previous checkout if the callback points elsewhere. Optional credential resolution is explicit; missing requested credentials skip worker execution. Default credential requests use the **resolved** model's provider id.
98
117
 
99
118
  `createObservationalMemoryCompactionStrategy()` keeps recent message entries like the default compaction strategy, renders existing observations/reflections as the summary, and returns a standard Prism compaction entry. Its `data` includes `throughEntryId`, `keepEntryIds`, `strategy`, `trigger`, and `memory: { type: "om.folded", version: 1, fullFold, observations, reflections, droppedObservationIds }`. When active observations exceed `observationsPoolMaxTokens`, it performs a full fold into `data.memory`.
100
119
 
@@ -110,13 +129,18 @@ The runtime requires host-supplied `session`, an `appendEntry` callback bound to
110
129
  - Recall tool and commands only see current-branch entries supplied by the host callback.
111
130
  - Invalid or missing ids fail closed; invalid recall tool ids skip entry lookup.
112
131
  - Utilities and fast compaction are O(n) over supplied entries and use no provider, network, filesystem, timer, worker, credential, or settings access.
113
- - Workers serialize only supplied branch entries, enforce `agentMaxTurns`, and run one consolidation pipeline at a time per runtime. Worker transcripts replay assistant `tool_call` messages before matching role `tool` `tool_result` messages so provider requests stay valid for call/result-pairing providers.
132
+ - Workers serialize only supplied branch entries within `maxWorkerMessageBytes`, enforce finite turns/calls/arguments/results/messages/errors, and run one consolidation pipeline at a time per runtime. Source serialization and reflection/drop prompts fail before joining beyond the transcript cap.
133
+ - Every provider call must name a registered worker tool. Unknown calls, call overflow, oversized/deep/cyclic/non-JSON arguments/results, and transcript overflow fail deterministically; no excess call enters the assistant transcript or executes.
134
+ - Raw arguments are measured before tool execution. Full results are measured before redaction/replay; the bounded redacted value/error is then measured again because replacement text can grow. Replayed call arguments, tool values/errors, runtime `lastError`, and debug error data contain exact known-secret redaction. Host tools may already have caused side effects before returning an invalid oversized result; keep worker tools small/idempotent.
135
+ - Worker transcripts replay assistant `tool_call` messages before matching role `tool` `tool_result` messages so provider requests stay valid for call/result-pairing providers. Calls produced on the final allowed turn execute and persist, but no additional provider turn starts.
114
136
  - Compaction preserves raw history; Prism appends one standard compaction entry and rebuilds provider context from its summary plus kept recent messages.
115
137
  - Pass known secrets to render/recall/runtime/tool/command helpers to redact exact values from prompts, records, structured results, and text output.
116
138
  - Live tests are opt-in with `PRISM_LIVE_OBSERVATIONAL_MEMORY_TESTS=1`.
117
139
 
118
140
  ## Related APIs
119
141
 
142
+ - [Use-case model selection](use-case-model-selection.md): session vs worker model binding and `resolveUseCaseModel`.
143
+ - [Thinking and reasoning](thinking-and-reasoning.md): `thinkingLevel` → provider `compat`.
120
144
  - [Compaction and retry policies](compaction-and-retry.md): replaceable compaction strategy boundary.
121
145
  - [LLM compaction package](compaction-llm.md): existing optional compaction-package pattern.
122
146
  - [Session stores and branching](session-stores-and-branching.md): branch entries that observational memory reads and appends to.
@@ -44,8 +44,11 @@ import {
44
44
  | --- | --- | --- |
45
45
  | `path` | `string` | Vault file path. Parent directories are created as needed. |
46
46
  | `getPassphrase` | `() => string \| Promise<string>` | Host-owned passphrase retrieval. Never logged by the adapter. |
47
- | `scrypt` | `{ N?, r?, p?, keyLength? }` | Optional KDF tuning. Defaults: `N=32768`, `r=8`, `p=1`, `keyLength=32`. Minimum `N=16384`. |
48
- | `fileMode` | `number` | Unix mode for newly written files. Defaults to `0o600`. |
47
+ | `scrypt` | `{ N?, r?, p?, keyLength? }` | Optional KDF tuning. Defaults: `N=32768`, `r=8`, `p=1`, `keyLength=32`; limits are listed below. |
48
+ | `fileMode` | `number` | Unix mode for files. Defaults to `0o600`; group/other permissions are rejected. |
49
+ | `limits.maxFileBytes` | `number` | Encrypted envelope file: 4 MiB default, 16 MiB hard cap. |
50
+ | `limits.maxVaultBytes` | `number` | Decrypted vault/plaintext: 3 MiB default, 12 MiB hard cap. |
51
+ | `limits.maxScryptMemoryBytes` | `number` | `128*N*r` memory estimate: 256 MiB default and hard cap. |
49
52
 
50
53
  ### System keychain
51
54
 
@@ -53,7 +56,8 @@ import {
53
56
  | --- | --- | --- |
54
57
  | `service` | `string` | Keychain service name (application identifier). |
55
58
  | `namespace` | `string` | Optional prefix separating environments or tenants within one service. |
56
- | `timeoutMs` | `number` | Operation timeout. Defaults to `5000`. |
59
+ | `timeoutMs` | `number` | Operation timeout. Defaults to 5,000 ms; hard cap 60,000 ms. |
60
+ | `maxPayloadBytes` | `number` | Decrypted keychain payload: 3 MiB default, 12 MiB hard cap. |
57
61
 
58
62
  ## Outputs / response / events
59
63
 
@@ -71,6 +75,8 @@ Encrypted file stores also expose:
71
75
  - `reload()` — re-read and decrypt from disk
72
76
  - `flush()` — force rewrite of the encrypted envelope
73
77
 
78
+ `encryptBytes()` and `decryptBytes()` are Promise-based because they use asynchronous `node:crypto.scrypt`.
79
+
74
80
  Errors are explicit and fail closed:
75
81
 
76
82
  | Error | Code | When |
@@ -123,6 +129,7 @@ import {
123
129
  const store = await openEncryptedCredentialStore({
124
130
  path: "./credentials.vault",
125
131
  getPassphrase: () => process.env.MY_APP_CREDENTIAL_PASSPHRASE!,
132
+ limits: { maxFileBytes: 4 * 1024 * 1024, maxVaultBytes: 3 * 1024 * 1024 },
126
133
  });
127
134
 
128
135
  const resolver = createExplicitCredentialResolver([
@@ -151,6 +158,47 @@ await rotateEncryptedCredentialStorePassphrase({
151
158
  });
152
159
  ```
153
160
 
161
+ ### Desktop keychain and explicit overrides
162
+
163
+ ```ts
164
+ import {
165
+ createEnvCredentialResolver,
166
+ createExplicitCredentialResolver,
167
+ createMemoryCredentialStore,
168
+ } from "@arnilo/prism";
169
+ import {
170
+ createKeychainCredentialStore,
171
+ createStoredCredentialResolver,
172
+ } from "@arnilo/prism-credentials-node";
173
+ import { createOpenAIProviderPackage } from "@arnilo/prism-provider-openai";
174
+
175
+ const keychain = createKeychainCredentialStore({
176
+ service: "com.example.my-app",
177
+ namespace: "production",
178
+ });
179
+ await keychain.set({
180
+ name: "apiKey",
181
+ provider: "openai",
182
+ credential: { type: "api_key", value: userSuppliedKey },
183
+ });
184
+
185
+ const runtimeOverrides = createMemoryCredentialStore();
186
+ // Set only for this user/agent instance; it wins over stored and env values.
187
+ runtimeOverrides.set({
188
+ name: "apiKey",
189
+ provider: "openai",
190
+ credential: { type: "api_key", value: temporaryOverride },
191
+ });
192
+
193
+ const apiKey = createExplicitCredentialResolver([
194
+ { name: "runtime", resolver: runtimeOverrides },
195
+ { name: "keychain", resolver: createStoredCredentialResolver(keychain) },
196
+ { name: "env", resolver: createEnvCredentialResolver(process.env, { openai: "OPENAI_API_KEY" }) },
197
+ ]);
198
+
199
+ const providers = createOpenAIProviderPackage({ apiKey });
200
+ ```
201
+
154
202
  ## Extension and configuration notes
155
203
 
156
204
  - Passphrase retrieval, TLS, and OS permission prompts remain host-owned.
@@ -161,12 +209,13 @@ await rotateEncryptedCredentialStorePassphrase({
161
209
 
162
210
  ## Security and performance notes
163
211
 
164
- - Authenticated encryption uses Node built-in `aes-256-gcm` and `scrypt`; no extra crypto dependencies for the file backend.
165
- - Atomic writes use temp file + rename; partial writes cannot replace a valid vault.
166
- - Derived keys are zeroed after encrypt/decrypt operations where practical.
167
- - Default scrypt `N=32768` targets interactive CLI unlock; raise `N` for higher security at the cost of unlock latency.
168
- - Keychain operations honor `timeoutMs` and surface `CredentialStoreTimeoutError` instead of blocking indefinitely.
169
- - Never log passphrases, derived keys, or decrypted credential payloads. Error messages do not echo secret values.
212
+ - Authenticated encryption uses Node built-in `aes-256-gcm` and asynchronous `scrypt`; no extra crypto dependency is added for the file backend.
213
+ - Envelope parsing rejects unknown shape, non-canonical/oversized base64, wrong salt/IV/tag size, unsupported algorithms/version, and excessive KDF work before scrypt. `N` must be a power of two from 16,384–262,144; `r≤32`, `p≤16`, `keyLength=32`, `N*r*p≤2,097,152`, and `128*N*r` must fit `maxScryptMemoryBytes`.
214
+ - Existing Unix vaults are checked before content read and must deny group/other access. Atomic writes create a random exclusive temp file at the requested restrictive mode, then rename; Windows skips Unix mode checks.
215
+ - Derived keys and package-owned plaintext buffers are zeroed after use. JavaScript passphrase strings and returned credentials remain host-owned.
216
+ - Keychain operations use `@napi-rs/keyring`'s abort-aware `AsyncEntry`, so native work runs outside the JavaScript event loop. A main-loop timer aborts and rejects at `timeoutMs`; native cancellation remains OS/backend-dependent and may briefly retain one libuv worker after rejection.
217
+ - Keychain payloads are bytes rather than password strings and are zeroed after parse/write. Unknown native errors are mapped to sanitized typed errors; no native message or secret value is echoed.
218
+ - Never log passphrases, derived keys, or decrypted credential payloads.
170
219
  - Live keychain tests are opt-in (`PRISM_TEST_KEYCHAIN=1`); default `npm test` stays offline.
171
220
 
172
221
  ## Related APIs
@@ -107,7 +107,7 @@ console.log(error.message);
107
107
  - Redaction only removes exact known secret values passed to the helper. It is not a general-purpose secret detector.
108
108
  - Do not pass empty strings as secrets; they are ignored.
109
109
  - `redactSecrets()` recursively walks arrays and object entries, so avoid using it on huge objects unless needed.
110
- - Cycle and non-JSON value handling: `redactSecrets()` is cycle-safe via a `WeakSet` visited-set. Self-referential or mutually referenced objects render `"[Circular]"` at the back-reference instead of throwing. `Date` and `RegExp` values are passed through unchanged; `ArrayBuffer` and typed arrays are passed through unchanged; `Map` is normalized to a plain object and `Set` to an array so the output stays JSON-compatible. `errorToErrorInfo()` tolerates a cyclic `error.cause` (rendered via `String()`).
110
+ - Cycle and non-JSON value handling: `redactSecrets()` is cycle-safe via an active-path `WeakSet`. Ancestor cycles render `"[Circular]"` at the back-reference instead of throwing; shared diamond references on separate branches stay structured (they are not collapsed to `"[Circular]"`). String object keys and `Map` keys are redacted like values, with deterministic `__2`/`__3`/… suffixes on collisions. `Date` and `RegExp` values are passed through unchanged; `ArrayBuffer` and typed arrays are passed through unchanged; `Map` is normalized to a plain object and `Set` to an array so the output stays JSON-compatible. `errorToErrorInfo()` tolerates a cyclic `error.cause` (rendered via `String()`). Symbols and non-enumerable properties remain outside JSON-shaped redaction.
111
111
  - Use placeholders in tests and docs. Never commit real tokens.
112
112
  - Live provider/worker tests are gated behind explicit environment variables and skipped by default: `PRISM_LIVE_PROVIDER_TESTS`, `PRISM_LIVE_COMPACTION_TESTS`, `PRISM_LIVE_OBSERVATIONAL_MEMORY_TESTS`. Default `npm test` is network-free; do not add ungated network calls to default tests.
113
113
  - Credentials are not eagerly resolved by the core runtime, serialized into provider requests/events/stores, or passed to loops/compaction.
@@ -128,7 +128,7 @@ A branch leaf (`leaf_entry_id`) is the current entry id for that branch. Rebuild
128
128
  | --- | --- |
129
129
  | `prism_session_entries` | `id` PK, `session_id` FK, `parent_id`, `run_id`, `timestamp`, `kind`, `schema_version`, `message` JSONB, `event` JSONB, `model` JSONB, `previous_model` JSONB, `label`, `summary`, `data` JSONB, `metadata` JSONB |
130
130
 
131
- Maps directly to `SessionEntry`. `kind` is one of the `SessionEntryKind` values. `schema_version` defaults to `1`. `parent_id` may be null for the root entry of a session.
131
+ Maps directly to `SessionEntry`. `kind` is one of the `SessionEntryKind` values. `schema_version` is nullable in schema version 3 for existing entry compatibility; hosts writing new rows should persist the entry's current schema version. `parent_id` may be null for the root entry of a session.
132
132
 
133
133
  `SessionAppendOptions.idempotencyKey` is not part of `SessionEntry`; store it in an adapter-owned side table when you need durable retry detection:
134
134
 
@@ -214,7 +214,8 @@ await runRunLedgerConformance(() => createLedger(testDatabase), { exerciseReopen
214
214
  | Primitive | Purpose |
215
215
  | --- | --- |
216
216
  | `PersistenceSchemaModel` | Versioned table/column/index model covering sessions, entries, parent chain, idempotency side table, runs, events, tool calls, usage, tenant columns, and `prism_migrations` |
217
- | `createPersistenceMigrationContract()` | Strictly increasing migration steps, `prism_migrations` recording, advisory-lock guidance, and least-privilege migration/runtime role guidance |
217
+ | `createPersistenceMigrationContract()` | Strictly increasing checked-in migration steps with deterministic SHA-256 checksums, `prism_migrations` recording, advisory-lock guidance, and least-privilege migration/runtime role guidance |
218
+ | `assertAppliedPersistenceMigrations()` / `assertPersistenceSchemaShape()` | Testable fail-closed history and normalized SQLite/PostgreSQL catalog checks for every required table, column/type/null/default, PK/unique/FK, and named index. |
218
219
  | `getPersistencePaginationCursors()` | Indexed `(session_id, timestamp, id)`, `(run_id, sequence)`, `(run_id, recorded_at, id)` cursor shapes that avoid offset scans |
219
220
  | `assertPersistenceQueryPaginationConforms()` | Generic cursor pagination fixture for `queryEntries` |
220
221
  | `assertTenantScopedQueryIsolation()` | Tenant-filtered reads must not leak rows or primary-id collisions across tenants |
@@ -345,7 +346,11 @@ Retention jobs should not run inside the agent/session runtime. They are a host
345
346
 
346
347
  ## Migrations
347
348
 
348
- Hosts own schema migrations. Prism publishes only the TypeScript contracts; no DDL is generated or executed by the core library. Recommended migration practices:
349
+ Hosts own schema migrations. Prism publishes only the TypeScript contracts; no DDL is generated or executed by the core library. First-party SQLite/PostgreSQL adapters automatically verify their checked-in schema-v3 history and catalog at open, before runtime writes. Their catalog reads are bounded metadata queries/PRAGMAs, not table-data scans.
350
+
351
+ Each new adapter-owned migration row records the contract SHA-256 checksum. A complete known v0.0.5 history whose checksum values are all `NULL` is a one-time compatibility case: under the SQLite transaction or PostgreSQL advisory transaction lock, the adapter verifies the full current shape, backfills all checksums, and continues. Unknown/duplicate/out-of-order/name-version/checksum mismatch, mixed/partial legacy values, or any missing/renamed/wrong-type/null/default/key/index artifact fails closed. Restore or apply a reviewed host migration; never edit checksums to silence drift.
352
+
353
+ Recommended migration practices:
349
354
 
350
355
  - Use a sequential or timestamped migration naming convention.
351
356
  - Store applied migrations in `prism_migrations` with `name`, `version`, `applied_at`, `applied_by`, and `checksum`.
@@ -124,10 +124,14 @@ Wire those values where they matter: provider adapters receive the resolved cred
124
124
  - Prism does not sandbox host tools, extensions, provider adapters, credential resolvers, or custom middleware. Use OS/container/process isolation when code is untrusted.
125
125
  - Redaction is exact known-secret replacement only. It is not arbitrary secret detection, entropy scanning, or DLP.
126
126
  - Known secrets must be passed into redactors before data is emitted or persisted. Redact again in host adapters if they transform records after Prism redaction.
127
- - Tool `parameters` metadata is not validated by default. Add a `ToolValidator`, use `createToolParameterValidator()` with a schema adapter, or install `@arnilo/prism-tool-validator-json-schema` before side effects.
128
- - MCP client tools from `@arnilo/prism-mcp` are untrusted remote servers. Configure stdio commands and HTTP URLs explicitly; bound output with `maxResultBytes`; register prefixed tools only after trust review. MCP server direction exposes only passed tools/commands, requires per-call `authorize`, and retains `PermissionPolicy`/`ToolValidator` gates for tools. Its web handler needs host `resolveAuthInfo`, TLS, rate limiting, and exact host/origin policy. See [MCP client/server exposure](mcp-tools.md).
129
- - `@arnilo/prism-server` exposes no agent/workflow by default and requires `authorize()` for every matched operation. Derive non-empty ownership from validated host identity, never request JSON. Configure exact host/origin allow-lists where needed, wire redaction before execution, retain tool/workflow policy checks, and adapt the Web handler behind host TLS/rate limits. Disconnect abort is default; persistent reconnect/status belongs to durable workflow checkpoints, not an invented in-memory agent result cache.
130
- - Coding tools from `@arnilo/prism-coding-agent` accept an optional `ExecutionPolicy` checked inside each tool before side effects; shared policy propagation includes `createReadOnlyTools()`. Use `@arnilo/prism-coding-security` for path roots, command rules, and identity-scoped approval caching. Caching defaults to none; missing run/session identity never falls back to a global cache. Prism does not provide OS sandboxing unless the host supplies a sandbox adapter.
127
+ - Tool `parameters` metadata is not validated by default. Add a `ToolValidator`, use `createToolParameterValidator()` with a schema adapter, or install `@arnilo/prism-tool-validator-json-schema` before side effects. Its untrusted-schema adapter rejects non-local refs, forbidden keys/cycles/non-finite values and bounds bytes/depth/properties/keywords/refs plus its LRU cache before Ajv compilation; do not raise caps above documented hard limits.
128
+ - Treat embeddings as untrusted numeric input. `@arnilo/prism-memory` rejects empty, non-number, NaN, and infinite vectors before in-memory similarity or pgvector parameters; custom `Embedder`/`VectorStore` implementations must retain the same boundary.
129
+ - Prism-generated session/run/tool/workflow/evaluation IDs use Node cryptographic UUIDs. Keep host-provided IDs authorization-scoped and validate them as untrusted identifiers; do not substitute timestamps or `Math.random()` for durable/security-relevant IDs.
130
+ - MCP client tools from `@arnilo/prism-mcp` are untrusted remote servers. Stdio remains an explicit host executable. Streamable HTTP requires exact HTTPS origins, rejects credentials/fragments/redirects/private or mixed DNS, pins a validated address on every SDK request/reconnect, and bounds each response; plaintext is explicit loopback-only development mode. Discovery has finite page/tool/cursor/metadata/schema totals and commits atomically. Every result branch shares byte/depth/property bounds before core dispatch; supply a known-secret `SecretRedactor`, `PermissionPolicy`, and `ToolValidator` there. MCP server direction exposes only passed tools/commands, requires per-call `authorize`, and retains core gates. Its web handler still needs host `resolveAuthInfo`, TLS, edge rate limiting, and exact host/origin policy. See [MCP client/server exposure](mcp-tools.md).
131
+ - `@arnilo/prism-server` exposes no agent/workflow by default and requires `authorize()` for every matched operation. Derive complete tenant/account/user ownership from validated host identity, never request JSON. Workflow active identity and cancellation compare exact ownership; a tenant-only scope intentionally cannot cancel a checkpoint/run carrying account or user identity. Pass the current explicitly revised workflow definition so recursive hash mismatch fails before abort or durable mutation. Configure exact host/origin allow-lists where needed, wire redaction before execution, retain tool/workflow policy checks, and adapt the Web handler behind host TLS/rate limits. Disconnect abort is default; persistent reconnect/status belongs to durable workflow checkpoints, not an invented in-memory agent result cache.
132
+ - Coding tools from `@arnilo/prism-coding-agent` accept an optional `ExecutionPolicy` checked inside each tool before side effects; shared policy propagation includes `createReadOnlyTools()`. They enforce finite text-scan/image/edit/write/shell limits, a 600-second default shell wall time, and a 64 MiB default total-output ceiling. Successful truncated shell output leaves a host-owned exclusive `0600` temp file; delete `metadata.fullOutputPath` after use. Error/abort/timeout/overflow removes unpublished spills. Custom read/edit/shell backends must honor supplied caps/signals. Use `@arnilo/prism-coding-security` for path roots, command rules, and identity-scoped approval caching. Limits are not containment: Prism provides no OS sandbox unless the host supplies one.
133
+ - `@arnilo/prism-credentials-node` rejects oversized/malformed envelopes and excessive scrypt work before KDF allocation, uses async scrypt, and requires restrictive existing/new Unix vault modes. Keep vault ownership and parent-directory access host-controlled; review before `chmod 600`, never auto-weaken a file policy. Keychain calls use abort-aware native async work with finite timeout/payload caps and sanitized errors. OS prompts, service availability, and whether a native backend promptly honors cancellation remain host/platform boundaries; no plaintext fallback is attempted.
134
+ - LLM compaction always sends finite summary `maxTokens`, retains bounded deltas/events, and bounds/redacts provider/factory/policy error detail. Observational-memory workers cap turns, calls, arguments, results, transcript, and surfaced errors; unknown tools fail before execution, while invalid results can only be rejected after a host tool returns and may therefore follow side effects. Pass all known provider/credential/tool secrets into compaction/runtime options; exact replacement is not secret discovery.
131
135
  - Default remote-media loading resolves every DNS answer, rejects the hostname if any address is non-public, and pins one validated address through the request. Explicit `allowedHostnames` can trust private destinations. A host-supplied `fetch` owns DNS/rebinding/proxy/redirect safety; a custom `requestUrl` must connect to its supplied validated address.
132
136
  - Permission checks happen before tool validation and before `tool.execute()`. Middleware cannot grant permission by renaming a tool.
133
137
  - Session stores and ledgers receive redacted values when a redactor is active, but durable storage remains host-owned. Enforce tenant/account/user ownership and retention in the database layer.
@@ -143,7 +147,7 @@ Wire those values where they matter: provider adapters receive the resolved cred
143
147
  - Secret scan: source, tests, docs, workflow files, package metadata, built tests, packed-install canary, and tarball deny-list checks found no private-key block or common live-token prefix. Runtime redaction fixtures cover requests, events, ledgers, stores, checkpoints, provider/OAuth errors, and credential ciphertext.
144
148
  - Threat suites pass for parameterized SQL/tenant isolation, HTTP URL/SSRF rejection, realpath/symlink containment, shell-metacharacter approval, schema prototype-pollution/remote-reference bounds, OAuth polling/abort/redaction, credential tamper/wrong-key/KDF floors, MCP result bounds/timeouts, and coding approval/path policy.
145
149
 
146
- PostgreSQL TLS/network policy, MCP endpoint allow-listing, provider base URLs, OS keychain availability, process sandboxing, workflow tenant identity, and ANSI/control-sequence sanitization in any host terminal renderer remain host boundaries. Prism 0.0.4 ships JSON-line RPC, not an interactive TUI; hosts must render untrusted model/tool text safely. Credential-gated PostgreSQL/provider/keychain tests are separate operator/CI gates, not silently replaced by mocks.
150
+ PostgreSQL TLS/network policy, MCP endpoint trust/credentials and egress policy beyond package origin/DNS pinning, provider base URLs, OS keychain availability, process sandboxing, workflow tenant identity, and ANSI/control-sequence sanitization in any host terminal renderer remain host boundaries. Prism 0.0.4 ships JSON-line RPC, not an interactive TUI; hosts must render untrusted model/tool text safely. Credential-gated PostgreSQL/provider/keychain tests are separate operator/CI gates, not silently replaced by mocks.
147
151
 
148
152
  ## Supervisor and A2A boundaries
149
153
 
@@ -152,7 +156,7 @@ PostgreSQL TLS/network policy, MCP endpoint allow-listing, provider base URLs, O
152
156
  - Keep depth, active children, input, turn/tool/token, timeout, and queue ceilings finite; propagate abort through nested calls.
153
157
  - Expose A2A only behind per-request authentication/authorization, TLS, edge rate limits, and replay policy. Public card discovery grants no invoke access.
154
158
  - Remote A2A endpoints/card URLs require exact HTTPS origin allow-lists and redirect rejection. Pin ES256 card keys/expiry; never auto-fetch untrusted `jku`.
155
- - Treat cards, task status, errors, artifacts, and SSE frames as untrusted bounded input and redact before logs/hooks/events.
159
+ - Treat cards, task status, errors, artifacts, and SSE frames as untrusted bounded input and redact before logs/hooks/events. Client streaming uses one fatal UTF-8 decoder, bounded incremental LF/CRLF/multiline SSE parsing, and rejects partial/post-terminal frames; malformed remote bytes never become replacement characters in JSON.
156
160
 
157
161
  ## Related APIs
158
162
 
package/docs/index.md CHANGED
@@ -8,7 +8,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
8
8
  ## Agent/session runtime
9
9
  - [Agent/session runtime](agent-session-runtime.md): create agents and sessions, get direct `AgentRunResult` values from `run`/`prompt`, use integrated `stream()`, and subscribe to normalized events. Covers tool-call loop transcript shape and prior-reasoning preservation across turns.
10
10
  - [Agent definitions](agent-definitions.md): resolve declarative `AgentDefinition` values via `resolveAgentDefinition`, and turn app-config `<configRoot>/agents/<name>/AGENT.md` bundles into runnable agents via `discoverAgentBundles` / `resolveAgentBundle` (explicit tool/skill activation by name, fail-closed omitted capabilities, migration-only `activateAllCapabilities`, strict duplicate scope checks, configurable prompt layers, no auto-discovery).
11
- - [Agent loops](agent-loops.md): replaceable per-run control loops — `singleShotLoop` default and `generate-validate-revise` with host-supplied `validator`/`parser`/`repairer` callbacks.
11
+ - [Agent loops](agent-loops.md): replaceable per-run control loops — `singleShotLoop` default and opt-in bounded artifact-loop tool rounds with host-supplied `validator`/`parser`/`repairer` callbacks.
12
12
  - [Agent events](agent-events.md): the `AgentEvent` stream — agent/turn/message (including live `tool_call_delta` fragments), provider turn timing, tool execution, queue/subscriber overflow, compaction/retry, artifact validation/refinement, and error variants, redacted via `redactAgentEvent`.
13
13
  - [Observability](observability.md): metadata-only provider/tool and run-feedback/evaluation projection, terminal span cleanup, low-cardinality metrics, and optional `@arnilo/prism-observability-opentelemetry` adapter.
14
14
  - [Evaluations](evaluations.md): optional deterministic scorers/datasets/experiments plus ID-only linkage from evaluation records to immutable owned run feedback.
@@ -18,15 +18,15 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
18
18
 
19
19
  ## Compaction/session memory
20
20
  - [Compaction and retry policies](compaction-and-retry.md): summarize branch history and retry transient provider failures with host-replaceable policies.
21
- - [LLM compaction package](compaction-llm.md): optional provider-backed compaction strategy package with max-output budgets mapped through `model.parameters.maxTokens` to provider wire fields.
22
- - [Observational memory compaction package](compaction-observational-memory.md): optional source-backed memory, owned runtime append callback, provider-valid worker transcripts, fast compaction, recall tool, and status/view command package.
23
- - [Working and semantic memory](working-and-semantic-memory.md): optional `@arnilo/prism-memory` working-memory store, semantic recall, Embedder/VectorStore contracts, in-memory adapters, and PostgreSQL/pgvector path.
21
+ - [LLM compaction package](compaction-llm.md): optional provider-backed strategy with finite summary/reserve/error caps, bounded redacted streaming retention, and mandatory finite post-policy `model.parameters.maxTokens`.
22
+ - [Observational memory compaction package](compaction-observational-memory.md): optional source-backed memory with owned append callback, finite turn/call/argument/result/transcript/error worker limits, redacted provider-valid transcripts, fast compaction, recall, and status/view commands; worker model falls back to host-supplied `sessionModel`.
23
+ - [Working and semantic memory](working-and-semantic-memory.md): optional `@arnilo/prism-memory` working-memory store, semantic recall, finite Embedder/VectorStore contracts, in-memory adapters, and PostgreSQL/pgvector path.
24
24
  - [Session stores](session-stores.md): `SessionStore` contract, `SessionAppendOptions`, `SessionAppendConflictError`, branch handles, `readBranchPath`, and dev-vs-production branch reads — start here for session persistence.
25
25
  - [Session stores and branching](session-stores-and-branching.md): detailed branch semantics and helper reference (kept for compatibility; links back to the canonical atomic append / branch-handle sections).
26
- - [Database persistence](database-persistence.md): production persistence contracts, shared schema/migration primitives (`@arnilo/prism/testing/persistence-schema`), conditional append transaction pattern, idempotency indexes, `readBranchPath`, reference relational schema, retention, migrations, and NoSQL mapping.
27
- - [SQLite persistence](sqlite-persistence.md): optional adapter with session/run storage, generic checkpoints/leases, and migration-003 owned run feedback over `better-sqlite3`.
28
- - [PostgreSQL persistence](postgres-persistence.md): optional pooled session/run/checkpoint/lease/feedback adapter over `pg`, with advisory-lock migrations and opt-in live conformance.
29
- - [Migration guide](migration.md): 0.0.3 compatibility and 0.0.5 adoption — first-party/custom database persistence plus explicit fail-closed tool/skill activation.
26
+ - [Database persistence](database-persistence.md): production persistence contracts, shared checksummed migration/full-shape catalog primitives (`@arnilo/prism/testing/persistence-schema`), conditional append, indexes, `readBranchPath`, reference relational schema, retention, and NoSQL mapping.
27
+ - [SQLite persistence](sqlite-persistence.md): optional `better-sqlite3` adapter with session/run storage, checkpoints/leases, feedback, and transactionally verified/backfilled migration-v3 metadata.
28
+ - [PostgreSQL persistence](postgres-persistence.md): optional pooled `pg` adapter with session/run/checkpoint/lease/feedback storage, advisory-locked checksummed/full-shape migrations, and opt-in live conformance.
29
+ - [Migration guide](migration.md): 0.0.3 compatibility and 0.0.6 adoption — workflow revisions, finite trust-boundary limits, first-party/custom database persistence, and explicit fail-closed tool/skill activation.
30
30
  - [Node JSONL session store](node-jsonl-session-store.md): development-only JSONL file adapter for single-process Node hosts; no cross-process safety.
31
31
  - [Persistence, credentials, and multimodality primitives](persistence-credentials-multimodality-primitives.md): Plan 056 inventory — session/run-ledger/persistence contracts, credential/OAuth seams, content/resource/model capabilities, package dependency matrix, conformance matrix, and threat model for production adapters.
32
32
 
@@ -34,11 +34,13 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
34
34
  - [Provider primitives](provider-primitives.md): shared bounded transport and OpenAI serialization helpers — migrated across first-party providers; native structured-output and observability contracts.
35
35
  - [Provider layer](provider-layer.md): register and resolve host-owned providers/models, choose replace-or-error duplicate policy, create provider events, stream/reconstruct tool-call deltas, use generic provider request options, and test with the mock provider; deprecated provider-level timeout/retry hints point to runtime abort/retry.
36
36
  - [Model registry](model-registry.md): register and resolve `ModelConfig` records with capabilities, limits, cost, cache support metadata, compat data, and duplicate policy.
37
- - [Provider caching](provider-caching.md): use `PromptCacheHints`, `PromptCacheBreakpoint`, `ModelCacheCapabilities`, cache-aware stable-prefix guidance, and shared cache diagnostics helpers; includes a per-provider explicit/implicit cache matrix for OpenAI, OpenRouter, OpenCode Go, Z.AI, Kimi, and NeuralWatt; cache hints are best-effort and cache keys are never secrets.
37
+ - [Provider caching](provider-caching.md): use `PromptCacheHints`, `PromptCacheBreakpoint`, `ModelCacheCapabilities`, cache-aware stable-prefix guidance, and shared cache diagnostics helpers; includes a per-provider explicit/implicit cache matrix for OpenAI, OpenRouter, OpenCode Go, Z.AI, Kimi, NeuralWatt, and the host-owned AI SDK adapter; cache hints are best-effort and cache keys are never secrets.
38
+ - [Thinking and reasoning](thinking-and-reasoning.md): portable `ThinkingLevel` helpers (`applyThinkingLevel` / `thinkingCompatFor`) map per-turn effort into provider `compat` fields; model defaults stay on `ModelConfig.compat`; no second options tree.
39
+ - [Use-case model selection](use-case-model-selection.md): bind `{ model?, provider?, thinkingLevel? }` for observational memory, LLM compaction, and other non-session LLM jobs with explicit session-model fallback via `resolveUseCaseModel`.
38
40
  - [Provider request policies](provider-request-policies.md): chain `ProviderRequestPolicy` hooks, use `createSessionCachePolicy`, and merge legacy/structured cache options safely.
39
- - [Provider packages](provider-packages.md): define explicit provider packages, model metadata, auth descriptors, request/cache policies, and provider-owned header precedence without package discovery or provider-specific core behavior; includes a first-party cache behavior summary.
40
- - Phase 12 package workspaces: [`@arnilo/prism-provider-openai`](providers/openai.md), [`@arnilo/prism-provider-opencode-go`](providers/opencode-go.md), [`@arnilo/prism-provider-openrouter`](providers/openrouter.md), [`@arnilo/prism-provider-zai`](providers/zai.md), [`@arnilo/prism-provider-kimi`](providers/kimi.md), and [`@arnilo/prism-provider-neuralwatt`](providers/neuralwatt.md) with implicit vLLM prefix caching, reasoning controls (`reasoning_effort`/`thinking_token_budget`/`enable_thinking`/`preserve_thinking`/`clear_thinking`), reasoning preservation, OpenAI-style tool-call loop, quota, telemetry, and retry classification helpers.
41
- - Optional AI SDK adapter: [`@arnilo/prism-provider-ai-sdk`](providers/ai-sdk.md) maps host-owned `LanguageModelV4` models onto Prism `AIProvider` streams (specification v4; available directly or through provider/all umbrellas).
41
+ - [Provider packages](provider-packages.md): define explicit provider packages, model metadata, auth descriptors, request/cache policies, and provider-owned header precedence without package discovery or provider-specific core behavior; includes a first-party cache behavior summary and the **caller-gated on-demand model discovery** contract (`list*Models`, setup zero-fetch).
42
+ - Phase 12 package workspaces: [`@arnilo/prism-provider-openai`](providers/openai.md), [`@arnilo/prism-provider-opencode-go`](providers/opencode-go.md) (official Go open models, dual-route Anthropic/OpenAI, caller-gated `listOpenCodeGoModels`, `reasoning_content`/thinking preserve), [`@arnilo/prism-provider-openrouter`](providers/openrouter.md) (app-controlled catalog, caller-gated `listOpenRouterModels`, `reasoning` merge/preserve, `cache_control` + sticky `session_id`), [`@arnilo/prism-provider-zai`](providers/zai.md) (official `thinking`/`reasoning_effort`/`tool_stream`, implicit cache, caller-gated `listZaiModels`), [`@arnilo/prism-provider-kimi`](providers/kimi.md), and [`@arnilo/prism-provider-neuralwatt`](providers/neuralwatt.md) with implicit vLLM prefix caching, reasoning controls (`reasoning_effort`/`thinking_token_budget`/`enable_thinking`/`preserve_thinking`/`clear_thinking`), reasoning preservation, OpenAI-style tool-call loop, quota, telemetry, and retry classification helpers.
43
+ - Optional AI SDK adapter: [`@arnilo/prism-provider-ai-sdk`](providers/ai-sdk.md) maps host-owned `LanguageModelV4` models onto Prism `AIProvider` streams (specification v4; no Prism catalog; maps `finish.usage` cache read/write tokens; reasoning is host-model-owned).
42
44
  - [OpenAI-compatible provider](providers/openai-compatible.md): optional provider subpath using native or injected `fetch` for Chat Completions streaming.
43
45
 
44
46
  ## Input, prompt, and context assembly
@@ -51,11 +53,11 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
51
53
  - [Retrieval-augmented generation](rag.md): optional bounded text/Markdown chunking, Phase 7 vector indexing/retrieval, stable citations, and explicit inert context injection.
52
54
 
53
55
  ## Tools
54
- - [Tools](tools.md): register host-owned active tools with replace-or-error duplicate policy, apply exact allow/deny filtering, and dispatch tool calls.
55
- - [Tool execution primitives](tool-execution-primitives.md): JSON Schema validation, exclusive-aware bounded parallel dispatch, MCP bridge mapping, coding execution policy, and image-read bounds.
56
+ - [Tools](tools.md): register host-owned active tools with replace-or-error duplicate policy, apply exact allow/deny filtering, dispatch normal or opt-in bounded artifact-loop calls, and optionally bound untrusted JSON Schema compilation.
57
+ - [Tool execution primitives](tool-execution-primitives.md): finite JSON Schema LRU validation, exclusive-aware bounded parallel dispatch, MCP bridge mapping, coding execution policy, and image-read bounds.
56
58
  - [Tool validator JSON Schema package](../packages/tool-validator-json-schema/README.md): optional `@arnilo/prism-tool-validator-json-schema` adapter for `tool.parameters`.
57
- - [MCP client bridge and server exposure](mcp-tools.md): optional `@arnilo/prism-mcp` package mapping remote tools into Prism and explicitly selected Prism tools/commands onto SDK `McpServer`.
58
- - [Coding agent tools](coding-agent-tools.md): optional first-party package `@arnilo/prism-coding-agent` providing `shell`, `read`, `write`, and `edit` tools (ported from pi) as `ToolDefinition`s a host registers; pluggable operation backends, per-path mutation serialization, optional `ExecutionPolicy`, bounded image reads (`maxImageBytes`, `transformImage`), and read-only/coding aggregators. Host shell/filesystem access — gate with permission/trust policies and `@arnilo/prism-coding-security` approval.
59
+ - [MCP client bridge and server exposure](mcp-tools.md): optional bounded atomic tool discovery/results, exact-origin DNS-pinned HTTPS/loopback-only HTTP client transport, and explicitly authorized Prism tools/commands on SDK `McpServer`.
60
+ - [Coding agent tools](coding-agent-tools.md): optional `shell`, `read`, `write`, and `edit` definitions with streamed text pages, bounded image/edit reads and write/edit payloads, finite shell wall/total-output limits, secure host-owned spill cleanup, pluggable bounded operation contracts, per-path mutation serialization, and optional `ExecutionPolicy`. Limits do not sandbox host access—gate with permission/trust policy and `@arnilo/prism-coding-security`.
59
61
  - [Coding execution approval and sandboxing](coding-security.md): path/command approval, identity-scoped caching, shell-turn exclusivity, and abort-aware streaming sandbox adapters for coding tools.
60
62
 
61
63
  ## Extensions/plugins
@@ -75,19 +77,19 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
75
77
 
76
78
  ## Multi-agent and interoperability
77
79
  - [Supervisor delegation](supervisors.md): optional explicit child allow-list, derived memory scopes, narrowing-only permissions, lifecycle hooks, nested delegation, cancellation, and finite budgets.
78
- - [A2A interoperability](a2a.md): optional A2A 1.0 cards, ES256 signatures, authorized JSON-RPC/SSE handler, and exact-origin remote client.
80
+ - [A2A interoperability](a2a.md): optional A2A 1.0 cards, ES256 signatures, authorized JSON-RPC/SSE handler, and exact-origin client with fatal streaming UTF-8 plus bounded LF/CRLF/multiline SSE parsing.
79
81
 
80
82
  ## CLI/RPC
81
83
  - [CLI/RPC](cli-rpc.md): Run print/json modes and LF-delimited RPC over the public AgentSession runtime, including branch-handle results, fixed `forkSession`, and `checkout`. `prism init` scaffolds a tiny TypeScript project with one selected provider and an offline mock test.
82
- - [Workflows](workflows.md): optional `@arnilo/prism-workflows` typed bounded DAG orchestration — durable human suspend/resume, schedules/background execution, nested workflows, bounded validated state, immutable-lineage replay, multi-process coordination, events, and optional RPC/Web bindings. Interactive TUI (C-012) deferred.
84
+ - [Workflows](workflows.md): optional `@arnilo/prism-workflows` typed bounded DAG orchestration — explicit recursive definition revisions, exact-owner cancellation/active identity, finite hard limits, durable human suspend/resume, schedules/background execution, nested workflows, replay, coordination, events, and optional RPC/Web bindings. Interactive TUI (C-012) deferred.
83
85
  - [Workflow orchestration primitives](workflow-orchestration-primitives.md): architecture inventory — workflow adapters consume core `CheckpointStore`, `LeaseStore`, and bounded `EventMultiplexer`; run control and optional RPC commands stay package-local.
84
86
  - [Workflow/TUI scope](workflow-tui-primitives.md): records why 0.0.5 ships workflow APIs/RPC control but no interactive terminal UI.
85
87
 
86
88
  ## Security and credentials
87
- - [Host security guide](host-security.md): fail-closed checklist for credentials, settings, redaction, trust roots, remote media, permission/approval policies, persistence, extension loading, and tool validation.
89
+ - [Host security guide](host-security.md): fail-closed checklist for bounded encrypted vault/KDF/keychain, JSON Schema/vector/cryptographic-ID, MCP discovery/result/transport operations, settings, redaction, trust roots, remote media, exact workflow ownership/revision checks, finite coding I/O and spill ownership, permission/approval policies, persistence, extension loading, and tool validation.
88
90
  - [Security/auth/trust](settings-auth-trust-security.md): settings providers, credential helpers, trust/permission policies, redaction controls, host-owned settings/credentials wiring outside `AgentConfig`, and security-boundary hardening summary.
89
91
  - [Credentials and redaction](credentials-and-redaction.md): compose explicit credential resolver order, use caller-supplied env objects/OAuth refresh helpers, resolve credentials only at the provider edge, and redact known secret values.
90
- - [Credential storage](credential-storage.md): optional `@arnilo/prism-credentials-node` encrypted-file and system-keychain adapters for durable host-owned credentials.
92
+ - [Credential storage](credential-storage.md): optional `@arnilo/prism-credentials-node` adapter with strict bounded AES-GCM envelopes, async finite scrypt, restrictive Unix files, and abort-aware bounded system-keychain calls.
91
93
 
92
94
  ## Testing and examples
93
95
  - Provider test doubles: `createMockProvider()` and provider event helpers are documented on the canonical Provider layer page above.
@@ -101,6 +103,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
101
103
 
102
104
  ## Release and install
103
105
  - [Release and install](release-and-install.md): 30-package graph and profiles, install/tarball rules, deterministic resumable provenance publication, and offline test budget.
106
+ - [Review coverage (2026-07-17 provider validation)](review-coverage-2026-07-17-provider-validation.md): Plan 067 evidence freeze — P0–P2 re-verification owners, seven first-party provider packages mapped to official-doc URLs, Pi secondary refs, cache/thinking/discovery surfaces, credential canaries, and use-case model-binding inventory.
104
107
  - [Review coverage (2026-07-15)](review-coverage-2026-07-15.md): frozen 0.0.5 finding/feature ownership, existing-primitive inventory, package decisions, threat boundaries, exclusions, and measured Phase 0 baseline.
105
108
  - [Review coverage (2026-07-14)](review-coverage-2026-07-14.md): traceability matrix linking review findings and bug-report fixes to plan tasks, tests, and documentation for release 0.0.4.
106
109
 
package/docs/mcp-tools.md CHANGED
@@ -98,7 +98,7 @@ for (const tool of bridge.tools) registry.register(tool);
98
98
  | `tools/call` content blocks | `ToolResult.content` (`text`, `image`; resource/audio/link → descriptive `text`) |
99
99
  | Tool `name` | Prefixed `mcp:<serverId>:<name>` (override with `namePrefix`) |
100
100
  | `isError` results | `ToolResult.error` with summarized text |
101
- | `structuredContent` | `ToolResult.value` / metadata |
101
+ | `structuredContent` | `ToolResult.value` (MCP attribution/byte count remains in metadata) |
102
102
 
103
103
  Duplicate prefixed names throw `McpToolNameCollisionError` at refresh time.
104
104
 
@@ -109,10 +109,17 @@ Duplicate prefixed names throw `McpToolNameCollisionError` at refresh time.
109
109
  | `serverId` | required | Stable identifier used in default name prefix |
110
110
  | `transport` | required | `stdio` or `streamable-http` config |
111
111
  | `namePrefix` | `mcp:<serverId>:` | Registry namespace for remote tools |
112
- | `listCacheTtlMs` | `30000` | Skip re-listing until TTL expires (invalidated on list-changed) |
113
- | `callTimeoutMs` | `60000` | Per-call MCP request timeout |
114
- | `maxResultBytes` | `10000000` | Bound mapped result content |
115
- | `signal` | none | Abort connect and trigger close on abort |
112
+ | `listCacheTtlMs` | 30 s (24 h hard) | Skip re-listing until TTL expires (invalidated on list-changed) |
113
+ | `callTimeoutMs` | 60 s (30 min hard) | Connect, list-page, and tool-call SDK request timeout/abort |
114
+ | `maxListPages` / `maxTools` | 20 / 500 (hard 100 / 5,000) | Stop pagination before another request/append |
115
+ | `maxCursorBytes` | 4 KiB (16 KiB hard) | Reject long or repeated cursors |
116
+ | `maxToolNameBytes` | 256 B (1 KiB hard) | Bound each remote name before mapping |
117
+ | `maxToolDescriptionBytes` | 16 KiB (64 KiB hard) | Bound each retained description |
118
+ | `maxToolSchemaBytes` | 256 KiB (1 MiB hard) | Combined input/output schemas per tool |
119
+ | `maxTotalToolSchemaBytes` | 4 MiB (16 MiB hard) | Aggregate schemas per refresh |
120
+ | `maxResultBytes` | 10,000,000 B (16 MiB hard) | Aggregate remote result before `ToolResult` |
121
+ | `maxJsonDepth` / `maxJsonProperties` | 64 / 10,000 (hard 128 / 100,000) | Bound schema and result JSON walks |
122
+ | `signal` | none | Abort connect/list and trigger close on connect abort |
116
123
 
117
124
  ### Stdio transport
118
125
 
@@ -135,12 +142,18 @@ The host explicitly chooses the executable, arguments, environment, and working
135
142
  {
136
143
  type: "streamable-http",
137
144
  url: "https://mcp.example.com/mcp",
145
+ allowedOrigins: ["https://mcp.example.com"],
146
+ maxResponseBytes?: number, // 16 MiB default, 64 MiB hard
147
+ allowLoopbackHttp?: boolean, // false; development loopback only
138
148
  requestInit?: RequestInit,
139
149
  sessionId?: string,
150
+ resolveHostname?: MediaHostnameResolver,
140
151
  }
141
152
  ```
142
153
 
143
- Only `http:` and `https:` URLs are accepted. Authentication (Bearer tokens, cookies) is supplied through `requestInit.headers` by the host.
154
+ HTTPS and at least one exact origin are required. The endpoint and every SDK session/reconnect request must match both the configured endpoint origin and `allowedOrigins`; origins cannot contain paths, credentials, fragments, or wildcards. Each request resolves at most 32 addresses, rejects the whole answer on any private/malformed address, pins one validated address through Node's HTTP(S) `lookup` seam, rejects redirects, and streams through the response cap. This covers initialization POSTs, SSE GET/reconnect, tool calls, and session DELETE. Authorization headers therefore never cross an origin or redirect.
155
+
156
+ Plaintext is accepted only when `allowLoopbackHttp: true`, the URL hostname is loopback/`localhost`, and every DNS answer is loopback. This is a development escape hatch, not private-network MCP access. `resolveHostname` is a test/host DNS seam; returned addresses still receive all checks and pinning. Authentication headers/cookies remain explicit host input through `requestInit.headers`.
144
157
 
145
158
  ### MCP server options
146
159
 
@@ -160,16 +173,19 @@ Web handler defaults: 1 MiB request (8 MiB hard), 2 MiB response (16 MiB hard),
160
173
  | Risk | Mitigation |
161
174
  | --- | --- |
162
175
  | Untrusted subprocess (stdio) | Explicit `command` / `args` / `env` / `cwd`; review before deploy |
163
- | SSRF / open redirects (HTTP) | Host URL allow-lists, network policy, no implicit discovery |
176
+ | SSRF / DNS rebinding / redirects (HTTP) | Exact HTTPS origins; credentials/fragments/redirects denied; every DNS answer public; one address pinned per request; explicit loopback-only HTTP escape hatch |
177
+ | Hostile discovery / schema compilation | Raw SDK `tools/list` requests avoid SDK Ajv output-schema compilation; finite pages/tools/cursors/metadata/schema totals; failed refresh leaves previous tools unchanged |
164
178
  | Tool-name shadowing | Prefixed names + `createToolRegistry({ duplicate: "error" })` |
165
- | Oversized server output | `maxResultBytes` on content mapping |
179
+ | Oversized/deep/wide server output | One aggregate byte/depth/property walk covers content, structured content, compatibility `toolResult`, and bounded remote errors before `ToolResult` |
166
180
  | Unvalidated arguments | Register tools with `createJsonSchemaToolArgumentValidator()` at dispatch |
167
181
  | Missing permission gate | Client direction: `PermissionPolicy` on `tool:mcp:<serverId>:<name>:execute`; server direction: required MCP `authorize` plus optional core `PermissionPolicy` |
168
182
  | Accidental server exposure | Empty default arrays, duplicate-name rejection, explicit tools/commands only |
169
183
  | Unbounded MCP HTTP | Bounded pre-parsed JSON, response bytes, concurrent requests, call timeout, SDK web-standard transport |
170
184
  | Cross-tenant operation | Authorizer derives ownership from validated auth and passes it to tool dispatch/selected workflow commands; never trust arguments as identity |
171
185
 
172
- MCP output is untrusted. Apply `SecretRedactor` and host logging policy to `ToolResult` before persisting or displaying. MCP server authorization does not replace tool `PermissionPolicy`, argument validation, coding `ExecutionPolicy`, workflow ownership checks, TLS, rate limiting, or sandboxing. A timed-out tool must cooperate with `AbortSignal` to stop side effects; the response is bounded even when untrusted code ignores abort.
186
+ MCP output is untrusted. Register bridge tools through core dispatch with a `SecretRedactor` so bounded remote content/errors are redacted before persistence or display. Prism does not infer unknown secrets. MCP server authorization does not replace tool `PermissionPolicy`, argument validation, coding `ExecutionPolicy`, workflow ownership checks, TLS, rate limiting, or sandboxing. A timed-out tool must cooperate with `AbortSignal` to stop side effects; protocol retention and HTTP responses remain bounded when remote work ignores abort.
187
+
188
+ Discovery validation is atomic: cursor/page/tool/name/description/schema failures reject `refresh()` and preserve the previous immutable tool-array reference. The bridge intentionally uses raw SDK `request()` for `tools/list` and `tools/call`; this avoids eager Ajv compilation/validation of untrusted remote output schemas. Host `ToolValidator` remains the argument-validation owner.
173
189
 
174
190
  ## Related APIs
175
191
 
@@ -181,4 +197,4 @@ MCP output is untrusted. Apply `SecretRedactor` and host logging policy to `Tool
181
197
 
182
198
  ## Testing
183
199
 
184
- Package tests use in-memory MCP transports (no network). Hosts should integration-test their configured stdio commands and HTTP endpoints in staging before production registration.
200
+ Package tests use in-memory MCP transports plus loopback-only HTTP fixtures for redirect, rebinding, response-cap, abort, and POST/GET/DELETE policy coverage. No public network is required. Hosts should integration-test configured stdio commands and HTTPS endpoints in staging before production registration.