@arnilo/prism 0.0.1 → 0.0.2

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 (120) hide show
  1. package/CHANGELOG.md +4 -2
  2. package/README.md +17 -7
  3. package/dist/agent-definitions.d.ts +12 -0
  4. package/dist/agent-definitions.js +131 -0
  5. package/dist/agent-loops.d.ts +14 -0
  6. package/dist/agent-loops.js +161 -0
  7. package/dist/agents.js +263 -76
  8. package/dist/cache-helpers.d.ts +28 -0
  9. package/dist/cache-helpers.js +73 -0
  10. package/dist/cli-runner.d.ts +38 -2
  11. package/dist/cli-runner.js +167 -5
  12. package/dist/compaction.js +2 -0
  13. package/dist/config.js +47 -12
  14. package/dist/contracts.d.ts +581 -6
  15. package/dist/contracts.js +41 -1
  16. package/dist/contribution-parsing.d.ts +19 -0
  17. package/dist/contribution-parsing.js +124 -0
  18. package/dist/contributions.d.ts +13 -3
  19. package/dist/contributions.js +96 -20
  20. package/dist/extensions.js +3 -0
  21. package/dist/index.d.ts +19 -9
  22. package/dist/index.js +10 -4
  23. package/dist/input.d.ts +7 -1
  24. package/dist/input.js +52 -11
  25. package/dist/instruction-injection.d.ts +28 -0
  26. package/dist/instruction-injection.js +55 -0
  27. package/dist/manifests.d.ts +1 -1
  28. package/dist/manifests.js +3 -3
  29. package/dist/models.d.ts +4 -1
  30. package/dist/models.js +5 -2
  31. package/dist/node/agent-definitions.d.ts +98 -0
  32. package/dist/node/agent-definitions.js +389 -0
  33. package/dist/node/contribution-discovery.d.ts +17 -0
  34. package/dist/node/contribution-discovery.js +163 -0
  35. package/dist/node/instruction-injectors.d.ts +32 -0
  36. package/dist/node/instruction-injectors.js +72 -0
  37. package/dist/node/session-store-jsonl.d.ts +1 -1
  38. package/dist/node/session-store-jsonl.js +42 -4
  39. package/dist/node/system-project-prompts.d.ts +30 -0
  40. package/dist/node/system-project-prompts.js +53 -0
  41. package/dist/provider-events.d.ts +3 -1
  42. package/dist/provider-events.js +34 -0
  43. package/dist/provider-request-policy.js +15 -1
  44. package/dist/providers/openai-compatible.js +1 -1
  45. package/dist/providers.d.ts +6 -2
  46. package/dist/providers.js +15 -1
  47. package/dist/redaction.d.ts +2 -1
  48. package/dist/redaction.js +3 -0
  49. package/dist/registry-options.d.ts +5 -0
  50. package/dist/registry-options.js +5 -0
  51. package/dist/rpc.d.ts +6 -2
  52. package/dist/rpc.js +71 -13
  53. package/dist/session-stores.d.ts +3 -1
  54. package/dist/session-stores.js +67 -6
  55. package/dist/skills.d.ts +4 -1
  56. package/dist/skills.js +3 -1
  57. package/dist/system-prompts.js +6 -2
  58. package/dist/testing/compaction-conformance.d.ts +17 -0
  59. package/dist/testing/compaction-conformance.js +61 -0
  60. package/dist/testing/extension-conformance.d.ts +26 -0
  61. package/dist/testing/extension-conformance.js +55 -0
  62. package/dist/testing/provider-conformance.d.ts +7 -0
  63. package/dist/testing/provider-conformance.js +18 -31
  64. package/dist/testing/session-store-conformance.d.ts +20 -0
  65. package/dist/testing/session-store-conformance.js +92 -0
  66. package/dist/testing/tool-conformance.d.ts +39 -0
  67. package/dist/testing/tool-conformance.js +79 -0
  68. package/dist/tools.d.ts +7 -2
  69. package/dist/tools.js +50 -13
  70. package/docs/agent-definitions.md +251 -0
  71. package/docs/agent-events.md +199 -0
  72. package/docs/agent-loops.md +217 -0
  73. package/docs/agent-session-runtime.md +20 -8
  74. package/docs/cli-rpc.md +39 -4
  75. package/docs/compaction-and-retry.md +2 -2
  76. package/docs/compaction-conformance.md +76 -0
  77. package/docs/compaction-llm.md +6 -3
  78. package/docs/compaction-observational-memory.md +4 -4
  79. package/docs/configuration-and-manifests.md +6 -1
  80. package/docs/context-and-skills.md +79 -6
  81. package/docs/contribution-discovery.md +149 -0
  82. package/docs/contribution-registries.md +9 -6
  83. package/docs/credentials-and-redaction.md +2 -0
  84. package/docs/customization.md +191 -0
  85. package/docs/database-persistence.md +407 -0
  86. package/docs/extension-authoring.md +193 -0
  87. package/docs/extension-conformance.md +80 -0
  88. package/docs/extensions.md +6 -0
  89. package/docs/host-security.md +141 -0
  90. package/docs/index.md +40 -19
  91. package/docs/input-and-prompt-assembly.md +19 -3
  92. package/docs/instruction-injection.md +183 -0
  93. package/docs/migration.md +201 -0
  94. package/docs/model-registry.md +122 -0
  95. package/docs/node-jsonl-session-store.md +5 -4
  96. package/docs/performance.md +127 -0
  97. package/docs/provider-caching.md +206 -0
  98. package/docs/provider-conformance.md +32 -5
  99. package/docs/provider-layer.md +51 -11
  100. package/docs/provider-packages.md +65 -5
  101. package/docs/provider-request-policies.md +113 -0
  102. package/docs/providers/kimi.md +22 -0
  103. package/docs/providers/neuralwatt.md +388 -0
  104. package/docs/providers/openai-compatible.md +1 -0
  105. package/docs/providers/openai.md +21 -0
  106. package/docs/providers/opencode-go.md +31 -3
  107. package/docs/providers/openrouter.md +29 -0
  108. package/docs/providers/zai.md +17 -0
  109. package/docs/public-contracts.md +87 -12
  110. package/docs/release-and-install.md +76 -26
  111. package/docs/runs-and-usage.md +236 -0
  112. package/docs/session-store-conformance.md +78 -0
  113. package/docs/session-stores-and-branching.md +10 -6
  114. package/docs/session-stores.md +126 -0
  115. package/docs/settings-auth-trust-security.md +18 -4
  116. package/docs/structured-output.md +247 -0
  117. package/docs/system-prompts.md +104 -2
  118. package/docs/tool-conformance.md +87 -0
  119. package/docs/tools.md +64 -8
  120. package/package.json +35 -2
@@ -0,0 +1,193 @@
1
+ # Extension authoring guide
2
+
3
+ ## What it does
4
+
5
+ This guide shows third-party package authors how to publish a Prism extension package without taking over a host app. An extension exports an `Extension` object with a `setup(api)` function. During explicit host loading, `setup()` registers inert contributions into host-owned registries: providers, models, auth descriptors, tools, context providers, skills, commands, input/prompt builders, compaction strategies, retry policies, store/resource/settings/credential hooks, provider request policies, system prompt contributions, and instruction injectors.
6
+
7
+ Extensions do not start agents, execute tools, read credentials, scan files, or call providers by themselves. The host app loads the extension, inspects/filters contributions, then chooses which entries become active runtime config.
8
+
9
+ ## When to use it
10
+
11
+ Use an extension package when you want reusable Prism capabilities that many host apps can opt into:
12
+
13
+ - provider/model metadata and provider-package registration
14
+ - reusable tools, context providers, skills, commands, input builders, and prompt builders
15
+ - compaction/retry strategies and middleware hooks
16
+ - data-only manifests/resources that hosts can inspect before importing code
17
+
18
+ Do not use an extension to hide host policy. The host still owns trust, permissions, credentials, provider selection, active tool registries, skill activation, storage, UI, and sandboxing. Prism does not auto-discover or sandbox extension packages.
19
+
20
+ ## Inputs / request
21
+
22
+ Package authors export a public `Extension` value:
23
+
24
+ ```ts
25
+ import type { Extension } from "@arnilo/prism";
26
+
27
+ export const extension: Extension = {
28
+ name: "acme-prism-extension",
29
+ setup(api) {
30
+ api.registerSkill({ name: "acme.brief", instructions: "Answer briefly." });
31
+ },
32
+ };
33
+ ```
34
+
35
+ Host apps load it explicitly:
36
+
37
+ ```ts
38
+ import { createExtensionKernel } from "@arnilo/prism";
39
+ import { extension } from "acme-prism-extension";
40
+
41
+ import { createContributionRegistries } from "@arnilo/prism";
42
+
43
+ const registries = createContributionRegistries({ duplicate: "error" });
44
+ const kernel = createExtensionKernel({ registries, secrets: [apiKey] });
45
+ await kernel.load([extension]);
46
+ ```
47
+
48
+ Common `ExtensionAPI` registration calls:
49
+
50
+ | Call | Registers | Activation is host-owned |
51
+ | --- | --- | --- |
52
+ | `registerProviderPackage()` | `ProviderPackage` setup metadata | host calls package setup / selects provider |
53
+ | `registerProvider()` / `registerModel()` | provider/model records | host resolves provider/model for an agent/run |
54
+ | `registerAuthMethod()` | credential descriptor | host resolves actual credentials |
55
+ | `registerTool()` | `ToolDefinition` | host copies selected tools into an active `ToolRegistry` |
56
+ | `registerContextProvider()` | `ContextProvider` | host passes selected providers to agent/input assembly |
57
+ | `registerSkill()` | `Skill` | host selects skills via config or `RunOptions.activeSkills` |
58
+ | `registerInputBuilder()` / `registerPromptBuilder()` | replaceable builders | host passes selected builders to `createAgent()` / assembly |
59
+ | `registerCompactionStrategy()` / `registerRetryPolicy()` | strategies | host selects them in agent/run config |
60
+ | `registerCommand()` / `registerAgent()` | command/agent definitions | host exposes/runs selected entries |
61
+ | `registerProviderRequestPolicy()` / `registerSystemPromptContribution()` | provider/prompt policies | host includes selected policy/layer in runtime config |
62
+ | `registerInstructionInjector()` | inert instruction injector | host passes selected injectors to agent/run config |
63
+ | `use(hook, middleware)` | middleware hook | host passes the kernel middleware registry to runtime config |
64
+
65
+ ## Outputs / response / events
66
+
67
+ `kernel.load([extension])` returns after `setup(api)` completes. The host can then inspect `kernel.registries.*.list()` or resolve named entries. Contributions stay inert until the host wires them into runtime config.
68
+
69
+ Extension errors follow the kernel policy:
70
+
71
+ - default `errorPolicy: "event"` emits an `extension_error` event with known secrets redacted
72
+ - `errorPolicy: "throw"` rejects/throws so the host can fail fast
73
+
74
+ The event bus and middleware registry are ordered and explicit. No hidden global extension kernel is created.
75
+
76
+ ## Request/response example
77
+
78
+ ```json
79
+ {
80
+ "loaded": ["acme-prism-extension"],
81
+ "contributed": {
82
+ "tools": ["acme.echo"],
83
+ "skills": ["acme.brief"],
84
+ "contextProviders": ["acme.project"]
85
+ },
86
+ "active": {
87
+ "tools": ["acme.echo"],
88
+ "skills": ["acme.brief"]
89
+ }
90
+ }
91
+ ```
92
+
93
+ The `contributed` set is what the extension registered. The `active` set is what the host chose to pass into the runtime.
94
+
95
+ ## Implementation example
96
+
97
+ ```ts
98
+ import {
99
+ createAgent,
100
+ createExtensionKernel,
101
+ createMockProvider,
102
+ createContributionRegistries,
103
+ createSkillRegistry,
104
+ createToolRegistry,
105
+ providerDone,
106
+ type Extension,
107
+ } from "@arnilo/prism";
108
+
109
+ export const extension: Extension = {
110
+ name: "acme-prism-extension",
111
+ setup(api) {
112
+ api.registerModel({ provider: "mock", model: "demo" });
113
+ api.registerAuthMethod({ provider: "mock", kind: "api_key", credentialName: "ACME_API_KEY" });
114
+ api.registerTool({
115
+ name: "acme.echo",
116
+ description: "Echo a JSON object.",
117
+ execute(args, ctx) {
118
+ return { toolCallId: ctx.toolCallId, name: "acme.echo", value: args };
119
+ },
120
+ });
121
+ api.registerContextProvider({
122
+ name: "acme.project",
123
+ resolve: () => [{ title: "Project", content: "Use Acme conventions." }],
124
+ });
125
+ api.registerSkill({
126
+ name: "acme.brief",
127
+ instructions: "Answer in one short paragraph.",
128
+ toolNames: ["acme.echo"],
129
+ });
130
+ api.registerPromptBuilder({ name: "acme.prompt", build: async (request) => request.messages });
131
+ api.registerCompactionStrategy({ name: "acme.compact", compact: async () => ({ summary: "summary" }) });
132
+ api.registerRetryPolicy({ name: "acme.retry", decide: () => ({ retry: false }) });
133
+ api.registerCommand({ name: "acme.status", execute: () => ({ ok: true }) });
134
+ api.use("provider_request", (request) => request);
135
+ },
136
+ };
137
+
138
+ const registries = createContributionRegistries({ duplicate: "error" });
139
+ const kernel = createExtensionKernel({ registries, errorPolicy: "throw" });
140
+ await kernel.load([extension]);
141
+
142
+ // Host activation: select contributions explicitly.
143
+ const tool = kernel.registries.tools.resolve("acme.echo");
144
+ const skill = kernel.registries.skills.resolve("acme.brief");
145
+ const provider = createMockProvider([providerDone()]);
146
+
147
+ const agent = createAgent({
148
+ model: { provider: "mock", model: "demo" },
149
+ provider,
150
+ tools: createToolRegistry([tool]),
151
+ skills: createSkillRegistry([skill]),
152
+ context: kernel.registries.contextProviders.list(),
153
+ promptBuilder: kernel.registries.promptBuilders.resolve("acme.prompt"),
154
+ middleware: kernel.middleware,
155
+ });
156
+
157
+ await agent.createSession().run("Use the Acme extension.", { activeSkills: ["acme.brief"] });
158
+ ```
159
+
160
+ ## Extension and configuration notes
161
+
162
+ - Export a stable named `Extension` value. Avoid side effects at module top level; keep registration inside `setup(api)`.
163
+ - Prefix contribution names (`acme.echo`, `acme.brief`) to avoid collisions. Hosts loading third-party packages should use `duplicate: "error"`.
164
+ - A data-only `prism` manifest can describe contributions/resources before the host imports executable package code. Manifest parsing never executes modules.
165
+ - `registerTool()` contributes a definition only. It does not grant permission, add allow-list entries, or execute the tool.
166
+ - `registerSkill()` contributes instructions only. Referenced `toolNames` are checked against host-active tools when the skill is activated.
167
+ - `registerAuthMethod()` and `registerCredentialResolver()` must not contain resolved credential values. Use descriptors/resolvers; the host resolves secrets at the provider/request edge.
168
+ - Middleware from `api.use()` runs only when the host passes `kernel.middleware` into runtime configuration.
169
+ - Provider packages, provider request policies, system prompt contributions, instruction injectors, builders, strategies, commands, store factories, resource loaders, settings providers, and credential resolvers are all inert until host code selects or invokes them.
170
+
171
+ ## Security and performance notes
172
+
173
+ - Prism does not sandbox extension code. Hosts should load only trusted packages or run untrusted packages in their own sandbox/process before calling Prism APIs.
174
+ - Prism does not auto-discover extensions. Filesystem discovery is a separate opt-in scanner that reads `SKILL.md`/`manifest.json` text and still does not activate contributions.
175
+ - Use host trust and permission policies to deny extension setup (`extension:<name>:setup`), resource loads, and tool execution before side effects.
176
+ - Pass known secret values to `createExtensionKernel({ secrets })` so setup/listener errors are redacted. Redaction is exact known-secret replacement, not general secret detection.
177
+ - Never put API keys, OAuth tokens, provider clients, credential resolver outputs, headers, or raw secrets in manifests, registry metadata, extension events, prompts, sessions, ledgers, or idempotency keys.
178
+ - Extension loading performs only the code in `setup(api)` and registry/middleware/event operations. Prism adds no background workers, watchers, network calls, provider calls, filesystem scans, or tool execution.
179
+ - Keep `setup(api)` bounded and deterministic. Long-running initialization, remote auth flows, migrations, and approval UI belong in the host app.
180
+
181
+ ## Related APIs
182
+
183
+ - [Extension kernel and event bus](extensions.md): low-level `ExtensionAPI`, registries, events, middleware, and error policy.
184
+ - [Contribution registries](contribution-registries.md): inert registry bundle populated by extensions.
185
+ - [Configuration and manifests](configuration-and-manifests.md): data-only package manifests and contribution declarations.
186
+ - [Contribution discovery (workspace)](contribution-discovery.md): opt-in filesystem scanner; no import or activation.
187
+ - [Provider packages](provider-packages.md): package-level provider/model/auth/request-policy contributions.
188
+ - [Tools](tools.md): host-owned active tool registry, filtering, dispatch, and permission checks.
189
+ - [Context and skills](context-and-skills.md): host selection and `toolNames` fail-closed skill activation.
190
+ - [Input and prompt assembly](input-and-prompt-assembly.md): selecting contributed builders/context/providers.
191
+ - [Instruction injection](instruction-injection.md): inert injectors that grant no capabilities.
192
+ - [Settings/auth/trust](settings-auth-trust-security.md): trust, permission, credentials, no sandbox, and redaction boundaries.
193
+ - [Extension conformance](extension-conformance.md): test extension setup, inertness, and error redaction/rethrow behavior.
@@ -0,0 +1,80 @@
1
+ # Extension conformance
2
+
3
+ ## What it does
4
+
5
+ Extension conformance helpers are dependency-free assertions for `Extension` adapter tests. They exercise setup execution, inert contribution registration, and setup-error handling under the kernel's error policy, without network or credentials.
6
+
7
+ Exported from `@arnilo/prism/testing/extension-conformance`:
8
+
9
+ - `assertExtensionConforms(extension, options?)`
10
+ - `ExtensionConformanceOptions`
11
+
12
+ ## When to use it
13
+
14
+ Use this helper when authoring an `Extension` package. It asserts:
15
+
16
+ - `setup` runs on load
17
+ - registered contributions land in the inert contribution registries (no side effects until host code resolves and invokes them)
18
+ - under the default `errorPolicy: "event"`, a failing setup emits a redacted `extension_error` event (when `secrets` is supplied)
19
+ - under `expectThrow: true`, a failing setup rethrows to the caller
20
+
21
+ ## Inputs / request
22
+
23
+ ```ts
24
+ import { assertExtensionConforms } from "@arnilo/prism/testing/extension-conformance";
25
+ import type { Extension } from "@arnilo/prism";
26
+
27
+ const extension: Extension = {
28
+ name: "demo",
29
+ setup(api) { api.registerSkill({ name: "brief", instructions: "Be brief." }); },
30
+ };
31
+
32
+ const kernel = await assertExtensionConforms(extension, { secrets: ["token-123"] });
33
+ ```
34
+
35
+ `ExtensionConformanceOptions`:
36
+ - `secrets?: readonly string[]` — secrets that must be redacted in the `extension_error` event (default policy only)
37
+ - `expectThrow?: boolean` — assert a failing setup rethrows under `errorPolicy: "throw"`
38
+
39
+ ## Outputs / response / events
40
+
41
+ Returns `Promise<ExtensionKernel>` so the caller can inspect registered contributions; throws a plain `Error` on the first violation. No runner.
42
+
43
+ ## Request/response example
44
+
45
+ ```ts
46
+ import { assertExtensionConforms } from "@arnilo/prism/testing/extension-conformance";
47
+
48
+ const kernel = await assertExtensionConforms(myExtension, { secrets: ["api-key"] });
49
+ // throws if a failing setup's error event leaks one of the supplied secrets.
50
+ ```
51
+
52
+ ## Implementation example
53
+
54
+ ```ts
55
+ import { assertExtensionConforms } from "@arnilo/prism/testing/extension-conformance";
56
+
57
+ const kernel = await assertExtensionConforms({
58
+ name: "demo",
59
+ setup(api) { api.registerTool({ name: "ping", execute: () => ({ value: "pong" }) }); },
60
+ });
61
+ ```
62
+
63
+ ## Extension and configuration notes
64
+
65
+ - The helper builds a fresh `ExtensionKernel` for each call; it does not reuse host kernel state.
66
+ - Contributions are inert by construction — the kernel stores envelopes and never invokes provider/tool/skill capabilities until host code resolves and calls them.
67
+ - Under `expectThrow`, the helper asserts the kernel rethrows a failing setup rather than isolating it.
68
+
69
+ ## Security and performance notes
70
+
71
+ - No credentials, no network required; pass fake secret strings.
72
+ - Redaction is exact-match (mirroring `createSecretRedactor`); the helper does not detect arbitrary secret patterns.
73
+ - The kernel does not sandbox tool/extension execution — hosts retain responsibility for trust and permission gating (see [Settings, auth, trust, security](settings-auth-trust-security.md)).
74
+
75
+ ## Related APIs
76
+
77
+ - [Extensions](extensions.md)
78
+ - [Contribution registries](contribution-registries.md)
79
+ - [Settings, auth, trust, security](settings-auth-trust-security.md)
80
+ - [Provider conformance](provider-conformance.md)
@@ -101,11 +101,13 @@ await kernel.middleware.run("provider_request", { metadata: {} });
101
101
  ## Extension and configuration notes
102
102
 
103
103
  - Extension loading is explicit. Prism does not discover packages, read manifests, or load filesystem config in the kernel.
104
+ - `AgentConfig.extensions` is host-owned metadata for compatibility; `createAgent()` and `session.run()` do not load it or call `Extension.setup()`. Load extensions with `createExtensionKernel().load(...)`, then pass selected contributions (`tools`, `context`, `skills`, middleware, etc.) into `createAgent()`.
104
105
  - Setup order is the order provided by the host.
105
106
  - The kernel writes only to explicit registries returned by `createContributionRegistries()` or provided by the host.
106
107
  - `api.registerTool()` contributes an inert `ToolDefinition` to `registries.tools`; it does not add the tool to an active tool registry, allow list, or dispatch loop.
107
108
  - `api.registerInputBuilder()`, `api.registerPromptBuilder()`, and `api.registerContextProvider()` contribute inert builders/providers; they do not replace defaults or run until the host passes selected entries to Phase 5 helpers.
108
109
  - `api.registerSkill()` contributes an inert `Skill` to `registries.skills`; it does not disclose instructions, activate referenced tools, or grant permissions until the host selects it.
110
+ - `api.registerInstructionInjector()` (Phase 30) contributes an inert `InstructionInjector` to `registries.instructionInjectors`; it grants no tools, skills, or permissions and is only applied when the host selects it via `AgentConfig.instructionInjectors`/`RunOptions.instructionInjectors`. See [Instruction injection](instruction-injection.md).
109
111
  - `api.registerProviderPackage()`, `api.registerAuthMethod()`, `api.registerProviderRequestPolicy()`, and `api.registerSystemPromptContribution()` contribute inert provider-package data; they do not load packages, resolve credentials, mutate provider payloads, or change prompts until selected by a host/runtime helper that documents that behavior.
110
112
  - `api.registerAgent()` contributes an inert `AgentDefinition`; its `create()` can call `createAgent()`, but the runtime is not started until host code resolves the definition and creates/runs a session.
111
113
  - The kernel registers middleware only into the explicit registry returned by `createMiddlewareRegistry()` or provided by the host.
@@ -115,6 +117,7 @@ await kernel.middleware.run("provider_request", { metadata: {} });
115
117
  ## Security and performance notes
116
118
 
117
119
  - No hidden global extension kernel, provider registry, credential resolver, settings provider, store, or resource loader is created.
120
+ - `AgentConfig.extensions` does not auto-execute, so constructing or running an agent cannot unexpectedly run extension code.
118
121
  - Error events use `ErrorInfo` and redact only known secret values passed in `secrets`.
119
122
  - Do not put resolved credential values in extension events, registry metadata, docs, logs, prompts, or session stores.
120
123
  - Event and middleware dispatch are ordered and dependency-free. They use no timers, background workers, filesystem discovery, network calls, provider calls, or tool execution.
@@ -122,10 +125,13 @@ await kernel.middleware.run("provider_request", { metadata: {} });
122
125
 
123
126
  ## Related APIs
124
127
 
128
+ - [Extension authoring guide](extension-authoring.md): package-author checklist for inert contributions, host activation, trust, permissions, no sandbox, and redaction.
125
129
  - [Middleware hooks](middleware-hooks.md): ordered hook registry populated by `ExtensionAPI.use()`.
126
130
  - [Provider packages](provider-packages.md): provider package and model metadata registration through `ExtensionAPI`.
127
131
  - [Contribution registries](contribution-registries.md): registry bundle populated by `ExtensionAPI`.
132
+ - [Contribution discovery (workspace)](contribution-discovery.md): filesystem-driven complement to extension registration — opt-in scan without `import()` or activation.
128
133
  - [Tools](tools.md): host activation, filtering, and dispatch for contributed tool definitions.
134
+ - [Instruction injection](instruction-injection.md): package injectors that layer instructions and context blocks for `first_turn`/`every_turn`/`on_input` without granting tools.
129
135
  - [Input and prompt assembly](input-and-prompt-assembly.md): host selection for contributed input/prompt builders.
130
136
  - [System prompts](system-prompts.md): host selection for contributed system prompt layers.
131
137
  - [Context and skills](context-and-skills.md): host selection and tool checks for contributed context providers and skills.
@@ -0,0 +1,141 @@
1
+ # Host security guide
2
+
3
+ ## What it does
4
+
5
+ This guide is a fail-closed checklist for apps embedding Prism. It maps host security responsibilities to existing Prism APIs for credentials, settings, redaction, trust roots, permission policies, session and ledger persistence, extension loading, and tool validation.
6
+
7
+ Prism supplies seams and checks. The host owns policy decisions, secret sources, durable storage, approval UI, sandboxing, and which contributed capabilities become active.
8
+
9
+ ## When to use it
10
+
11
+ Use this guide before exposing an agent to users, third-party extensions, durable storage, or real provider credentials.
12
+
13
+ Do not use it as a replacement for product threat modeling, process/container sandboxing, secret management, database access control, or provider-side policy. Prism does not sandbox tools/extensions and does not detect arbitrary secrets.
14
+
15
+ ## Inputs / request
16
+
17
+ Start from explicit host inputs. Do not let runtime code discover security state implicitly.
18
+
19
+ | Security input | Host-owned source | Prism API / page |
20
+ | --- | --- | --- |
21
+ | Settings | app config object or caller-named files | `createStaticSettingsProvider`, `loadSettingsFiles()` |
22
+ | Credentials | runtime override, memory store, vault/env object | `createExplicitCredentialResolver`, `createEnvCredentialResolver`, `resolveCredentialValue()` |
23
+ | Redaction values | exact known credential strings | `createSecretRedactor`, `redactSecrets()` |
24
+ | Trust roots | app-selected directories/resources | `createPathTrustPolicy`, `assertTrusted()` |
25
+ | Permission decisions | allow/deny rules or approval UI result | `createStaticPermissionPolicy`, `assertPermission()` |
26
+ | Tool allow-list | active tools for this agent/session/run | `createToolRegistry`, `filterTools()`, `dispatchToolCall()` |
27
+ | Tool argument rules | host validator | `AgentConfig.validator`, `RunOptions.validate`, `ToolValidator` |
28
+ | Durable history | host database adapter | `SessionStore`, `assertSessionStoreConforms()` |
29
+ | Durable audit | host ledger adapter | `RunLedger`, `redactRunLedgerRecord()` |
30
+ | Extensions | explicit package imports only | `createExtensionKernel`, `ExtensionAPI` |
31
+
32
+ ## Outputs / response / events
33
+
34
+ Security controls fail closed before side effects when wired at the guarded edge:
35
+
36
+ - trust denial blocks resource/extension reads before load/use
37
+ - permission denial blocks extension setup, resource loading, and tool execution
38
+ - unknown or denied tools emit `tool_execution_blocked`
39
+ - validator failures emit `tool_execution_blocked` with `validation_failed`
40
+ - configured redactors scrub provider requests, agent events, session entries, ledger records, tool errors, extension errors, and injector context
41
+
42
+ These checks are explicit function calls during load, assembly, dispatch, append, or run handling. Prism adds no background watchers, filesystem scanners, network probes, credential polling, or automatic extension discovery.
43
+
44
+ ## Request/response example
45
+
46
+ ```json
47
+ {
48
+ "credentialSource": "caller-owned env object",
49
+ "trustedRoots": ["/workspace/app"],
50
+ "allowedActions": ["tool:notes/read:execute", "extension:acme:setup"],
51
+ "activeTools": ["notes/read"],
52
+ "toolValidation": "host ToolValidator",
53
+ "persistence": "redacted SessionStore + RunLedger"
54
+ }
55
+ ```
56
+
57
+ The JSON above is an app security plan, not a Prism config format. Hosts translate each field into the explicit APIs listed in this guide.
58
+
59
+ ## Implementation example
60
+
61
+ ```ts
62
+ import {
63
+ createEnvCredentialResolver,
64
+ createSecretRedactor,
65
+ createStaticPermissionPolicy,
66
+ createToolRegistry,
67
+ filterTools,
68
+ resolveCredentialValue,
69
+ type ToolDefinition,
70
+ type ToolValidator,
71
+ } from "@arnilo/prism";
72
+ import { createPathTrustPolicy } from "@arnilo/prism/node/trust";
73
+
74
+ const workspaceRoot = "/workspace/app";
75
+ const env = { DEMO_API_KEY: "fake-demo-key" }; // docs-only placeholder
76
+ const credentials = createEnvCredentialResolver(env, { demo: "DEMO_API_KEY" });
77
+ const apiKey = await resolveCredentialValue(credentials, { provider: "demo", name: "apiKey" });
78
+
79
+ const redactor = createSecretRedactor([apiKey]);
80
+ const permission = createStaticPermissionPolicy({
81
+ allow: ["tool:notes/read:execute", "extension:acme:setup"],
82
+ });
83
+ const trust = createPathTrustPolicy({ trustedRoots: [workspaceRoot] });
84
+
85
+ const readNotes: ToolDefinition = {
86
+ name: "notes/read",
87
+ parameters: { type: "object", properties: { id: { type: "string" } } },
88
+ execute(args, context) {
89
+ return { toolCallId: context.toolCallId, name: "notes/read", value: { id: args.id } };
90
+ },
91
+ };
92
+
93
+ const validate: ToolValidator = (_tool, args) =>
94
+ typeof args.id === "string" && args.id.length <= 100
95
+ ? undefined
96
+ : "id must be a short string";
97
+
98
+ const tools = createToolRegistry(filterTools([readNotes], { allow: ["notes/read"] }), { duplicate: "error" });
99
+
100
+ void { apiKey, redactor, permission, trust, tools, validate };
101
+ ```
102
+
103
+ Wire those values where they matter: provider adapters receive the resolved credential, agents/runs receive `redactor`, tool dispatch receives `permission` and `validate`, resource/extension loaders receive `trust` and `permission`, and durable adapters receive already-redacted entries/records.
104
+
105
+ ## Extension and configuration notes
106
+
107
+ - Keep security state explicit. `AgentConfig.settings` and `AgentConfig.credentials` are host-owned metadata; `createAgent()` and `session.run()` do not automatically call `settings.get()` or `credentials.resolve()`.
108
+ - Resolve credentials at the provider/request edge, as late as possible. Do not put resolved credentials in configs, manifests, registries, prompts, messages, events, session entries, run ledgers, idempotency keys, cache keys, or logs.
109
+ - Use `createExplicitCredentialResolver()` to document source order such as runtime override → stored credential → caller-supplied env object → fallback.
110
+ - Use `createEnvCredentialResolver()` only with an object the host passes in. Prism does not read `process.env` for credentials.
111
+ - Use `createPathTrustPolicy()` for workspace/resource roots and fail closed on symlink escapes.
112
+ - Use `createContributionRegistries({ duplicate: "error" })` and prefixed names for third-party packages to prevent silent shadowing.
113
+ - Extension contributions are inert until selected. Loading an extension package runs its `setup(api)` code, so hosts should load only trusted packages or isolate untrusted code outside Prism.
114
+ - Skills and instruction injectors grant no tools, permissions, validators, or resource access. Host-active tools and permission policies still decide execution.
115
+ - For production persistence, implement a database-backed `SessionStore`/`RunLedger`, run `assertSessionStoreConforms()` against the store, and follow the database schema guidance. Do not ship provider instances, credential resolvers, or secrets into durable rows.
116
+
117
+ ## Security and performance notes
118
+
119
+ - Fail closed: unknown providers, unknown tools, denied tools, invalid tool arguments, missing skill tool dependencies, trust failures, permission failures, append conflicts, and validator failures should stop the unsafe action.
120
+ - Prism does not sandbox host tools, extensions, provider adapters, credential resolvers, or custom middleware. Use OS/container/process isolation when code is untrusted.
121
+ - Redaction is exact known-secret replacement only. It is not arbitrary secret detection, entropy scanning, or DLP.
122
+ - 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.
123
+ - Tool `parameters` metadata is not validation. Add a `ToolValidator` or validate inside the tool before side effects.
124
+ - Permission checks happen before tool validation and before `tool.execute()`. Middleware cannot grant permission by renaming a tool.
125
+ - 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.
126
+ - Provider-owned auth/content/session/cache/security headers win over caller headers in adapters that merge headers.
127
+ - Security checks are bounded explicit calls on the active path. Prism adds no hidden global middleware, background workers, watchers, network calls, or filesystem scans.
128
+
129
+ ## Related APIs
130
+
131
+ - [Settings, auth, trust, and security controls](settings-auth-trust-security.md): low-level helpers and boundary hardening table.
132
+ - [Credentials and redaction](credentials-and-redaction.md): credential resolver order, caller-supplied env objects, OAuth refresh, exact redaction, and no persistent secret store.
133
+ - [Tools](tools.md): active tool registry, allow/deny filters, permission order, validator order, blocked events, and no sandbox.
134
+ - [Extension authoring guide](extension-authoring.md): inert contribution package boundary and extension loading security notes.
135
+ - [Extension kernel and event bus](extensions.md): `createExtensionKernel`, setup error redaction/rethrow, and permission-gated extension setup.
136
+ - [Contribution discovery](contribution-discovery.md): opt-in realpath-contained scanner that imports nothing and activates nothing.
137
+ - [Instruction injection](instruction-injection.md): redacted injector context and no capability grants.
138
+ - [Session stores](session-stores.md): durable session store contract and secret/persistence boundaries.
139
+ - [Runs and usage ledger](runs-and-usage.md): redacted run/event/tool/usage ledger records.
140
+ - [Database persistence](database-persistence.md): production schema, ownership, indexes, retention, and adapter readiness checklist.
141
+ - [Provider caching](provider-caching.md): cache keys and provider-owned header safety rules.
package/docs/index.md CHANGED
@@ -6,50 +6,71 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
6
6
  - [Public contracts](public-contracts.md): type shapes for messages, content, agents, sessions, providers, tools, context, skills, extensions, stores, resources, settings, credentials, and events.
7
7
 
8
8
  ## Agent/session runtime
9
- - [Agent/session runtime](agent-session-runtime.md): create agents and sessions, run prompts, and subscribe to normalized session events.
9
+ - [Agent/session runtime](agent-session-runtime.md): create agents and sessions, run prompts, subscribe to normalized events, and see which `AgentConfig` fields are runtime-consumed vs host-owned metadata. Covers tool-call loop transcript shape and prior-reasoning preservation across turns.
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.
12
+ - [Agent events](agent-events.md): the `AgentEvent` stream — agent/turn/message (including live `tool_call_delta` fragments), tool execution, queue/subscriber overflow, compaction/retry, artifact validation/refinement, and error variants, redacted via `redactAgentEvent`.
13
+ - [Runs and usage ledger](runs-and-usage.md): `RunLedger` adapter for durable run, event, tool-call, usage persistence, cache diagnostics, ownership/idempotency, and redaction guidance.
14
+ - [Performance limits](performance.md): bounded live subscriber queues, branch-read pagination expectations, JSONL/dev-store limits, and production sizing assumptions.
15
+ - [Structured output](structured-output.md): the `Artifact*` seam (parser/validator/repairer, host-defined `T`) — the only typed-output path from a loop, with a Synapta-style schema→`ArtifactValidation` mapping example and an end-to-end third-party integration walkthrough.
10
16
 
11
17
  ## Compaction/session memory
12
18
  - [Compaction and retry policies](compaction-and-retry.md): summarize branch history and retry transient provider failures with host-replaceable policies.
13
- - [LLM compaction package](compaction-llm.md): optional provider-backed compaction strategy package.
14
- - [Observational memory compaction package](compaction-observational-memory.md): optional source-backed memory, fast compaction, recall tool, and status/view command package.
15
- - [Session stores and branching](session-stores-and-branching.md): store session entries, rebuild branch context, and navigate branch leaves.
16
- - [Node JSONL session store](node-jsonl-session-store.md): persist session entries to caller-named JSONL files in Node hosts.
19
+ - [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.
20
+ - [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.
21
+ - [Session stores](session-stores.md): `SessionStore` contract, `SessionAppendOptions`, `SessionAppendConflictError`, branch handles, `readBranchPath`, and dev-vs-production branch reads — start here for session persistence.
22
+ - [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).
23
+ - [Database persistence](database-persistence.md): production persistence contracts, conditional append transaction pattern, idempotency indexes, `readBranchPath`, reference relational schema, retention, migrations, and NoSQL mapping.
24
+ - [Migration guide](migration.md): the two cross-cutting app migrations in one place — in-memory/JSONL → database-backed `ProductionPersistenceStore` persistence (+ `RunLedger`) and permissive capability defaults → Phase 38 explicit `tools`/`skills` activation, with before/after shapes and links to the detailed pages.
25
+ - [Node JSONL session store](node-jsonl-session-store.md): development-only JSONL file adapter for single-process Node hosts; no cross-process safety.
17
26
 
18
27
  ## Provider and model connection
19
- - [Provider layer](provider-layer.md): register and resolve host-owned providers/models, create provider events, use generic provider request options, and test with the mock provider.
20
- - [Provider packages](provider-packages.md): define explicit provider packages, model metadata, auth descriptors, and request/cache policies without package discovery or provider-specific core behavior.
21
- - 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), and [`@arnilo/prism-provider-kimi`](providers/kimi.md).
28
+ - [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.
29
+ - [Model registry](model-registry.md): register and resolve `ModelConfig` records with capabilities, limits, cost, cache support metadata, compat data, and duplicate policy.
30
+ - [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.
31
+ - [Provider request policies](provider-request-policies.md): chain `ProviderRequestPolicy` hooks, use `createSessionCachePolicy`, and merge legacy/structured cache options safely.
32
+ - [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.
33
+ - 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.
22
34
  - [OpenAI-compatible provider](providers/openai-compatible.md): optional provider subpath using native or injected `fetch` for Chat Completions streaming.
23
35
 
24
36
  ## Input, prompt, and context assembly
25
- - [Input and prompt assembly](input-and-prompt-assembly.md): render tiny prompt templates and turn common host input, history, attachments, explicit resources, summaries, and tool results into messages with replaceable builders and provider-input assembly.
26
- - [System prompts](system-prompts.md): compose explicit package/app/user/run system prompt layers without filesystem discovery or hidden globals.
27
- - [Context and skills](context-and-skills.md): resolve ordered context providers and keep context/skill selection host-owned.
37
+ - [SDK customization guide](customization.md): map provider resolution, middleware, context, builders, injectors, loops, compaction, retry, stores, and skills to explicit host-wired APIs.
38
+ - [Input and prompt assembly](input-and-prompt-assembly.md): render tiny prompt templates and turn common host input, history, attachments, explicit resources, summaries, and tool results into messages with replaceable builders, provider-input assembly, legacy default order, and opt-in cache-aware ordering.
39
+ - [System prompts](system-prompts.md): compose explicit user/package/app/run system prompt layers, auto-load the standard `AGENTS.md` (workspace) / `SYSTEM.md` prompt files via the Node `loadSystemPromptFiles` loader (trust-gated for `AGENTS.md`), and append `SYSTEM.md` → per-agent `AGENT.md` body → repo `AGENTS.md` layers from a discovered agent bundle via `resolveAgentBundle`.
40
+ - [Instruction injection](instruction-injection.md): register package injectors that layer redacted instructions/context blocks without granting tools, permissions, or resource escapes.
41
+ - [Context and skills](context-and-skills.md): resolve ordered context providers and keep context/skill selection host-owned; omitted declarative skills stay inactive by default, `toolNames` fail closed before provider turns, and strict skill registries prevent silent shadowing.
28
42
 
29
43
  ## Tools
30
- - [Tools](tools.md): register host-owned active tools, apply exact allow/deny filtering, and dispatch tool calls.
44
+ - [Tools](tools.md): register host-owned active tools with replace-or-error duplicate policy, apply exact allow/deny filtering, and dispatch tool calls.
31
45
 
32
46
  ## Extensions/plugins
33
- - [Contribution registries](contribution-registries.md): explicit host-owned registries for extension/package contributions without hidden globals.
47
+ - [Contribution discovery (workspace)](contribution-discovery.md): opt-in, realpath-contained directory scanner turning `SKILL.md`/`manifest.json` into inert `DiscoveredContribution` envelopes the host registers — no `import()`, no auto-activate, no provider scanning. (Per-agent `AGENT.md` bundles live under an app-controlled `configRoot`; see [Agent definitions](agent-definitions.md).)
48
+ - [Contribution registries](contribution-registries.md): explicit host-owned registries for extension/package contributions without hidden globals, with `duplicate: "error"` strict mode for provider/model/tool/skill shadowing prevention.
34
49
  - [Extension kernel and event bus](extensions.md): load host-provided extensions in order, register contributions, emit lifecycle events, and isolate extension errors.
50
+ - [Extension authoring guide](extension-authoring.md): publish third-party extension packages that register inert contributions and show host-owned activation, trust, permissions, redaction, and no-sandbox boundaries.
35
51
  - [Middleware hooks](middleware-hooks.md): ordered hook registry for provider, input, context, tool, retry, compaction, and session lifecycle boundaries.
36
52
 
37
53
  ## Configuration/manifests
38
- - [Configuration and manifests](configuration-and-manifests.md): merge in-memory JSON config layers and validate data-only package manifests.
54
+ - [Configuration and manifests](configuration-and-manifests.md): merge in-memory JSON config layers and validate data-only package manifests with prototype-pollution key rejection.
39
55
  - [Node filesystem config loader](node-filesystem-config.md): explicitly read caller-named JSON config files in Node hosts.
40
56
  - [Resource loading](resource-loading.md): decode text, JSON, and manifest resources through caller-provided loaders.
41
57
 
42
58
  ## CLI/RPC
43
- - [CLI/RPC](cli-rpc.md): Run print/json modes and LF-delimited RPC over the public AgentSession runtime.
59
+ - [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`.
44
60
 
45
61
  ## Security and credentials
46
- - [Security/auth/trust](settings-auth-trust-security.md): settings providers, credential helpers, trust/permission policies, and redaction controls.
47
- - [Credentials and redaction](credentials-and-redaction.md): compose explicit credential resolver order, use caller-supplied env objects/OAuth refresh helpers, and redact known secret values.
62
+ - [Host security guide](host-security.md): fail-closed checklist for credentials, settings, redaction, trust roots, permission policies, persistence, extension loading, and tool validation.
63
+ - [Security/auth/trust](settings-auth-trust-security.md): settings providers, credential helpers, trust/permission policies, redaction controls, host-owned `AgentConfig.settings`/`credentials`, and security-boundary hardening summary.
64
+ - [Credentials and redaction](credentials-and-redaction.md): compose explicit credential resolver order, use caller-supplied env objects/OAuth refresh helpers, avoid eager `AgentConfig.credentials` resolution, and redact known secret values.
48
65
 
49
66
  ## Testing and examples
50
67
  - [Provider layer](provider-layer.md): use `createMockProvider()` and provider event helpers for deterministic tests without timers, credentials, or network.
51
- - [Provider conformance](provider-conformance.md): run network-free provider adapter assertions from `@arnilo/prism/testing/provider-conformance`.
52
- - `examples/`: compile-checked typed examples and runnable mock demos (SDK basics, provider registration, auth, tools, stores/branching, compaction, observational-memory recall, CLI, RPC).
68
+ - [Provider conformance](provider-conformance.md): run network-free provider adapter assertions (stream order, abort, tool-call reconstruction, cache usage, content coverage, protected header ownership, secret leak) from `@arnilo/prism/testing/provider-conformance`.
69
+ - [Session store conformance](session-store-conformance.md): assert any `SessionStore` adapter satisfies append/idempotency/conflict/branch invariants from `@arnilo/prism/testing/session-store-conformance`.
70
+ - [Compaction conformance](compaction-conformance.md): assert any `CompactionStrategy` returns a non-empty redacted summary and observes abort from `@arnilo/prism/testing/compaction-conformance`.
71
+ - [Tool conformance](tool-conformance.md): assert the tool-dispatch blocked-reason matrix (unknown/denied/invalid/permission/validator) and success path from `@arnilo/prism/testing/tool-conformance`.
72
+ - [Extension conformance](extension-conformance.md): assert an `Extension` setup runs, contributions stay inert, and setup errors are redacted or rethrown from `@arnilo/prism/testing/extension-conformance`.
73
+ - `examples/`: compile-checked typed examples and runnable mock demos (SDK basics, provider registration, auth, tools, cache-aware prompt assembly, NeuralWatt agent run, stores/branching, compaction, observational-memory recall, structured-output/artifact-loop, CLI, RPC).
53
74
 
54
75
  ## Release and install
55
76
  - [Release and install](release-and-install.md): package layout, install specifiers, required `@arnilo/prism` peer, tarball contents and exclusions, the map-retention knob, the release workflow, and the offline test budget.