@arnilo/prism 0.0.20 → 0.0.23

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.
@@ -0,0 +1,127 @@
1
+ # Ponytail behavior integration
2
+
3
+ ## What it does
4
+
5
+ `@arnilo/prism-ponytail` is an optional package that wires [DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail) into Prism contribution contracts.
6
+
7
+ It registers upstream skills and commands, injects active mode instructions via upstream `getPonytailInstructions` / `filterSkillBodyForMode`, and persists mode as session custom `ponytail-mode` entries. Import is inert; missing upstream fails closed at `setup` with a bounded redacted error.
8
+
9
+ ## When to use it
10
+
11
+ Use it when a host wants lazy-minimalism coding behavior (`lite`, `full`, `ultra`) with upstream Ponytail skills (`ponytail-audit`, `ponytail-debt`, `ponytail-gain`, `ponytail-help`, `ponytail-review`) in a Prism extension kernel.
12
+
13
+ Install optional peer `@dietrichgebert/ponytail@^4.8.4` **or** pass `upstreamPath` to a checkout with `skills/` and `hooks/`.
14
+
15
+ Pair with progressive disclosure: mode slices on the `ponytail-mode` injector; full skill bodies via `load_skill` only.
16
+
17
+ ## Inputs / request
18
+
19
+ `createPonytailExtension(options)`:
20
+
21
+ | Field | Type | Required | Purpose |
22
+ | --- | --- | --- | --- |
23
+ | `upstreamPath` | `string` | no | Override path to Ponytail root; default resolves optional peer package. |
24
+ | `defaultMode` | `PonytailMode` | no | Initial mode when no session entry exists (default `full`). |
25
+ | `quietStartup` | `boolean` | no | Suppress startup status events. |
26
+ | `appendEntry` | `(entry, opts?) => Promise<void>` | yes | Host session append (OM `attach` pattern). |
27
+ | `getEntries` | `() => readonly SessionEntry[] \| Promise<...>` | yes | Current branch entries for mode restore. |
28
+ | `configPath` | `string` | no | Bounded local config for `defaultMode` / `quietStartup` / `hideStatus`. |
29
+
30
+ `PonytailMode`: `off` \| `lite` \| `full` \| `ultra`.
31
+
32
+ Session custom entry shape:
33
+
34
+ ```json
35
+ { "kind": "custom", "data": { "type": "ponytail-mode", "mode": "full" } }
36
+ ```
37
+
38
+ Registered skills: `ponytail`, `ponytail-audit`, `ponytail-debt`, `ponytail-gain`, `ponytail-help`, `ponytail-review`.
39
+
40
+ Registered commands: `ponytail`, `ponytail-review`, `ponytail-audit`, `ponytail-gain`, `ponytail-debt`, `ponytail-help`.
41
+
42
+ `ponytail` command actions: `lite|full|ultra|off`, `status`, `default <mode>`.
43
+
44
+ ## Outputs / response / events
45
+
46
+ | Export | Purpose |
47
+ | --- | --- |
48
+ | `createPonytailExtension(options)` | Returns an inert `Extension` until `kernel.load([...])`. |
49
+ | `ponytail-mode` injector | `InstructionInjector` calling upstream `getPonytailInstructions(mode)`. |
50
+ | `ponytail` command | Set mode, report status, or persist default mode to config file. |
51
+ | Alias commands | Dispatch `{ skill, dispatch: "load_skill" }` for companion skills. |
52
+ | `ponytail:status` / `ponytail:loaded` events | Optional host metadata (no statusline shell scripts). |
53
+
54
+ Deactivation: exact phrases `stop ponytail` and `normal mode`.
55
+
56
+ ## Request/response example
57
+
58
+ ```json
59
+ { "command": "ponytail", "args": { "mode": "lite" }, "sessionId": "s1" }
60
+ ```
61
+
62
+ ```json
63
+ { "kind": "custom", "data": { "type": "ponytail-mode", "mode": "lite" } }
64
+ ```
65
+
66
+ ## Implementation example
67
+
68
+ ```ts
69
+ import { createPonytailExtension } from "@arnilo/prism-ponytail";
70
+ import {
71
+ createExtensionKernel,
72
+ createLoadSkillTool,
73
+ createLoadedSkillSet,
74
+ createMemorySessionStore,
75
+ createSkillRegistry,
76
+ } from "@arnilo/prism";
77
+
78
+ const store = createMemorySessionStore();
79
+ const callbacks = {
80
+ appendEntry: async (entry, options) => store.append(entry, options),
81
+ getEntries: async () => store.list("s1"),
82
+ };
83
+
84
+ const kernel = createExtensionKernel({ errorPolicy: "throw" });
85
+ await kernel.load([
86
+ createPonytailExtension({
87
+ upstreamPath: undefined, // optional peer @dietrichgebert/ponytail
88
+ defaultMode: "full",
89
+ quietStartup: true,
90
+ ...callbacks,
91
+ }),
92
+ ]);
93
+
94
+ const registry = createSkillRegistry(kernel.registries.skills.list());
95
+ const loaded = createLoadedSkillSet();
96
+ const loadSkill = createLoadSkillTool({ registry, loaded });
97
+
98
+ await kernel.registries.commands.get("ponytail")!.execute({ mode: "lite" }, { sessionId: "s1" });
99
+ // Select instructionInjectors: ["ponytail-mode"] on runs that should receive mode slices.
100
+ ```
101
+
102
+ See `examples/caveman-ponytail.ts` for combined Caveman + Ponytail progressive disclosure demo (network-free fixtures).
103
+
104
+ ## Extension and configuration notes
105
+
106
+ - Import alone registers nothing (`sideEffects: false`); no timers, watchers, network, or shell scripts.
107
+ - Upstream hook modules load via `createRequire` from resolved root — instruction strings are not forked in Prism.
108
+ - Mode restore scans `getEntries()` for latest `data.type === "ponytail-mode"` (OM attach pattern).
109
+ - `ponytail-subagent` hook is not wired; nested-agent behavior is host responsibility.
110
+ - No TUI statusline scripts; use `ponytail status` command or extension events.
111
+ - Not included in `@arnilo/prism-code` or `@arnilo/prism-sdk` profiles — opt-in install only.
112
+
113
+ ## Security and performance notes
114
+
115
+ - Upstream text is untrusted; reads bounded (`MAX_SKILL_FILE_BYTES` 256 KiB, `MAX_INJECTED_INSTRUCTION_BYTES` 32 KiB).
116
+ - Config writes only to host `configPath` with size cap (`MAX_CONFIG_FILE_BYTES` 16 KiB).
117
+ - Errors redact absolute paths and home directories.
118
+ - O(skills) setup scan; O(1) mode tracking per turn; no background workers.
119
+
120
+ ## Related APIs
121
+
122
+ - [Caveman behavior integration](caveman.md): complementary terse-communication mode package.
123
+ - [Extension kernel and event bus](extensions.md): explicit `kernel.load`.
124
+ - [Context and skills](context-and-skills.md): progressive catalog + `load_skill`.
125
+ - [Instruction injection](instruction-injection.md): `ponytail-mode` injector.
126
+ - [Observational memory compaction package](compaction-observational-memory.md): session callback attach pattern.
127
+ - [Migration guide](migration.md): `0.0.21 → 0.0.22` notes.
@@ -24,7 +24,7 @@ Use this package when you need server-backed persistence with pooled connections
24
24
  - managed cloud databases (RDS, Cloud SQL, Neon, Supabase, etc.)
25
25
  - CI integration tests against a real PostgreSQL service
26
26
 
27
- Prefer [`@arnilo/prism-session-store-sqlite`](sqlite-persistence.md) for local CLI tools, single-writer workloads, and network-free default tests. This adapter stores sessions/runs, not semantic vectors; use the separate [`@arnilo/prism-memory` pgvector path](working-and-semantic-memory.md), which rejects non-finite vectors before SQL, when vector recall is needed.
27
+ Prefer [`@arnilo/prism-session-store-sqlite`](sqlite-persistence.md) for local CLI tools, single-writer workloads, and network-free default tests. This adapter stores sessions/runs, not semantic vectors; use the separate [`@arnilo/prism-memory` pgvector path](working-and-semantic-memory.md), which rejects non-finite vectors before SQL, when vector recall is needed. For durable policy decisions, evaluations, work mutation idempotency, and model-router state, use the separate [`@arnilo/prism-enterprise-postgres`](enterprise-postgres-state.md) composition; it has its own migration history and does not replace session/run persistence.
28
28
 
29
29
  ## Inputs / request
30
30
 
@@ -141,4 +141,5 @@ PRISM_TEST_POSTGRES_URL="$DATABASE_URL" npm run test:postgres --workspace @arnil
141
141
  - [Persistence, credentials, and multimodality primitives](persistence-credentials-multimodality-primitives.md): package matrix and threat model.
142
142
  - [Workflows](workflows.md): adapt `persistence.checkpoints` and pass `persistence.leases` to `createWorkflowCoordinator()` and `createWorkflowSchedules()` for durable background execution and schedules.
143
143
  - [Working and semantic memory](working-and-semantic-memory.md): optional `@arnilo/prism-memory` PostgreSQL/pgvector working + semantic stores (separate from session/run persistence).
144
+ - [Enterprise PostgreSQL state](enterprise-postgres-state.md): separate durable policy/evaluation/work/router stores and cleanup.
144
145
  - [Migration guide](migration.md): moving from JSONL/in-memory to database-backed persistence.
@@ -2,13 +2,13 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- Prism is published as one core package, thirty-seven first-party capability packages, and six pure-manifest family/profile packages (**44** publishable manifests total). This page describes how they are packed, what each tarball contains, how to install them, the required `@arnilo/prism` peer dependency, the release workflow, and the offline test budget. The measurable 1.0 readiness gates (command-per-gate) live in [`0.1.0-readiness.md`](./0.1.0-readiness.md).
5
+ Prism is published as one core package, forty first-party capability packages, and six pure-manifest family/profile packages (**47** publishable manifests total). This page describes how they are packed, what each tarball contains, how to install them, the required `@arnilo/prism` peer dependency, the release workflow, and the offline test budget. The measurable 1.0 readiness gates (command-per-gate) live in [`0.1.0-readiness.md`](./0.1.0-readiness.md).
6
6
 
7
7
  Core package:
8
8
 
9
9
  - `@arnilo/prism` — the runtime, contracts, registries, streaming events, CLI (including `prism init`), and the `/docs` hub. `files`: `dist` (with `!dist/__tests__` and `!dist/**/*.map` negations), `docs`, `templates`, `CHANGELOG.md`. `bin`: `prism` -> `dist/cli.js`. `sideEffects`: `["dist/cli.js"]`.
10
10
 
11
- First-party workspace packages (each has non-optional `@arnilo/prism@0.0.20` peer and `sideEffects: false`; RAG also peers on memory, and server also peers on workflows):
11
+ First-party workspace packages (each has non-optional `@arnilo/prism@0.0.23` peer and `sideEffects: false`; RAG also peers on memory, and server also peers on workflows):
12
12
 
13
13
  - `@arnilo/prism-provider-anthropic`, `@arnilo/prism-provider-google`, `@arnilo/prism-provider-openai`, `@arnilo/prism-provider-openrouter`, `@arnilo/prism-provider-kimi`, `@arnilo/prism-provider-zai`, `@arnilo/prism-provider-opencode-go`, `@arnilo/prism-provider-neuralwatt` — provider adapters.
14
14
  - `@arnilo/prism-provider-azure`, `@arnilo/prism-provider-bedrock`, `@arnilo/prism-provider-vertex` — optional enterprise-cloud adapters (Entra/IAM/ADC; separate from consumer Anthropic/Google).
@@ -22,7 +22,8 @@ First-party workspace packages (each has non-optional `@arnilo/prism@0.0.20` pee
22
22
  - `@arnilo/prism-tool-validator-json-schema` — bounded JSON Schema tool argument validation.
23
23
  - `@arnilo/prism-mcp` — MCP transport/client bridge plus explicit authorized Prism tool/command server exposure.
24
24
  - `@arnilo/prism-coding-agent` / `@arnilo/prism-coding-security` — optional host shell/filesystem tools plus approval, containment, and sandbox policy.
25
- - `@arnilo/prism-session-store-sqlite` / `@arnilo/prism-session-store-postgres` — production persistence, checkpoints, and leases.
25
+ - `@arnilo/prism-session-store-sqlite` / `@arnilo/prism-session-store-postgres` — production session/run persistence, checkpoints, and leases.
26
+ - `@arnilo/prism-enterprise-postgres` — optional PostgreSQL policy/evaluation/work-idempotency/model-router composition; separate checksum migration and explicit cleanup.
26
27
  - `@arnilo/prism-credentials-node` — encrypted-file and keychain credential storage.
27
28
  - `@arnilo/prism-workflows` — typed bounded DAG orchestration with durable approval, schedules/background runs, composition/state/replay, and multi-process coordination.
28
29
  - `@arnilo/prism-evals` — optional deterministic scorers, immutable datasets, and bounded batch experiments over `AgentRunResult`.
@@ -33,10 +34,12 @@ First-party workspace packages (each has non-optional `@arnilo/prism@0.0.20` pee
33
34
  - `@arnilo/prism-web-tools` — optional bounded host-selected Brave/Exa search and Firecrawl Markdown/schema extraction; native fetch, no vendor SDK/browser.
34
35
  - `@arnilo/prism-browser` — optional host-supplied Playwright browser tools (`browser_open`/`browser_snapshot`/`browser_act`/`browser_close`); import launches nothing; `playwright-core@1.61.0` optional peer.
35
36
  - `@arnilo/prism-ag-ui` — optional bounded AG-UI mapper/authorized Web handler/replay plus stable `./acp` sibling; root and ACP imports are inert.
37
+ - `@arnilo/prism-caveman` — optional upstream Caveman behavior integration (`upstreamPath` required; not in code/sdk/all profiles).
38
+ - `@arnilo/prism-ponytail` — optional upstream Ponytail behavior integration (peer `@dietrichgebert/ponytail` or `upstreamPath`; not in code/sdk/all profiles).
36
39
 
37
40
  ### 0.0.12 AG-UI package boundary
38
41
 
39
- `@arnilo/prism-ag-ui` is a publishable optional code package with root AG-UI exports and stable `./acp` sibling, peer `@arnilo/prism@0.0.20`, pinned `@ag-ui/core@0.0.57` / `@agentclientprotocol/sdk@1.3.0`, and no import-time network/listener/run. It is included by `@arnilo/prism-all` only—not `@arnilo/prism-code` or `@arnilo/prism-sdk`—so coding and SDK profiles stay free of UI protocol dependencies.
42
+ `@arnilo/prism-ag-ui` is a publishable optional code package with root AG-UI exports and stable `./acp` sibling, peer `@arnilo/prism@0.0.23`, pinned `@ag-ui/core@0.0.57` / `@agentclientprotocol/sdk@1.3.0`, and no import-time network/listener/run. It is included by `@arnilo/prism-all` only—not `@arnilo/prism-code` or `@arnilo/prism-sdk`—so coding and SDK profiles stay free of UI protocol dependencies.
40
43
 
41
44
  Family/profile packages (pure manifests, no code or `dist`; ship `README.md` and `CHANGELOG.md`; use exact hard `dependencies`):
42
45
 
@@ -46,7 +49,7 @@ Family/profile packages (pure manifests, no code or `dist`; ship `README.md` and
46
49
  - `@arnilo/prism-code` — base + coding-agent + coding-security + MCP; providers and persistence remain explicit choices.
47
50
  - `@arnilo/prism-sdk` — base + workflows + MCP + Node credentials + OpenTelemetry; providers and persistence remain explicit choices.
48
51
  - `@arnilo/prism-evals` remains optional and network-free by default; model judges are host callbacks and live credentialed gates run separately. `examples/evaluation-gate.ts` demonstrates non-zero threshold gating.
49
- - `@arnilo/prism-all` — every first-party package: code + SDK + providers + persistence + evals + memory/RAG + server + supervisor + web tools + browser + Phase 8 optional policy/router/enterprise providers/work-tools. **0.0.13** enrolls `@arnilo/prism-policy`, `@arnilo/prism-model-router`, `@arnilo/prism-provider-azure`, `@arnilo/prism-provider-bedrock`, `@arnilo/prism-provider-vertex`, and `@arnilo/prism-work-tools` in the umbrella only. Installation alone activates no network/listener, telemetry, database, memory, evaluation, delegation, MCP, shell, filesystem, or browser capability.
52
+ - `@arnilo/prism-all` — every first-party package: code + SDK + providers + session and enterprise PostgreSQL persistence + evals + memory/RAG + server + supervisor + web tools + browser + optional policy/router/enterprise providers/work-tools. Installation activates nothing. **0.0.13** enrolls `@arnilo/prism-policy`, `@arnilo/prism-model-router`, `@arnilo/prism-provider-azure`, `@arnilo/prism-provider-bedrock`, `@arnilo/prism-provider-vertex`, and `@arnilo/prism-work-tools` in the umbrella only. Installation alone activates no network/listener, telemetry, database, memory, evaluation, delegation, MCP, shell, filesystem, or browser capability.
50
53
 
51
54
  Profile footprint snapshot (Node 24/npm 11, lockfile graph, 2026-07-19): `base` reaches 6 first-party packages and one external dependency root (Ajv); `code` reaches 10 and three (Ajv, MCP SDK, diff); `sdk` reaches 11 and three (Ajv, MCP SDK, keyring); `all` reaches **41** first-party manifests after Phase 8 optional packages ship (graph bump Task 10); AG-UI adds only its protocol SDK dependencies while native database drivers remain all-profile-only. Native database drivers stay out of base/code/sdk; both appear only in all.
52
55
 
@@ -78,9 +81,10 @@ Consumers install the core package for the runtime and add first-party packages
78
81
  | Run the default (network-free) test suite | `npm test` |
79
82
  | Dry-run pack core + every package | `npm run pack:dry-run` |
80
83
  | Local mirror of the release verify gate | `npm run release:dry-run` |
81
- | Validate clean tag/version/ranges and reject registry collisions | `npm run release:check -- --version 0.0.20` |
82
- | Preview deterministic publish order | `npm run release:publish -- --version 0.0.20 --dry-run --allow-dirty --allow-untagged` |
83
- | Resume interrupted tagged publication | `npm run release:publish -- --version 0.0.20 --resume --report release-artifacts/publish-report.json` |
84
+ | Validate clean tag/version/ranges and reject registry collisions | `npm run release:check -- --version 0.0.23` |
85
+ | Preview deterministic publish order | `npm run release:publish -- --version 0.0.23 --dry-run --allow-dirty --allow-untagged` |
86
+ | Resume interrupted tagged publication | `npm run release:publish -- --version 0.0.23 --resume --report release-artifacts/publish-report.json` |
87
+ | Protected PostgreSQL enterprise suite | `PRISM_TEST_POSTGRES_URL="$DATABASE_URL" npm run test:postgres` |
84
88
  | Full SDK readiness gate (typecheck + offline tests + pack) | `npm run sdk:ready` |
85
89
 
86
90
  Public core import specifiers (from the root `exports` map):
@@ -117,7 +121,7 @@ A packed tarball contains only public compiled output and release files:
117
121
  - Code packages ship `README.md`, `LICENSE`, and `CHANGELOG.md`; family/profile packages ship `README.md` and `CHANGELOG.md`.
118
122
  - The core tarball additionally ships the full `docs/` directory (the docs hub) and `templates/init/` used by `prism init`.
119
123
  - `dist/cli.js` and the `bin` link in core.
120
- - **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.0.20.tgz`; first-party packages produce `arnilo-prism-provider-<name>-0.0.20.tgz` / `arnilo-prism-compaction-<name>-0.0.20.tgz` / `arnilo-prism-coding-agent-0.0.20.tgz`; family/profile packages produce `arnilo-prism-{providers,compaction,base,code,sdk,all}-0.0.20.tgz`. The CLI bin name `prism` is unaffected by the package name (`npx prism` still works; npm allows the bin field to differ from the package name).
124
+ - **Tarball filenames.** npm strips the `@scope/` prefix, so the core package `@arnilo/prism` produces a tarball named `arnilo-prism-0.0.23.tgz`; first-party packages produce `arnilo-prism-provider-<name>-0.0.23.tgz` / `arnilo-prism-compaction-<name>-0.0.23.tgz` / `arnilo-prism-coding-agent-0.0.23.tgz`; family/profile packages produce `arnilo-prism-{providers,compaction,base,code,sdk,all}-0.0.23.tgz`. The CLI bin name `prism` is unaffected by the package name (`npx prism` still works; npm allows the bin field to differ from the package name).
121
125
 
122
126
  Excluded from every tarball by `files` negation:
123
127
 
@@ -136,9 +140,9 @@ Excluded from every tarball by `files` negation:
136
140
  "name": "host-app",
137
141
  "type": "module",
138
142
  "dependencies": {
139
- "@arnilo/prism": "0.0.20",
140
- "@arnilo/prism-provider-openai": "0.0.20",
141
- "@arnilo/prism-compaction-observational-memory": "0.0.20"
143
+ "@arnilo/prism": "0.0.23",
144
+ "@arnilo/prism-enterprise-postgres": "0.0.23",
145
+ "@arnilo/prism-provider-openai": "0.0.23"
142
146
  }
143
147
  }
144
148
  ```
@@ -181,11 +185,11 @@ For SDK readiness, run the same one-command gate directly. It composes existing
181
185
  npm run sdk:ready
182
186
  ```
183
187
 
184
- Release publication derives all **44** manifests from the workspace once, validates exact `0.0.20` manifest/lockfile/internal ranges, then uses deterministic dependency order. `release:check` requires a clean commit tagged `v0.0.20` and rejects any existing registry version. `release:publish --resume` skips only registry versions whose internal dependency fingerprint matches the local manifest; conflicting versions fail closed. Each attempted package is written immediately to the JSON report, so a failed job can rerun safely. `--dry-run` performs registry availability checks and invokes `npm publish --dry-run` with explicit public access, provenance, and `latest` tag, but does not publish.
188
+ Release publication derives all **47** manifests from the workspace once, validates exact `0.0.23` manifest/lockfile/internal ranges, then uses deterministic dependency order. `release:check` requires a clean commit tagged `v0.0.23` and rejects any existing registry version. `release:publish --resume` skips only registry versions whose internal dependency fingerprint matches the local manifest; conflicting versions fail closed. Each attempted package is written immediately to the JSON report, so a failed job can rerun safely. `--dry-run` performs registry availability checks and invokes `npm publish --dry-run` with explicit public access, provenance, and `latest` tag, but does not publish.
185
189
 
186
190
  ```bash
187
- npm run release:check -- --version 0.0.20
188
- npm run release:publish -- --version 0.0.20 --dry-run --allow-dirty --allow-untagged
191
+ npm run release:check -- --version 0.0.23
192
+ npm run release:publish -- --version 0.0.23 --dry-run --allow-dirty --allow-untagged
189
193
  ```
190
194
 
191
195
  `--allow-dirty` and `--allow-untagged` exist only for local preview; real publication and CI never pass them. npm registry calls occur only in these release preflight/publication commands, never build/test/package discovery.
@@ -196,6 +200,71 @@ Optional live smoke tests stay separate from SDK readiness because they require
196
200
  PRISM_LIVE_PROVIDER_TESTS=1 npm run test --workspaces --if-present
197
201
  ```
198
202
 
203
+ ### 0.0.23 publish handoff
204
+
205
+ **Decision: GO after protected operator prerequisites below.** Release **0.0.23** (Phase 6, plan 006) adds `@arnilo/prism-enterprise-postgres`, the optional PostgreSQL composition for policy decisions, evaluation records, work-mutation claim/CAS state, and cross-replica model-router rate/budget/circuit state. The publish graph is **47 manifests** (41 code + 6 family/profile; +1 package). `@arnilo/prism-all` includes it; core remains dependency-free. See [migration](migration.md#0022--0023-production-enterprise-state-adapters-intentional-pre-10-contract-changes) and [enterprise PostgreSQL state](enterprise-postgres-state.md).
206
+
207
+ Intentional pre-1.0 migration points: work idempotency now uses `begin`/CAS transitions and never automatically replays `unknown`; durable router state requires awaited methods plus verified identity and disables `providerSource`. Policy/evaluation/work/router data remain opt-in. No Redis, queue, event delivery, exactly-once effect claim, worker, migration CLI, ORM, or new core API ships.
208
+
209
+ ```bash
210
+ git diff --check
211
+ npm ci
212
+ npm run sdk:ready
213
+ PRISM_TEST_POSTGRES_URL="$DATABASE_URL" npm run test:postgres
214
+ PRISM_TEST_POSTGRES_URL="$DATABASE_URL" node scripts/benchmark-0.0.23.mjs
215
+ node --test scripts/budget-gate.test.mjs scripts/tooling-gate.test.mjs
216
+ node scripts/scan-secrets.mjs && node scripts/verify-sbom.mjs
217
+ npm audit --audit-level=moderate
218
+ npm run release:gate
219
+ npm run release:check -- --version 0.0.23 --allow-dirty --allow-untagged --report /tmp/prism-0.0.23-preflight.json
220
+ npm run release:publish -- --version 0.0.23 --dry-run --allow-dirty --allow-untagged --report /tmp/prism-0.0.23-dry-run.json
221
+ git tag -s v0.0.23 -m "Prism 0.0.23"
222
+ git verify-tag v0.0.23
223
+ git push origin v0.0.23
224
+ ```
225
+
226
+ `npm publish --dry-run` is non-publishing and applies `publishConfig.access`; the real protected tag workflow is the only publication path, with provenance and resume report. It must run the PostgreSQL suite using a protected, disposable database URL. The recorded benchmark is local/CI comparison evidence, not a portable SLO. npm publication is immutable: a partial publish resumes from the same tag; a confirmed defect requires deprecation plus a fixed version.
227
+
228
+ ### 0.0.22 publish handoff
229
+
230
+ **Decision: GO after protected operator prerequisites below.** Release **0.0.22** (Phase 5 third-party behavior integrations, plan 005) ships `@arnilo/prism-caveman` and `@arnilo/prism-ponytail` as opt-in behavior packages (upstream Caveman/Ponytail wiring, session mode persistence, progressive disclosure + injector split). Core `@arnilo/prism` runtime is unchanged. The publish graph is **46 manifests** (+2). No intentional pre-1.0 breaks for hosts that do not install the new packages — see [migration](migration.md) under `0.0.21 → 0.0.22 third-party behavior integrations`.
231
+
232
+ ```bash
233
+ git diff --check
234
+ npm ci
235
+ npm run sdk:ready
236
+ node --test scripts/budget-gate.test.mjs
237
+ node scripts/scan-secrets.mjs && node scripts/verify-sbom.mjs
238
+ npm audit --audit-level=moderate
239
+ npm run release:gate
240
+ npm run release:check -- --version 0.0.22 --allow-dirty --allow-untagged --report /tmp/prism-0.0.22-preflight.json
241
+ npm run release:publish -- --version 0.0.22 --dry-run --allow-dirty --allow-untagged --report /tmp/prism-0.0.22-dry-run.json
242
+ git tag -s v0.0.22 -m "Prism 0.0.22"
243
+ git verify-tag v0.0.22
244
+ git push origin v0.0.22
245
+ ```
246
+
247
+ ### 0.0.21 publish handoff
248
+
249
+ **Decision: GO after protected operator prerequisites below.** Release **0.0.21** (Phase 4 coding-tool capability gaps, plan 004) ships `repo_search` `outputMode`, bounded `glob`, optional session-scoped read-before-write, bounded `delete`/`move`, and coding-security approval/sandbox wiring. The exact graph stays **44 publishable manifests**; no package added or retired. Intentional pre-1.0 breaks are documented in [migration](migration.md) under `0.0.20 → 0.0.21 coding-tool capability gaps`.
250
+
251
+ ```bash
252
+ git diff --check
253
+ npm ci
254
+ npm run sdk:ready
255
+ node --test scripts/budget-gate.test.mjs
256
+ node scripts/scan-secrets.mjs && node scripts/verify-sbom.mjs
257
+ npm audit --audit-level=moderate
258
+ npm run release:gate
259
+ npm run release:check -- --version 0.0.21 --allow-dirty --allow-untagged --report /tmp/prism-0.0.21-preflight.json
260
+ npm run release:publish -- --version 0.0.21 --dry-run --allow-dirty --allow-untagged --report /tmp/prism-0.0.21-dry-run.json
261
+ git tag -s v0.0.21 -m "Prism 0.0.21"
262
+ git verify-tag v0.0.21
263
+ git push origin v0.0.21
264
+ ```
265
+
266
+ The dry-run checks every registry collision and executes npm's non-publishing tarball validation for each dependency-ordered manifest. The protected tag workflow alone publishes through `npm run release:publish -- --version "${GITHUB_REF_NAME#v}" --resume --report release-artifacts/publish-report.json`; re-run a failed job for the same tag. `npm audit signatures --json --include-attestations` and artifact checksums remain post-publish checks.
267
+
199
268
  ### 0.0.20 publish handoff
200
269
 
201
270
  **Decision: GO after protected operator prerequisites below.** Release **0.0.20** (Phase 3 skills and context progressive disclosure, plan 003) ships progressive skill catalog assembly (`skillsDisclosure`), session `load_skill`, empty `SkillRegistry` default with `activateAllSkills` migration opt-in, priority-aware context budget demotion, and optional `toolResultFold`. The exact graph stays **44 publishable manifests**; no package added or retired. Intentional pre-1.0 breaks are documented in [migration](migration.md) under `0.0.19 → 0.0.20 skills and context progressive disclosure`.
@@ -835,8 +904,8 @@ npm publication is not transactional and published versions are immutable. Parti
835
904
 
836
905
  ## Extension and configuration notes
837
906
 
838
- - **Required `@arnilo/prism` peer.** Every first-party code package declares a non-optional `@arnilo/prism@0.0.20` peer (`peerDependenciesMeta` must not mark `@arnilo/prism` optional; other peers such as `playwright-core` may be optional). The range stays pinned to `0.0.20` for the current 0.x release and will widen to `^1.0.0` at the 1.x stable release. Inside the workspace each package also declares `"@arnilo/prism": "file:../.."` in `devDependencies` so `npm install` resolves the peer locally; that devDependency is stripped from consumer installs and is not a runtime dependency.
839
- - **Public access.** All 43 manifests (37 code packages + 6 family/profile packages) declare `"publishConfig": { "access": "public" }`; the publisher also passes `--access public` explicitly because scoped packages otherwise default to restricted on first publish.
907
+ - **Required `@arnilo/prism` peer.** Every first-party code package declares a non-optional `@arnilo/prism@0.0.23` peer (`peerDependenciesMeta` must not mark `@arnilo/prism` optional; other peers such as `playwright-core` may be optional). The range stays pinned to `0.0.23` for the current 0.x release and will widen to `^1.0.0` at the 1.x stable release. Inside the workspace each package also declares `"@arnilo/prism": "file:../.."` in `devDependencies` so `npm install` resolves the peer locally; that devDependency is stripped from consumer installs and is not a runtime dependency.
908
+ - **Public access.** All 47 manifests (41 code packages + 6 family/profile packages) declare `"publishConfig": { "access": "public" }`; the publisher also passes `--access public` explicitly because scoped packages otherwise default to restricted on first publish.
840
909
  - **Map retention knob.** Source maps are emitted locally but stripped from tarballs by `!dist/**/*.map`. Removing that `files` negation ships maps in releases (larger tarballs, better consumer stack traces).
841
910
  - **Release workflow.** `.github/workflows/release.yml` has six jobs. `verify` runs network-free SDK readiness on Node 24; `node20-compat` builds/imports every public root `exports` default target on Node 20 for declared `engines.node >=20` (docs examples need Node >=22.6 native TypeScript stripping); `postgres-integration` uses `pgvector/pgvector:pg16`; `supply-chain` runs high-severity audit, SPDX/license policy, and tracked-source secret scanning; and tag-only `codeql-release` runs SAST. Tag-only `publish` needs all five gates, preserves clean exact-tag/version/topological publication, and alone receives `NPM_TOKEN`, `id-token: write`, and `attestations: write`. Before npm publish it packs all current tarballs, generates checksums plus SPDX, scans unpacked public artifacts, creates GitHub attestations for tarballs and SBOM, then retains artifacts for 30 days. Registry state remains the resumable journal. Local `npm run release:dry-run` remains network-free SDK readiness; local PostgreSQL coverage is `PRISM_TEST_POSTGRES_URL=... npm run test:postgres`.
842
911
  - **Adding a package.** New workspace packages are picked up automatically by `npm run build --workspaces`, `npm test --workspaces`, `npm run pack:dry-run`, the packaging guard (`src/__tests__/packaging.test.ts`), and the install-smoke test (`src/__tests__/install-smoke.test.ts`) via the workspace glob; add the package to both tests' config arrays for explicit per-package assertions.
@@ -950,13 +1019,14 @@ Every release gate maps to an exact enforcement test or command, so the checklis
950
1019
  | Gate | Enforcement |
951
1020
  | --- | --- |
952
1021
  | Docs coverage for persistence/runtime/migration surfaces | `docs.test.ts` enrolls every API page in `apiPages` (heading + index-link + bare-specifier + secret-scan checks); dedicated section assertions pin `database-persistence.md`, `runs-and-usage.md`, `session-stores-and-branching.md`, `migration.md`, `agent-definitions.md`, `performance.md`, and the Phase 41 `external_app_example_*` / `phase41_external_app_surfaces_*` gates. |
953
- | Package exports/subpaths resolve to built output | `public-export-contract.test.ts` asserts every `exports`/`main`/`types`/`bin` target resolves to a built file under `dist/` with a sibling `.d.ts`, and no target escapes `dist/` (no `src/` or `examples/` leak). CI `node20-compat` also imports every public root `exports` default target on Node 20. |
1022
+ | Package exports/subpaths resolve to built output | `public-export-contract.test.ts` asserts every `exports`/`main`/`types`/`bin` target resolves to a built file under `dist/` with a sibling `.d.ts` (`dist/index.js` + `dist/index.d.ts` for a root package), and no target escapes `dist/` (no `src/` or `examples/` leak). CI `node20-compat` also imports every public root `exports` default target on Node 20. |
954
1023
  | Public-API drift | `public-export-contract.test.ts` `phase39_public_protocol_exports_and_types_do_not_drift` pins the runtime protocol (`providerToolCallDelta`, `ToolCallDeltaContent`), the `/testing/provider-conformance` subpath shape, and the observational-memory runtime `.d.ts` surface. |
955
1024
  | Root SDK export surface freeze | `public-export-contract.test.ts` `root export surface is frozen` snapshots every value and type export of `src/index.ts` (107 value + 69 type) so any add/remove is a deliberate test update; `every frozen value export resolves at runtime` rebuilds `dist/index.js` and asserts each value export is present (catches build drift), and `every frozen type export appears in the built type declarations` asserts each type export is in `dist/index.d.ts`. |
956
1025
  | Examples compile and are listed; runnable demos execute | `npm run typecheck` runs `tsc -p examples --noEmit`; `docs.test.ts` checks every `examples/*.ts` file is listed in `examples/README.md`, then runs demos offline and scans output for secrets. |
957
1026
  | Examples run to completion with no secret leakage | `docs.test.ts` `examples_demos_run_to_completion_and_emit_no_secret` runs each demo (Node strips TypeScript types natively) with exit-0 and real-secret scans; `external_app_example_*` pins the DB-backed adapter reference exercising the `RunLedger`, branch-handle checkout, fork, and prior-run resume. |
958
- | Tarball excludes built tests, source maps, and source | `packaging.test.ts` rejects `dist/__tests__/`, `*.map`, `src/`, `plans/`, and internal files; confirms every package ships README/changelog (and code packages ship LICENSE), core ships docs + CLI, exported targets exist (`dist/index.js` + `dist/index.d.ts` for NeuralWatt), and `prism-all` transitively reaches all 32 published first-party manifests. |
1027
+ | Tarball excludes built tests, source maps, and source | `packaging.test.ts` rejects `dist/__tests__/`, `*.map`, `src/`, `plans/`, and internal files; confirms every package ships README/changelog (and code packages ship LICENSE), core ships docs + CLI, and every export target exists. `prism-all` reaches every current publishable package except the deliberate Caveman/Ponytail opt-outs. |
959
1028
  | NeuralWatt package/docs/examples release gate | `packaging.test.ts` pins `@arnilo/prism-provider-neuralwatt` package exports/type declarations and `@arnilo/prism-providers`/`@arnilo/prism-all` membership; `docs.test.ts` asserts `docs/index.md` links `providers/neuralwatt.md` and `provider-caching.md`, and that `examples/cache-aware-prompt-assembly.ts` plus `examples/neuralwatt-agent-run.ts` exist and are listed. |
1029
+ | Enterprise PostgreSQL package/docs/example gate | Packaging/install/public-contract tests include `@arnilo/prism-enterprise-postgres`; `docs.test.ts` pins its API page, four-store migration/ownership/unknown-outcome/async-router guidance, and `examples/enterprise-postgres-state.ts`; `npm run test:postgres` exercises migration, restart, contention, and cleanup with an explicit database URL. |
960
1030
  | Version graph and resumable publication | `release.test.ts` covers exact package/lock/range validation, topological order, registry collisions, dry-run, interrupted reports/resume, clean tagged git state, provenance/public/tag arguments, and token-safe errors. `release:check` and `release:publish` derive the workspace graph without a manual package list. |
961
1031
  | Pre-publish compatibility gates | `release:gate` (in `sdk:ready`) fails on removed/changed `.d.ts` exports vs `scripts/compat-baseline/` (unless `--allow-break` + migration note), version-range/lockfile drift, and tarball deny-list violations (`plans/`, `code-reviews/`, `docs/review-coverage-*`, `*.map`, `__tests__/`); unit-tested in `scripts/release-gate.test.mjs`. |
962
1032
  | Formatting, linting, and coverage thresholds | `npm run lint` and `npm run format:check` run Biome (single root `biome.json`, workspaces inherit) and fail on any lint error or unformatted file; `npm run test:coverage` uses Node's built-in `--experimental-test-coverage` with enforced minimums (lines 60 / functions 70 / branches 75) and no third-party service. All three run inside `sdk:ready`. |
@@ -89,7 +89,22 @@ Startup: M365 `version --output json`; GWS `--version`. Forbidden: `login`, `set
89
89
 
90
90
  ### Draft → approve → execute
91
91
 
92
- Mutation tools (`*_mail_draft_send`, `*_draft_*`) create an in-adapter draft and return `{ status: "pending_approval", draftId }` until `approval.isApproved` is true. Retries with the same `idempotencyKey` return `{ status: "duplicate" }` after first successful execute.
92
+ Mutation tools (`*_mail_draft_send`, `*_draft_*`) create an in-adapter draft and return `{ status: "pending_approval", draftId }` until `approval.isApproved` is true.
93
+
94
+ ### Durable idempotency (0.0.23)
95
+
96
+ `createMemoryIdempotencyStore()` remains for tests and a single process. For production replicas, use `createPostgresEnterpriseState({ pool }).workIdempotency`. It changes the old `get`/`put` replay abstraction to explicit async state transitions:
97
+
98
+ | Observable state | Meaning / host action |
99
+ | --- | --- |
100
+ | absent | `begin()` atomically acquires the first claim. |
101
+ | `in_progress` | Another worker owns the claim; do not dispatch a second connector effect. |
102
+ | `completed` | Return the bounded stored `{ draftId, resourceId? }` duplicate summary. |
103
+ | `failed_retryable` | A later `begin()` may reclaim it within the capped attempt policy. |
104
+ | `failed_terminal` | Do not retry; surface the bounded failure. |
105
+ | `unknown` | External result is ambiguous; reconcile with the connector/operator through `resolveUnknown()`. Never auto-replay. |
106
+
107
+ Call `begin({ identity, key, op })` **before** the external effect. After it succeeds, call `complete`, `fail`, or `markUnknown` with the returned claim token and version. The connector effect stays outside the database transaction, so this is claim-before-effect/deduplication—not exactly-once delivery. Claims default to 15 minutes (hard 60 minutes); expired claims transition to `unknown`; attempts default to 3 (hard 5). Stored rows contain no request body, token, raw provider response, or unrestricted payload.
93
108
 
94
109
  ## Limits
95
110
 
@@ -111,6 +126,7 @@ Mutation tools (`*_mail_draft_send`, `*_draft_*`) create an in-adapter draft and
111
126
 
112
127
  ## Related
113
128
 
129
+ - [Enterprise PostgreSQL state](enterprise-postgres-state.md): durable claim/CAS store, cleanup, and operator reconciliation.
114
130
  - [Work connectors](work-connectors.md)
115
131
  - [Agent identity](agent-identity.md)
116
132
  - [Host security](host-security.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arnilo/prism",
3
- "version": "0.0.20",
3
+ "version": "0.0.23",
4
4
  "description": "Agent harness for AI providers, agents, sessions, and tools.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -123,6 +123,7 @@
123
123
  "packages/work-tools",
124
124
  "packages/policy",
125
125
  "packages/model-router",
126
+ "packages/enterprise-postgres",
126
127
  "packages/browser",
127
128
  "packages/ag-ui",
128
129
  "packages/prism-*"
@@ -138,7 +139,7 @@
138
139
  "format": "biome format --write .",
139
140
  "format:check": "biome format .",
140
141
  "pack:dry-run": "npm pack --dry-run && npm run pack:dry-run --workspaces --if-present",
141
- "test:postgres": "npm run test:postgres --workspace @arnilo/prism-session-store-postgres && npm run test:postgres --workspace @arnilo/prism-memory",
142
+ "test:postgres": "node scripts/require-postgres-url.mjs && npm run test:postgres --workspace @arnilo/prism-session-store-postgres && npm run test:postgres --workspace @arnilo/prism-memory && npm run test:postgres --workspace @arnilo/prism-enterprise-postgres",
142
143
  "release:dry-run": "npm run sdk:ready",
143
144
  "release:check": "node scripts/release.mjs check",
144
145
  "release:publish": "node scripts/release.mjs publish",