ds4-context-engine 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DS4 Context Engine contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,399 @@
1
+ # DS4 Context Engine for Pi
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
4
+ [![Pi 0.84.3](https://img.shields.io/badge/Pi-0.84.3-blue.svg)](https://github.com/earendil-works/pi)
5
+ [![Node.js >=22.19](https://img.shields.io/badge/Node.js-%3E%3D22.19-339933.svg)](https://nodejs.org/)
6
+
7
+ DS4 Context Engine is a non-destructive, provider-independent context management layer for [Pi](https://github.com/earendil-works/pi). It keeps Pi's native JSONL session as the canonical history and builds a smaller, inspectable, model-aware working context for each model call.
8
+
9
+ ```text
10
+ complete Pi JSONL history
11
+ ↓
12
+ DS4 planning, retrieval, summaries and policy
13
+ ↓
14
+ bounded active context with provenance
15
+ ↓
16
+ Pi provider
17
+ ```
18
+
19
+ > **Project status:** M0–M13 are implemented. The Pi adapter and standalone `ds4-context-core` package are version `0.1.0`; the adapter targets Pi `0.84.3`.
20
+
21
+ ## Why DS4
22
+
23
+ Long coding sessions accumulate old decisions, repeated context, large tool outputs and project state faster than any model context window can hold them. DS4 separates durable history from the model's current working set.
24
+
25
+ It provides:
26
+
27
+ - deterministic token budgeting with soft and hard input limits;
28
+ - preservation of the current request, recent turns and atomic tool call/result groups;
29
+ - exact and FTS5 historical retrieval with source provenance;
30
+ - trust-gated project indexing, Git-aware invalidation and bounded source snippets;
31
+ - hierarchical, validated, non-destructive compaction summaries;
32
+ - persistent pins and append-only durable memory stored canonically in Pi JSONL;
33
+ - content-addressed storage and bounded references for large tool results;
34
+ - privacy classifications, secret redaction and provider-specific allow rules;
35
+ - model-specific calibration and adaptive context allocation;
36
+ - optional verified continuation for eligible OpenAI Responses profiles;
37
+ - an inspectable Context Manifest explaining included and excluded material;
38
+ - fail-open recovery to Pi's native context path for operational failures.
39
+
40
+ ## Architectural guarantees
41
+
42
+ 1. **Pi JSONL remains canonical.** DS4 never replaces Pi's session format.
43
+ 2. **SQLite is disposable.** It contains derived projections and can be rebuilt from canonical sources.
44
+ 3. **Compaction is non-destructive.** Raw history is not deleted or rewritten.
45
+ 4. **Provenance is preserved.** Retrieved and summarized context identifies its source.
46
+ 5. **Tool groups remain atomic.** Tool calls are not separated from their results.
47
+ 6. **Provider state is optional.** Continuation handles and cache state are never canonical.
48
+ 7. **Operational failures fail open.** Pi can continue with its native context behavior.
49
+ 8. **Enabled privacy enforcement fails closed.** Restricted content is replaced or the provider payload is rejected instead of being leaked.
50
+
51
+ ## Requirements
52
+
53
+ - [Pi](https://github.com/earendil-works/pi) `0.84.3`
54
+ - Node.js `22.19.0` or newer
55
+ - SQLite support provided by Node's built-in `node:sqlite`
56
+
57
+ Pi is intentionally pinned until extension contract tests validate a newer release.
58
+
59
+ ## Installation
60
+
61
+ Pi packages execute with the user's full permissions. Review and trust the source before installing this or any other extension.
62
+
63
+ ### From GitHub
64
+
65
+ ```bash
66
+ pi install git:github.com/Alucard24/ds4-context-engine
67
+ ```
68
+
69
+ To try it for one run without adding it to settings:
70
+
71
+ ```bash
72
+ pi -e git:github.com/Alucard24/ds4-context-engine
73
+ ```
74
+
75
+ ### From npm
76
+
77
+ Install the public npm package with:
78
+
79
+ ```bash
80
+ pi install npm:ds4-context-engine
81
+ ```
82
+
83
+ ### Local checkout
84
+
85
+ ```bash
86
+ git clone https://github.com/Alucard24/ds4-context-engine.git
87
+ cd ds4-context-engine
88
+ npm ci
89
+ npm run check
90
+ pi install -l .
91
+ ```
92
+
93
+ For extension development without installing the package:
94
+
95
+ ```bash
96
+ pi -e ./src/extension/index.ts
97
+ ```
98
+
99
+ Restart Pi or run `/reload` after installing or changing the extension.
100
+
101
+ ## Quick start
102
+
103
+ DS4 starts in managed mode with conservative defaults. No configuration file is required.
104
+
105
+ After loading the extension, inspect its state:
106
+
107
+ ```text
108
+ /context status
109
+ /context tokens
110
+ /context health
111
+ ```
112
+
113
+ Global configuration is loaded from:
114
+
115
+ ```text
116
+ ~/.pi/agent/ds4-context.json
117
+ ```
118
+
119
+ A trusted project can override it with:
120
+
121
+ ```text
122
+ .pi/ds4-context.json
123
+ ```
124
+
125
+ Use observer mode as a pass-through rollback while retaining diagnostics:
126
+
127
+ ```json
128
+ {
129
+ "context": {
130
+ "mode": "observer"
131
+ }
132
+ }
133
+ ```
134
+
135
+ Disable the extension's behavior without uninstalling it:
136
+
137
+ ```json
138
+ {
139
+ "enabled": false
140
+ }
141
+ ```
142
+
143
+ Project configuration and project source indexing are disabled when Pi reports the project as untrusted.
144
+
145
+ ## Commands
146
+
147
+ ### Inspection
148
+
149
+ | Command | Purpose |
150
+ | --- | --- |
151
+ | `/context` or `/context status` | Runtime, session, planner and subsystem status |
152
+ | `/context tokens` | Token budget and active-context composition |
153
+ | `/context manifest` | Latest Context Manifest |
154
+ | `/context explain` | Human-readable planning explanation |
155
+ | `/context included` | Items selected for the latest model call |
156
+ | `/context excluded` | Items excluded from the latest model call |
157
+ | `/context summaries` | Hierarchical summary graph diagnostics |
158
+ | `/context retrieved` | Historical retrieval diagnostics |
159
+ | `/context project` | Project index and retrieval status |
160
+ | `/context privacy` | Classification and provider-policy status |
161
+ | `/context model` | Active model profile and calibration |
162
+ | `/context continuation` | Native continuation decisions and counters |
163
+ | `/context artifacts` | Artifact storage and integrity status |
164
+ | `/context compaction` | Last compaction status |
165
+ | `/context compact-preview` | Preview compaction diagnostics |
166
+ | `/context health` | SQLite and subsystem health checks |
167
+ | `/context rebuild-index` | Rebuild derived state from canonical sources |
168
+
169
+ ### Pins and durable memory
170
+
171
+ ```text
172
+ /context pins
173
+ /context pin [--scope session|branch|project] [--classification LEVEL] <content>
174
+ /context unpin PIN_ID [reason]
175
+
176
+ /context memory
177
+ /context memory list
178
+ /context memory add [--scope session|project] [--key KEY] [--classification LEVEL] <claim>
179
+ /context memory supersede MEMORY_ID [--source ID,ID] <new claim>
180
+ /context memory invalidate MEMORY_ID [reason]
181
+ /context memory expire MEMORY_ID [reason]
182
+ ```
183
+
184
+ Valid privacy classifications are `normal`, `internal`, `sensitive` and `local-only`.
185
+
186
+ ## Configuration reference
187
+
188
+ The following example shows the main configuration groups. Omitted values use the defaults in [`packages/core/src/config/config.ts`](packages/core/src/config/config.ts).
189
+
190
+ ```json
191
+ {
192
+ "enabled": true,
193
+ "context": {
194
+ "mode": "managed",
195
+ "targetFillRatio": 0.7,
196
+ "softLimitRatio": 0.8,
197
+ "hardLimitRatio": 0.9,
198
+ "minimumOutputReserve": 8192,
199
+ "preferredOutputReserve": 32768,
200
+ "recentTailTokens": 64000,
201
+ "maxPinnedTokens": 16000,
202
+ "maxMemoryTokens": 8000,
203
+ "maxRetrievedHistoryTokens": 16000,
204
+ "maxProjectTokens": 20000,
205
+ "maxSummaryTokens": 12000
206
+ },
207
+ "retrieval": {
208
+ "exact": true,
209
+ "fts": true,
210
+ "semantic": false,
211
+ "maxResults": 12
212
+ },
213
+ "project": {
214
+ "enabled": true,
215
+ "maxFiles": 10000,
216
+ "maxFileBytes": 512000,
217
+ "maxTotalBytes": 50000000,
218
+ "snippetLines": 80,
219
+ "snippetOverlapLines": 12,
220
+ "maxResults": 8
221
+ },
222
+ "memory": {
223
+ "enabled": true,
224
+ "maxPinChars": 4000,
225
+ "maxClaimChars": 2000,
226
+ "maxResults": 12
227
+ },
228
+ "artifacts": {
229
+ "enabled": true,
230
+ "maxInlineToolResultChars": 12000,
231
+ "maxArtifactBytes": 100000000,
232
+ "maxSearchBytes": 50000000,
233
+ "excerptChars": 6000,
234
+ "maxSearchMatches": 12,
235
+ "storeLargeOutputs": true
236
+ },
237
+ "compaction": {
238
+ "enabled": true,
239
+ "mode": "hierarchical",
240
+ "validate": true,
241
+ "segmentTargetTokens": 30000,
242
+ "preserveRecentVerbatim": true
243
+ },
244
+ "privacy": {
245
+ "enabled": false,
246
+ "defaultClassification": "normal",
247
+ "localProviders": ["faux", "ollama", "llama-cpp", "lmstudio"],
248
+ "remoteDefaultAllowed": ["normal", "internal"],
249
+ "remoteProviders": {
250
+ "openrouter": ["normal"]
251
+ },
252
+ "redactSecrets": true
253
+ },
254
+ "modelAwareness": {
255
+ "enabled": true,
256
+ "calibrationWindow": 24,
257
+ "minimumCalibrationSamples": 3,
258
+ "calibrationRatioLowerBound": 0.5,
259
+ "calibrationRatioUpperBound": 2.0,
260
+ "overrides": {
261
+ "openrouter/vendor/model": {
262
+ "contextWindow": 200000,
263
+ "maxRetrievedHistoryTokens": 12000
264
+ }
265
+ }
266
+ },
267
+ "nativeContinuation": {
268
+ "enabled": false,
269
+ "allowProviderStorage": false,
270
+ "profiles": ["openai/*"],
271
+ "maxStateAgeMs": 1800000,
272
+ "retryManagedReplay": true
273
+ },
274
+ "diagnostics": {
275
+ "storeContextManifest": true,
276
+ "storeFullRenderedContext": false,
277
+ "logLevel": "info"
278
+ },
279
+ "storage": {
280
+ "databasePath": "ds4-context/context.db"
281
+ }
282
+ }
283
+ ```
284
+
285
+ Invalid or unknown values are ignored with a warning. Model overrides merge deterministically from `*` to `provider/*` to an exact `provider/model` profile.
286
+
287
+ ## Privacy and provider storage
288
+
289
+ Privacy enforcement is disabled by default and must be configured for the providers you use. Unknown providers are treated as remote unless explicitly listed as local. `local-only` content is never permitted by a remote allow rule.
290
+
291
+ Native continuation is also disabled by default. Enabling it requires both explicit storage consent and an exact or provider-scoped profile:
292
+
293
+ ```json
294
+ {
295
+ "nativeContinuation": {
296
+ "enabled": true,
297
+ "allowProviderStorage": true,
298
+ "profiles": ["openai/*"]
299
+ }
300
+ }
301
+ ```
302
+
303
+ Eligible OpenAI Responses requests then set `store: true`. Review the provider's retention policy before enabling this option. DS4 keeps response handles only in volatile memory, verifies exact managed prefixes before reuse and retries once with a full managed replay when recognized continuation state is stale.
304
+
305
+ See [`docs/PRIVACY.md`](docs/PRIVACY.md) and [`docs/NATIVE_CONTINUATION.md`](docs/NATIVE_CONTINUATION.md).
306
+
307
+ ## Storage and recovery
308
+
309
+ By default, derived state is stored below Pi's agent directory:
310
+
311
+ ```text
312
+ ~/.pi/agent/ds4-context/
313
+ ├── context.db
314
+ └── artifacts/
315
+ ```
316
+
317
+ The database contains rebuildable indexes, summary metadata, manifests, project projections and calibration data. Canonical memory and pin mutations remain append-only entries in Pi JSONL. Project files remain canonical for project knowledge. Complete tool results remain in Pi JSONL while the artifact store keeps verified, content-addressed copies for bounded retrieval.
318
+
319
+ To validate or rebuild derived state:
320
+
321
+ ```text
322
+ /context health
323
+ /context rebuild-index
324
+ ```
325
+
326
+ Deleting DS4's database must not alter a Pi session or project, although derived indexes and calibration data will be regenerated.
327
+
328
+ ## Development
329
+
330
+ ```bash
331
+ npm ci
332
+ npm run build:core
333
+ npm run typecheck
334
+ npm test
335
+ npm run check
336
+ npm run pack:check
337
+ npm pack --dry-run
338
+ npm pack --dry-run --workspace ds4-context-core
339
+ ```
340
+
341
+ The test suite covers configuration, migrations, canonical JSONL projection, planning, atomic tool groups, retrieval, compaction, project knowledge, artifacts, memory, privacy, model awareness, continuation, the portable-core dependency boundary and Pi extension lifecycle behavior. The package check also builds both tarballs, installs them in a clean temporary consumer and starts the packaged extension with isolated Pi RPC state.
342
+
343
+ ### Portable core
344
+
345
+ `ds4-context-core` is a compiled ESM package with no Pi dependency. It owns runtime-neutral policy, storage and projections; agent adapters translate native sessions and lifecycle hooks at the boundary. The root `ds4-context-engine` package is the Pi adapter and depends one-way on the core workspace.
346
+
347
+ ### Repository layout
348
+
349
+ ```text
350
+ packages/core/src portable policy, planning, compaction, retrieval and storage
351
+ src/pi-adapter Pi JSONL projection, summary completion and provider integration
352
+ src/extension Pi hooks, commands and fail-open orchestration
353
+ tests core contract, unit, integration, golden and benchmark coverage
354
+ scripts package and release-readiness checks
355
+ .github/workflows continuous integration
356
+ ```
357
+
358
+ ## Documentation
359
+
360
+ - [Architecture](docs/ARCHITECTURE.md)
361
+ - [Context planner](docs/CONTEXT_PLANNER.md)
362
+ - [Context Manifest](docs/CONTEXT_MANIFEST.md)
363
+ - [Compaction](docs/COMPACTION.md)
364
+ - [Summary graph](docs/SUMMARY_GRAPH.md)
365
+ - [Historical retrieval](docs/RETRIEVAL.md)
366
+ - [Project knowledge](docs/PROJECT_KNOWLEDGE.md)
367
+ - [Artifacts](docs/ARTIFACTS.md)
368
+ - [Memory and pins](docs/MEMORY_AND_PINS.md)
369
+ - [Privacy](docs/PRIVACY.md)
370
+ - [Model awareness](docs/MODEL_AWARENESS.md)
371
+ - [Native continuation](docs/NATIVE_CONTINUATION.md)
372
+ - [Portable core](docs/PORTABLE_CORE.md)
373
+ - [Storage](docs/STORAGE.md)
374
+ - [Release process](docs/RELEASING.md)
375
+ - [Architecture decisions](docs/ADR/README.md)
376
+ - [Original development plan](DS4_Context_Engine_Extension_Piano_Sviluppo.md)
377
+
378
+ ## Roadmap
379
+
380
+ The original M0–M13 roadmap is complete. `ds4-context-core` now contains the compiled Pi-independent implementation, while runtime-specific behavior remains in the Pi adapter.
381
+
382
+ Possible later work includes additional agent-runtime adapters, semantic retrieval, richer symbol indexing, cross-session project memory, context quality metrics, learned ranking and local KV integration. These are not required by the current MVP.
383
+
384
+ ## Contributing
385
+
386
+ Issues and focused pull requests are welcome. Before submitting a change:
387
+
388
+ 1. preserve Pi JSONL as canonical history;
389
+ 2. keep SQLite and artifacts rebuildable;
390
+ 3. preserve provenance and atomic tool groups;
391
+ 4. retain strict compaction validation and safe fallback behavior;
392
+ 5. add or update tests;
393
+ 6. run `npm run check`, `npm run pack:check` and `git diff --check`.
394
+
395
+ Please include reproduction steps for bugs and avoid attaching real session files, credentials or private provider payloads.
396
+
397
+ ## License
398
+
399
+ [MIT](LICENSE)
@@ -0,0 +1,60 @@
1
+ # Architecture Decision Records
2
+
3
+ The initial decisions from the development plan are accepted:
4
+
5
+ | ADR | Decision | Status |
6
+ |---|---|---|
7
+ | 001 | Pi remains the agent runtime | Accepted |
8
+ | 002 | Pi JSONL is the canonical source; SQLite is rebuildable | Accepted |
9
+ | 003 | Compaction creates derived artifacts and never destroys raw history | Accepted |
10
+ | 004 | The Pi `context` hook is the primary integration point | Accepted |
11
+ | 005 | Lexical and exact retrieval precede semantic retrieval | Accepted |
12
+ | 006 | Provider continuation/cache state is non-canonical | Accepted |
13
+ | 007 | Core policy is published separately from the Pi adapter | Accepted |
14
+ | 008 | Fail open to Pi's native behavior | Accepted |
15
+ | 009 | Use built-in `node:sqlite` behind a storage adapter for M0 | Accepted |
16
+ | 010 | Scope Pi's short entry IDs by session in the derived database | Accepted |
17
+ | 011 | Validate append-only checkpoints by byte offset and physical-line hash | Accepted |
18
+ | 012 | Persist Context Manifests without prompt or message content | Accepted |
19
+ | 013 | Correlate each assistant response with the most recent pending manifest | Accepted |
20
+ | 014 | Use deterministic whole-turn fitting and fail open on unsafe plans | Accepted |
21
+ | 015 | Treat `ds4:pin` labels on active entries as mandatory atomic groups | Accepted |
22
+ | 016 | Preserve Pi's compaction cut point and replace only summary generation | Accepted |
23
+ | 017 | Reject invalid custom summaries and fall back to Pi's generator | Accepted |
24
+ | 018 | Store summary provenance in canonical Pi details and derived SQLite rows | Accepted |
25
+ | 019 | Keep summary nodes immutable and represent replacement only with parent-child edges | Accepted |
26
+ | 020 | Resolve the aggregation predecessor from Pi's active branch, never session-global recency | Accepted |
27
+ | 021 | Embed newly created non-active nodes in Pi details for complete graph reconstruction | Accepted |
28
+ | 022 | Correlate compaction commits by pending summary ID, not duplicate summary text | Accepted |
29
+ | 023 | Rank literal identifiers and phrases ahead of FTS; semantic retrieval stays optional | Accepted |
30
+ | 024 | Inject automatic historical evidence only from Pi's active branch | Accepted |
31
+ | 025 | Treat retrieved text as JSON-quoted data and discard it on planner fallback | Accepted |
32
+ | 026 | Never enumerate or query project knowledge without Pi project trust | Accepted |
33
+ | 027 | Validate live file hashes before injection and retain prior snippets only as stale derived rows | Accepted |
34
+ | 028 | Treat project source as JSON-quoted untrusted data and discard it on planner fallback | Accepted |
35
+ | 029 | Record Git revision metadata but keep live files, not Git or SQLite, canonical | Accepted |
36
+ | 030 | Keep full tool results canonical in Pi JSONL; condense only provider-facing copies | Accepted |
37
+ | 031 | Address artifact objects by verified SHA-256 and separate deduplicated bytes from source references | Accepted |
38
+ | 032 | Permit artifact search only by explicit current-branch reference with bounded redacted literal excerpts | Accepted |
39
+ | 033 | Disable artifact offload for observer and ephemeral sessions | Accepted |
40
+ | 034 | Persist memory and pin mutations as versioned Pi custom entries; keep SQLite materialized | Accepted |
41
+ | 035 | Require manual creation and explicit supersession; never silently overwrite durable claims | Accepted |
42
+ | 036 | Make branch pins conditional on their creation leaf appearing in Pi's active branch | Accepted |
43
+ | 037 | Treat pins as user-confirmed mandatory context and memory as quoted historical data | Accepted |
44
+ | 038 | Share project-scoped state only for the same trusted canonical project path | Accepted |
45
+ | 039 | Disable durable memory and pin mutation for observer and ephemeral sessions | Accepted |
46
+ | 040 | Treat every provider as remote unless its exact ID is explicitly configured local | Accepted |
47
+ | 041 | Reject `local-only` in all remote allow rules and prevent marker-based downgrades | Accepted |
48
+ | 042 | Sanitize native context before planning and omit prohibited synthetic source groups whole | Accepted |
49
+ | 043 | Recheck provider-specific serialization in `before_provider_request` without logging payloads | Accepted |
50
+ | 044 | Fail closed with placeholders/empty payload when privacy enforcement fails | Accepted |
51
+ | 045 | Persist pin/memory/artifact/summary classifications through their canonical or rebuildable metadata | Accepted |
52
+ | 046 | Load DS4 last when later extensions could replace provider payloads | Accepted |
53
+ | 047 | Keep native continuation disabled until provider storage is explicitly acknowledged | Accepted |
54
+ | 048 | Wrap only explicitly profiled OpenAI Responses providers and delegate serialization/transport to Pi | Accepted |
55
+ | 049 | Send a continuation delta only after exact request-option and request-plus-response prefix hashes match | Accepted |
56
+ | 050 | Retry rejected stale continuation state once with the complete managed replay before exposing output | Accepted |
57
+ | 051 | Keep continuation handles volatile and exclude them from manifests, logs, and DS4 persistence | Accepted |
58
+ | 052 | Compile `ds4-context-core` as ESM and keep the Pi adapter dependency one-way | Accepted |
59
+
60
+ Each decision will receive a dedicated record when implementation pressure introduces alternatives or consequences not already covered by the development plan.