@gmickel/gno 1.20.0 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +29 -5
  2. package/assets/skill/SKILL.md +46 -15
  3. package/package.json +2 -1
  4. package/spec/cli.md +144 -0
  5. package/spec/db/schema.sql +170 -0
  6. package/spec/evals-agentic.md +48 -0
  7. package/spec/mcp.md +22 -0
  8. package/spec/output-schemas/capsule-reverified-event.schema.json +47 -0
  9. package/spec/output-schemas/changes.schema.json +280 -0
  10. package/spec/output-schemas/document-diff.schema.json +185 -0
  11. package/spec/output-schemas/impact.schema.json +122 -0
  12. package/spec/output-schemas/publish-artifact.schema.json +284 -0
  13. package/spec/output-schemas/saved-capsule-list.schema.json +16 -0
  14. package/spec/output-schemas/saved-capsule-registration.schema.json +172 -0
  15. package/spec/output-schemas/saved-capsule-reverification.schema.json +59 -0
  16. package/spec/output-schemas/saved-capsule-unwatch.schema.json +16 -0
  17. package/spec/output-schemas/saved-capsule-watch.schema.json +17 -0
  18. package/src/cli/commands/changes.ts +160 -0
  19. package/src/cli/commands/context-saved.ts +189 -0
  20. package/src/cli/options.ts +8 -0
  21. package/src/cli/program.ts +195 -0
  22. package/src/core/capsule-registry.ts +279 -0
  23. package/src/core/capsule-reverification-scheduler.ts +218 -0
  24. package/src/core/capsule-reverification.ts +289 -0
  25. package/src/core/change-diff.ts +182 -0
  26. package/src/core/change-journal.ts +228 -0
  27. package/src/core/knowledge-delta.ts +395 -0
  28. package/src/core/knowledge-impact.ts +202 -0
  29. package/src/ingestion/sync.ts +214 -165
  30. package/src/mcp/tools/changes.ts +80 -0
  31. package/src/mcp/tools/index.ts +29 -0
  32. package/src/publish/artifact-validation.ts +259 -0
  33. package/src/publish/artifact.ts +234 -118
  34. package/src/publish/export-service.ts +5 -9
  35. package/src/publish/metadata.ts +195 -0
  36. package/src/sdk/client.ts +42 -0
  37. package/src/sdk/index.ts +7 -0
  38. package/src/sdk/types.ts +22 -0
  39. package/src/serve/doc-events.ts +12 -1
  40. package/src/serve/resident-runtime.ts +22 -0
  41. package/src/serve/routes/api.ts +13 -0
  42. package/src/serve/routes/changes.ts +102 -0
  43. package/src/serve/server.ts +34 -0
  44. package/src/serve/watch-service.ts +9 -0
  45. package/src/store/index.ts +21 -0
  46. package/src/store/migrations/015-document-change-journal.ts +85 -0
  47. package/src/store/migrations/016-saved-capsules.ts +131 -0
  48. package/src/store/migrations/017-document-change-retention-counters.ts +33 -0
  49. package/src/store/migrations/018-saved-capsule-registration-epoch.ts +24 -0
  50. package/src/store/migrations/019-saved-capsule-registration-generation.ts +53 -0
  51. package/src/store/migrations/index.ts +10 -0
  52. package/src/store/sqlite/adapter.ts +291 -7
  53. package/src/store/sqlite/capsule-registry-store.ts +534 -0
  54. package/src/store/sqlite/change-journal-store.ts +473 -0
  55. package/src/store/types.ts +262 -0
package/README.md CHANGED
@@ -94,7 +94,7 @@ gno daemon --detach # headless continuous indexing (background; --status / --st
94
94
 
95
95
  <!-- public-truth:current-version -->
96
96
 
97
- > Current release: **v1.19.0** — see [CHANGELOG.md](./CHANGELOG.md)
97
+ > Current release: **v1.22.0** — see [CHANGELOG.md](./CHANGELOG.md)
98
98
 
99
99
  <!-- /public-truth -->
100
100
 
@@ -109,6 +109,13 @@ gno daemon --detach # headless continuous indexing (background; --status / --st
109
109
  watcher, jobs, stores, and models. The packed npm smoke proves two-client
110
110
  parity, warm reuse, redacted lifecycle status, fail-closed security, restart,
111
111
  and shutdown.
112
+ - **Knowledge Delta**: `gno changes`, `gno diff`, and `gno impact` expose
113
+ bounded metadata-only history, structural change summaries, and explainable
114
+ dependency paths across CLI, REST, MCP, and SDK.
115
+ - **Saved Capsule freshness**: CLI-only `gno context watch`, `watches`,
116
+ `reverify`, and `unwatch` register caller-owned Capsule files. The resident
117
+ runtime coalesces evidence changes into canonical, non-generative freshness
118
+ receipts and closed local metadata notifications.
112
119
  - **Second-brain capture**: `gno capture`, REST `/api/capture`, SDK
113
120
  `client.capture()`, MCP `gno_capture`, and Web UI Quick Capture write
114
121
  provenance-rich notes from text, stdin, or files, including typed presets for
@@ -553,9 +560,9 @@ Connect GNO to Claude Desktop, Cursor, Raycast, and more:
553
560
 
554
561
  ![GNO MCP](./assets/screenshots/mcp.jpg)
555
562
 
556
- GNO exposes 22 tools by default via [Model Context Protocol](https://modelcontextprotocol.io),
563
+ GNO exposes 25 tools by default via [Model Context Protocol](https://modelcontextprotocol.io),
557
564
  including the core retrieval tools below. Starting MCP with `--enable-write`
558
- adds 15 opt-in mutation tools, for 37 total.
565
+ adds 15 opt-in mutation tools, for 40 total.
559
566
 
560
567
  | Tool | Description |
561
568
  | :------------------- | :------------------------------------ |
@@ -574,6 +581,9 @@ adds 15 opt-in mutation tools, for 37 total.
574
581
  | `gno_status` | Index health check |
575
582
  | `gno_trace_list` | List private local retrieval receipts |
576
583
  | `gno_trace_show` | Inspect one bounded trace receipt |
584
+ | `gno_changes` | Read retained metadata-only changes |
585
+ | `gno_diff` | Read one structural document delta |
586
+ | `gno_impact` | Trace bounded dependency impact |
577
587
 
578
588
  **Design**: Default MCP mode is read-only: retrieval, opt-in verified synthesis,
579
589
  graph, status, and job inspection. Raw retrieval tools leave synthesis to your
@@ -700,7 +710,7 @@ GNO is local-first, but sometimes you want a URL to send someone. [**gno.sh**](h
700
710
 
701
711
  ![gno.sh publish reader](./assets/screenshots/publish-reader.jpg)
702
712
 
703
- The workflow is deliberately explicit: **export locally → upload artifact → share URL**. Your private notes and metadata stay on your machine. Only what you export leaves.
713
+ The workflow is deliberately explicit: **export locally → upload artifact → share URL**. Private and `publish: false` notes stay on your machine. Exported artifacts omit local collection paths and source URIs.
704
714
 
705
715
  ```bash
706
716
  # Export a single note
@@ -735,6 +745,15 @@ Upload the artifact at [gno.sh/studio](https://gno.sh/studio) and pick a visibil
735
745
 
736
746
  **Reader experience**: editorial serif typography, drop caps, hanging punctuation, table of contents, keyboard shortcuts (`j/k`, `/`), scoped Pagefind-style search, and backlinks restricted to the published subset. Nothing leaks that you didn't publish.
737
747
 
748
+ Public exports also carry a deterministic agent manifest. It lists only the
749
+ sanitized published Markdown projection, with relative Markdown locators,
750
+ content hashes, exact line spans, and Capsule-compatible evidence identities.
751
+ The projection revision is stable while those published bytes and reader
752
+ metadata are unchanged. Secret-link and invite-only exports do not receive
753
+ agent capabilities or manifests. Encrypted exports remain ciphertext-only.
754
+ Reader metadata drops embedded local path or GNO/file URI tokens; canonical
755
+ and image fields accept only uncredentialed public HTTP(S) targets.
756
+
738
757
  Republishing a public, secret-link, or invite-only artifact updates the same URL. Encrypted shares should be replaced from a fresh local export so the server never needs your plaintext.
739
758
 
740
759
  Encrypted source-backed publish on `gno.sh` is intentionally disabled. For encrypted shares, use:
@@ -775,6 +794,9 @@ curl http://localhost:3000/api/health
775
794
  | `/api/ask` | POST | AI-powered Q&A |
776
795
  | `/api/context` | POST | Build evidence Capsule |
777
796
  | `/api/context/verify` | POST | Verify saved Capsule |
797
+ | `/api/changes` | GET | List retained changes |
798
+ | `/api/diff` | GET | Read structural delta |
799
+ | `/api/impact` | GET | Trace dependency impact |
778
800
  | `/api/docs` | GET | List documents |
779
801
  | `/api/docs` | POST | Create document |
780
802
  | `/api/docs/:id` | PUT | Update document content |
@@ -850,7 +872,9 @@ graph TD
850
872
  | **Local LLM** | AI answers via llama.cpp, no API keys |
851
873
  | **Remote Inference** | Optional HTTP endpoints for embedding, reranking, expansion, and generation |
852
874
  | **Privacy First** | Local by default; no telemetry; network use is explicit or model provisioning |
853
- | **MCP Server** | 10 automatic client targets; 22 read-only tools, 37 with writes enabled |
875
+ | **MCP Server** | 10 automatic client targets; 25 read-only tools, 40 with writes enabled |
876
+ | **Knowledge Delta** | Bounded metadata history, structural diffs, and dependency impact paths |
877
+ | **Context Capsules** | Deterministic evidence bundles plus saved-file freshness reverification |
854
878
  | **Collections** | Organize sources with patterns, excludes, contexts |
855
879
  | **Tag Filtering** | Frontmatter tags with hierarchical paths, filter via `--tags-any`/`--tags-all` |
856
880
  | **Note Linking** | Wiki links, backlinks, related notes, cross-collection navigation |
@@ -63,21 +63,22 @@ Recipe rules:
63
63
 
64
64
  ## Command Overview
65
65
 
66
- | Category | Commands | Description |
67
- | ------------ | ---------------------------------------------------------------- | ------------------------------------------------------ |
68
- | **Search** | `search`, `vsearch`, `query`, `ask` | Find documents by keywords, meaning, or get AI answers |
69
- | **Links** | `links`, `backlinks`, `similar`, `graph`, `graph query` | Navigate document relationships and typed connections |
70
- | **Retrieve** | `get`, `multi-get`, `ls` | Fetch document content by URI or ID |
71
- | **Index** | `init`, `collection add/list/remove`, `index`, `update`, `embed` | Set up and maintain document index |
72
- | **Tags** | `tags`, `tags add`, `tags rm` | Organize and filter documents |
73
- | **Context** | `context add/list/rm/check/build/verify` | Configure guidance or compile/verify evidence Capsules |
74
- | **Traces** | `trace list/show/label/export/replay/delete/purge` | Manage and replay private retrieval receipts |
75
- | **Models** | `models list/use/pull/clear/path` | Manage local AI models |
76
- | **Serve** | `serve`, `daemon` | One resident Web/headless gateway and watcher |
77
- | **Publish** | `publish export` | Export gno.sh publish artifacts |
78
- | **MCP** | `mcp`, `mcp install/uninstall/status` | AI assistant integration |
79
- | **Skill** | `skill install/uninstall/show/paths` | Install skill for AI agents |
80
- | **Admin** | `status`, `doctor`, `cleanup`, `reset`, `vec`, `completion` | Maintenance and diagnostics |
66
+ | Category | Commands | Description |
67
+ | ------------ | ----------------------------------------------------------------------- | ------------------------------------------------------------------------ |
68
+ | **Search** | `search`, `vsearch`, `query`, `ask` | Find documents by keywords, meaning, or get AI answers |
69
+ | **Links** | `links`, `backlinks`, `similar`, `graph`, `graph query` | Navigate document relationships and typed connections |
70
+ | **Retrieve** | `get`, `multi-get`, `ls` | Fetch document content by URI or ID |
71
+ | **Index** | `init`, `collection add/list/remove`, `index`, `update`, `embed` | Set up and maintain document index |
72
+ | **Tags** | `tags`, `tags add`, `tags rm` | Organize and filter documents |
73
+ | **Context** | `context add/list/rm/check/build/verify/watch/watches/reverify/unwatch` | Configure guidance or compile, verify, and watch saved evidence Capsules |
74
+ | **Changes** | `changes`, `diff`, `impact` | Inspect bounded metadata history and dependency impact |
75
+ | **Traces** | `trace list/show/label/export/replay/delete/purge` | Manage and replay private retrieval receipts |
76
+ | **Models** | `models list/use/pull/clear/path` | Manage local AI models |
77
+ | **Serve** | `serve`, `daemon` | One resident Web/headless gateway and watcher |
78
+ | **Publish** | `publish export` | Export gno.sh publish artifacts |
79
+ | **MCP** | `mcp`, `mcp install/uninstall/status` | AI assistant integration |
80
+ | **Skill** | `skill install/uninstall/show/paths` | Install skill for AI agents |
81
+ | **Admin** | `status`, `doctor`, `cleanup`, `reset`, `vec`, `completion` | Maintenance and diagnostics |
81
82
 
82
83
  ## Search Modes
83
84
 
@@ -229,6 +230,36 @@ When using GNO through MCP, prefer this retrieval order:
229
230
  6. Use `gno_query_diagnose` when a known target document should have appeared but did not; it reports BM25/vector/fusion/graph/rerank stage presence and filter state.
230
231
  7. Use `gno_get` with `fromLine`/`lineCount` for targeted reads, or `gno_multi_get` to batch top refs.
231
232
 
233
+ For a caller-owned canonical Capsule that should stay fresh locally:
234
+
235
+ ```bash
236
+ gno context watch capsule.json --question "Who owns launch?" --notify --json
237
+ gno context watches --json
238
+ gno context reverify <registration-id> --json
239
+ gno context unwatch <registration-id> --json
240
+ ```
241
+
242
+ These lifecycle operations are CLI-only and scoped to the Capsule's index.
243
+ They persist bounded metadata and evidence hashes, not Capsule or passage
244
+ bytes. Automatic resident work starts only after settled index changes,
245
+ produces the same canonical non-generative verification receipt, and never
246
+ rewrites the saved file or invokes answer generation. A failed operation has
247
+ no receipt. Local notifications contain no question, label, path, URI, hashes,
248
+ receipt, credentials, or source content.
249
+
250
+ Use Knowledge Delta when the task asks what changed or what depends on a
251
+ changed source:
252
+
253
+ ```bash
254
+ gno changes --since 2026-07-20T00:00:00Z --json
255
+ gno diff gno://notes/plan.md --json
256
+ gno impact gno://notes/plan.md --max-depth 3 --json
257
+ ```
258
+
259
+ Treat cursors and change IDs as opaque. Journal results are bounded,
260
+ metadata-only, and retention-aware; do not infer source-body history when a
261
+ diff reports partial, expired, or unavailable history.
262
+
232
263
  Use narrower tools when the request tells you to:
233
264
 
234
265
  - `gno_search`: exact phrase, filename, identifier, stack trace, error text
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gmickel/gno",
3
- "version": "1.20.0",
3
+ "version": "1.22.0",
4
4
  "description": "Local semantic search for your documents. Index Markdown, PDF, and Office files with hybrid BM25 + vector search.",
5
5
  "keywords": [
6
6
  "embeddings",
@@ -83,6 +83,7 @@
83
83
  "eval:retrieval-candidates": "bun scripts/retrieval-candidate-benchmark.ts",
84
84
  "eval:retrieval-candidates:write": "bun scripts/retrieval-candidate-benchmark.ts --write",
85
85
  "eval:agentic": "bun evals/agentic/cli.ts",
86
+ "eval:agentic:demo": "bun evals/agentic/demos/generate-context-capsule.ts",
86
87
  "eval:watch": "bun --bun evalite watch",
87
88
  "research:finetune:bootstrap": "bun research/finetune/scripts/bootstrap-promotion-fixtures.ts",
88
89
  "research:finetune:autonomous:noop": "bun research/finetune/autonomous/scripts/noop-run.ts",
package/spec/cli.md CHANGED
@@ -86,11 +86,16 @@ equivalent files fail closed as ambiguous.
86
86
  | context check | yes | no | no | yes | no | terminal |
87
87
  | context build | yes | no | no | yes | no | Markdown |
88
88
  | context verify | yes | no | no | yes | no | Markdown |
89
+ | context watch | yes | no | no | no | no | terminal |
90
+ | context watches | yes | no | no | no | no | terminal |
91
+ | context unwatch | yes | no | no | no | no | terminal |
92
+ | context reverify | yes | no | no | no | no | terminal |
89
93
  | context rm | no | no | no | no | no | terminal |
90
94
  | models list | yes | no | no | yes | no | terminal |
91
95
  | models pull | no | no | no | no | no | terminal |
92
96
  | models clear | no | no | no | no | no | terminal |
93
97
  | models path | yes | no | no | no | no | terminal |
98
+ | publish export | yes | no | no | no | no | terminal |
94
99
  | cleanup | no | no | no | no | no | terminal |
95
100
  | doctor | yes | no | no | yes | no | terminal |
96
101
  | mcp | no | no | no | no | no | stdio |
@@ -1364,6 +1369,58 @@ fingerprint and deterministic recount callback before any store read; CLI
1364
1369
  runtimes without that tokenizer fail with `tokenizer_unavailable` rather than
1365
1370
  trusting saved `usedTokens`.
1366
1371
 
1372
+ ### gno context watch / watches / unwatch / reverify
1373
+
1374
+ Register an explicit canonical JSON Capsule file for local, evidence-triggered
1375
+ reverification:
1376
+
1377
+ ```bash
1378
+ gno context watch <file> [--question <text>] [--label <text>] [--notify] [--json]
1379
+ gno context watches [--json]
1380
+ gno context unwatch <registration> [--json]
1381
+ gno context reverify <registration> [--json]
1382
+ ```
1383
+
1384
+ The registration persists only the absolute file path, exact file hash,
1385
+ Capsule/index identity, optional question and label, notification preference,
1386
+ and evidence URI/hash references. Capsule bytes and evidence passages are never
1387
+ copied into the database. The file remains caller-owned and immutable to GNO.
1388
+ The Capsule's canonical index is authoritative when `watch` is invoked without
1389
+ an explicit global `--index`; an explicit mismatch fails before journal or
1390
+ evidence reads.
1391
+
1392
+ A resident `serve` or `daemon` runtime reverifies affected registrations after
1393
+ watcher work has settled. Raw journal changes are coalesced, one bounded
1394
+ reverification batch runs at a time, and the durable journal high-water mark
1395
+ prevents duplicate work after restart. An expired journal cursor triggers a
1396
+ conservative bounded pass over all registrations. Reverification uses the
1397
+ canonical `context verify` receipt. Operation failures are stored separately
1398
+ and never synthesized into a receipt.
1399
+
1400
+ `--notify` enables local metadata-only `capsule-reverified` events after the
1401
+ verification record commits. Events contain registration/Capsule identity,
1402
+ operation status, affected-question state, and timestamp; they contain no
1403
+ question, file path, URI, passage, Capsule, or receipt bytes. `context
1404
+ reverify` performs the same non-generative verification immediately.
1405
+
1406
+ `context reverify` exits `0` only when `operationStatus` is `completed`. A
1407
+ persisted `failed` operation is still rendered: terminal output includes the
1408
+ failure code and message, while `--json` writes the closed structured
1409
+ reverification object to stdout. The command then exits `2`; the structured
1410
+ failure must never be mistaken for a successful verification receipt.
1411
+
1412
+ JSON contracts are Draft-07 and closed:
1413
+
1414
+ - `watch`: `saved-capsule-watch.schema.json`; the initial verification is null.
1415
+ - `watches`: `saved-capsule-list.schema.json`.
1416
+ - `unwatch`: `saved-capsule-unwatch.schema.json`.
1417
+ - `reverify`: `saved-capsule-reverification.schema.json`; a completed
1418
+ canonical receipt and a failed operation record are mutually exclusive.
1419
+ - local SSE notification data: `capsule-reverified-event.schema.json`.
1420
+
1421
+ These registration-management surfaces are CLI-only. REST, MCP, and SDK expose
1422
+ the non-persistent `context verify` operation, not watch lifecycle mutations.
1423
+
1367
1424
  ---
1368
1425
 
1369
1426
  ### gno models list
@@ -1502,6 +1559,49 @@ gno models path [--json]
1502
1559
 
1503
1560
  ---
1504
1561
 
1562
+ ### gno publish export
1563
+
1564
+ Build a reader-safe gno.sh artifact from one active collection or document.
1565
+
1566
+ **Synopsis:**
1567
+
1568
+ ```bash
1569
+ gno publish export <target> \
1570
+ [--out <path>] \
1571
+ [--visibility public|secret-link|invite-only|encrypted] \
1572
+ [--passphrase <value>] \
1573
+ [--slug <slug>] \
1574
+ [--title <title>] \
1575
+ [--summary <summary>] \
1576
+ [--preview] \
1577
+ [--json]
1578
+ ```
1579
+
1580
+ Public V1 spaces MUST carry a `manifest` conforming to
1581
+ [`publish-artifact.schema.json`](./output-schemas/publish-artifact.schema.json).
1582
+ The manifest contains schema version `1.0`, a deterministic projection
1583
+ revision, generated time, closed public capabilities, sorted published
1584
+ documents, relative Markdown locators, SHA-256 content hashes, and
1585
+ Capsule-compatible evidence identities. Manifest hashes and revisions MUST be
1586
+ derived only from sanitized notes and metadata present in the published
1587
+ projection. Local collection paths, document source URIs, unpublished
1588
+ documents, and filtered metadata MUST NOT enter artifact bytes or revision
1589
+ inputs. Reader metadata values containing embedded local path or GNO/file URI
1590
+ tokens MUST be filtered. Canonical and image metadata MUST contain
1591
+ uncredentialed public HTTP(S) targets; local hostnames and literal loopback,
1592
+ private, or link-local addresses MUST be filtered.
1593
+
1594
+ Secret-link and invite-only V1 spaces MUST NOT contain a manifest or agent
1595
+ capability field. Encrypted V2 spaces MUST contain only ciphertext parameters,
1596
+ the opaque secret token, route slug, source type, and encrypted visibility; no
1597
+ plaintext manifest or evidence may appear outside the ciphertext. V2 builders
1598
+ MUST emit a closed projection, validate payload strings as non-empty bounded
1599
+ base64, require a positive safe-integer KDF iteration count, and bound the
1600
+ non-blank opaque token. Caller-supplied extension fields MUST NOT enter the
1601
+ artifact.
1602
+
1603
+ ---
1604
+
1505
1605
  ### gno cleanup
1506
1606
 
1507
1607
  Remove orphaned content, chunks, and vectors not referenced by active documents.
@@ -2607,6 +2707,50 @@ derived from frontmatter relations, content-type graph hints, and backfilled
2607
2707
  wiki/markdown projections (for example `mentions`, `references`, or
2608
2708
  `related`), not the global graph export edge-type enum above.
2609
2709
 
2710
+ ### gno changes
2711
+
2712
+ List retained, metadata-only document lifecycle changes.
2713
+
2714
+ ```bash
2715
+ gno changes [--since <ISO-8601|cursor>] [--collection <name>] [--limit <n>] [--json]
2716
+ ```
2717
+
2718
+ - `--since` accepts an ISO-8601 time or an opaque cursor returned by an earlier
2719
+ call. Cursors are monotonic, stable, and must not be parsed by callers.
2720
+ - `--limit` defaults to 100 and is bounded to 1-1000.
2721
+ - JSON output uses `changes.schema.json`. It includes opaque per-change IDs,
2722
+ old/new identity and hash snapshots, normalized structural deltas, pagination,
2723
+ cursor-expiry, and retention-truncation disclosure.
2724
+ - The journal never returns source bodies.
2725
+
2726
+ ### gno diff
2727
+
2728
+ Show the latest retained structural delta for one document, or select an exact
2729
+ retained journal entry by opaque ID.
2730
+
2731
+ ```bash
2732
+ gno diff <doc> [--change <id>] [--json]
2733
+ ```
2734
+
2735
+ JSON output uses `document-diff.schema.json`. `content.status` is always
2736
+ `not_retained`; GNO does not reconstruct old bodies. `history.status` is
2737
+ `partial` when `structureDelta.truncated` discloses unavailable prior
2738
+ structure. Expired/purged IDs return `status: "expired"` without inventing
2739
+ history.
2740
+
2741
+ ### gno impact
2742
+
2743
+ Find active documents that depend on one document through inbound typed,
2744
+ wiki-link, or Markdown-link edges.
2745
+
2746
+ ```bash
2747
+ gno impact <doc> [--max-depth <n>] [--max-nodes <n>] [--max-edges <n>] [--frontier-limit <n>] [--visited-limit <n>] [--json]
2748
+ ```
2749
+
2750
+ The traversal is cycle-safe and enforces depth, node, edge, frontier, and
2751
+ visited-row caps. Every impacted document includes one deterministic
2752
+ dependency-to-root evidence path. JSON output uses `impact.schema.json`.
2753
+
2610
2754
  **Exit Codes:**
2611
2755
 
2612
2756
  - 0: Success
@@ -19,6 +19,8 @@
19
19
  -- retrieval_traces - Opt-in private retrieval trace headers
20
20
  -- retrieval_trace_runs/events/judgments - Bounded trace outcome records
21
21
  -- retrieval_trace_exports/export_traces - Export manifests and trace joins
22
+ -- document_changes - Bounded metadata-only document lifecycle journal
23
+ -- document_change_journal_state - Monotonic cursor/retention boundary
22
24
 
23
25
  -- ─────────────────────────────────────────────────────────────────────────────
24
26
  -- Schema Metadata
@@ -361,6 +363,64 @@ CREATE TABLE IF NOT EXISTS retrieval_trace_export_traces (
361
363
  -- and an absolute 100,000 subordinate-record safety cap per trace. Runtime
362
364
  -- retention applies the lower configured maxRecordsPerTrace bound.
363
365
 
366
+ -- ─────────────────────────────────────────────────────────────────────────────
367
+ -- Document Change Journal
368
+ -- ─────────────────────────────────────────────────────────────────────────────
369
+
370
+ -- Append-only while retained. Rows contain identity, hashes, active state, and
371
+ -- compact structural summaries only; source and converted bodies are excluded.
372
+
373
+ CREATE TABLE IF NOT EXISTS document_changes (
374
+ sequence INTEGER PRIMARY KEY AUTOINCREMENT,
375
+ document_id INTEGER NOT NULL CHECK (document_id > 0),
376
+ collection TEXT NOT NULL,
377
+ change_kind TEXT NOT NULL
378
+ CHECK (change_kind IN ('create', 'update', 'rename', 'inactivate', 'reactivate')),
379
+ old_rel_path TEXT,
380
+ new_rel_path TEXT,
381
+ old_docid TEXT,
382
+ new_docid TEXT,
383
+ old_uri TEXT,
384
+ new_uri TEXT,
385
+ old_source_hash TEXT,
386
+ new_source_hash TEXT,
387
+ old_mirror_hash TEXT,
388
+ new_mirror_hash TEXT,
389
+ old_active INTEGER CHECK (old_active IS NULL OR old_active IN (0, 1)),
390
+ new_active INTEGER CHECK (new_active IS NULL OR new_active IN (0, 1)),
391
+ heading_delta_json TEXT NOT NULL DEFAULT '{"added":[],"removed":[]}',
392
+ link_delta_json TEXT NOT NULL DEFAULT '{"added":[],"removed":[]}',
393
+ typed_edge_delta_json TEXT NOT NULL DEFAULT '{"added":[],"removed":[]}',
394
+ date_delta_json TEXT NOT NULL
395
+ DEFAULT '{"added":[],"removed":[],"changed":[]}',
396
+ structure_truncated INTEGER NOT NULL DEFAULT 0
397
+ CHECK (structure_truncated IN (0, 1)),
398
+ observed_at_ms INTEGER NOT NULL CHECK (observed_at_ms >= 0),
399
+ byte_size INTEGER NOT NULL CHECK (byte_size > 0 AND byte_size <= 131072),
400
+ CHECK (length(CAST(heading_delta_json AS BLOB)) <= 16384),
401
+ CHECK (length(CAST(link_delta_json AS BLOB)) <= 16384),
402
+ CHECK (length(CAST(typed_edge_delta_json AS BLOB)) <= 16384),
403
+ CHECK (length(CAST(date_delta_json AS BLOB)) <= 16384)
404
+ );
405
+
406
+ CREATE INDEX IF NOT EXISTS idx_document_changes_collection_sequence
407
+ ON document_changes(collection, sequence);
408
+ CREATE INDEX IF NOT EXISTS idx_document_changes_document_sequence
409
+ ON document_changes(document_id, sequence);
410
+ CREATE INDEX IF NOT EXISTS idx_document_changes_retention
411
+ ON document_changes(observed_at_ms, sequence);
412
+
413
+ CREATE TABLE IF NOT EXISTS document_change_journal_state (
414
+ singleton_id INTEGER PRIMARY KEY CHECK (singleton_id = 1),
415
+ last_sequence INTEGER NOT NULL DEFAULT 0 CHECK (last_sequence >= 0),
416
+ retention_floor INTEGER NOT NULL DEFAULT 0
417
+ CHECK (retention_floor >= 0 AND retention_floor <= last_sequence),
418
+ retained_entries INTEGER NOT NULL DEFAULT 0
419
+ CHECK (retained_entries >= 0),
420
+ retained_bytes INTEGER NOT NULL DEFAULT 0
421
+ CHECK (retained_bytes >= 0)
422
+ );
423
+
364
424
  -- ─────────────────────────────────────────────────────────────────────────────
365
425
  -- Document Tags
366
426
  -- ─────────────────────────────────────────────────────────────────────────────
@@ -440,3 +500,113 @@ CREATE TABLE IF NOT EXISTS doc_edges (
440
500
 
441
501
  CREATE INDEX IF NOT EXISTS idx_doc_edges_src_type ON doc_edges(src_doc_id, edge_type);
442
502
  CREATE INDEX IF NOT EXISTS idx_doc_edges_dst_type ON doc_edges(dst_doc_id, edge_type);
503
+
504
+ -- ─────────────────────────────────────────────────────────────────────────────
505
+ -- Saved Context Capsules (metadata only)
506
+ -- ─────────────────────────────────────────────────────────────────────────────
507
+
508
+ CREATE TABLE IF NOT EXISTS saved_capsule_registrations (
509
+ registration_id TEXT PRIMARY KEY,
510
+ file_path TEXT NOT NULL UNIQUE,
511
+ file_hash TEXT NOT NULL,
512
+ capsule_id TEXT NOT NULL,
513
+ index_name TEXT NOT NULL,
514
+ question TEXT,
515
+ label TEXT,
516
+ notification_preference TEXT NOT NULL DEFAULT 'none'
517
+ CHECK (notification_preference IN ('none', 'local')),
518
+ registered_at_ms INTEGER NOT NULL CHECK (registered_at_ms >= 0),
519
+ updated_at_ms INTEGER NOT NULL CHECK (updated_at_ms >= registered_at_ms),
520
+ last_attempted_sequence INTEGER NOT NULL DEFAULT 0
521
+ CHECK (last_attempted_sequence >= 0),
522
+ registration_generation INTEGER NOT NULL DEFAULT 0
523
+ CHECK (registration_generation >= 0),
524
+ CHECK (length(registration_id) BETWEEN 1 AND 128),
525
+ CHECK (length(CAST(file_path AS BLOB)) BETWEEN 1 AND 8192),
526
+ CHECK (length(file_hash) = 64 AND file_hash NOT GLOB '*[^0-9a-f]*'),
527
+ CHECK (length(capsule_id) = 64 AND capsule_id NOT GLOB '*[^0-9a-f]*'),
528
+ CHECK (length(CAST(index_name AS BLOB)) BETWEEN 1 AND 128),
529
+ CHECK (question IS NULL OR length(CAST(question AS BLOB)) <= 8192),
530
+ CHECK (label IS NULL OR length(CAST(label AS BLOB)) <= 512)
531
+ );
532
+
533
+ CREATE INDEX IF NOT EXISTS idx_saved_capsules_index
534
+ ON saved_capsule_registrations(index_name, registration_id);
535
+
536
+ CREATE TABLE IF NOT EXISTS saved_capsule_evidence (
537
+ registration_id TEXT NOT NULL,
538
+ evidence_id TEXT NOT NULL,
539
+ canonical_uri TEXT NOT NULL,
540
+ collection TEXT NOT NULL,
541
+ source_hash TEXT NOT NULL,
542
+ mirror_hash TEXT NOT NULL,
543
+ passage_hash TEXT NOT NULL,
544
+ PRIMARY KEY (registration_id, evidence_id),
545
+ FOREIGN KEY (registration_id)
546
+ REFERENCES saved_capsule_registrations(registration_id)
547
+ ON DELETE CASCADE,
548
+ CHECK (length(evidence_id) = 64 AND evidence_id NOT GLOB '*[^0-9a-f]*'),
549
+ CHECK (length(CAST(canonical_uri AS BLOB)) BETWEEN 1 AND 8192),
550
+ CHECK (length(CAST(collection AS BLOB)) BETWEEN 1 AND 256),
551
+ CHECK (length(source_hash) = 64 AND source_hash NOT GLOB '*[^0-9a-f]*'),
552
+ CHECK (length(mirror_hash) = 64 AND mirror_hash NOT GLOB '*[^0-9a-f]*'),
553
+ CHECK (length(passage_hash) = 64 AND passage_hash NOT GLOB '*[^0-9a-f]*')
554
+ );
555
+
556
+ CREATE INDEX IF NOT EXISTS idx_saved_capsule_evidence_uri
557
+ ON saved_capsule_evidence(canonical_uri, registration_id);
558
+ CREATE INDEX IF NOT EXISTS idx_saved_capsule_evidence_source
559
+ ON saved_capsule_evidence(source_hash, registration_id);
560
+ CREATE INDEX IF NOT EXISTS idx_saved_capsule_evidence_mirror
561
+ ON saved_capsule_evidence(mirror_hash, registration_id);
562
+
563
+ CREATE TABLE IF NOT EXISTS saved_capsule_verifications (
564
+ registration_id TEXT PRIMARY KEY,
565
+ trigger_kind TEXT NOT NULL CHECK (trigger_kind IN ('manual', 'journal')),
566
+ from_sequence INTEGER NOT NULL CHECK (from_sequence >= 0),
567
+ through_sequence INTEGER NOT NULL CHECK (through_sequence >= from_sequence),
568
+ operation_status TEXT NOT NULL CHECK (operation_status IN ('completed', 'failed')),
569
+ affected_question_state TEXT NOT NULL
570
+ CHECK (affected_question_state IN ('unaffected', 'affected', 'unknown')),
571
+ affected_reasons_json TEXT NOT NULL,
572
+ receipt_json TEXT,
573
+ receipt_hash TEXT,
574
+ error_code TEXT,
575
+ error_message TEXT,
576
+ verified_at_ms INTEGER NOT NULL CHECK (verified_at_ms >= 0),
577
+ FOREIGN KEY (registration_id)
578
+ REFERENCES saved_capsule_registrations(registration_id)
579
+ ON DELETE CASCADE,
580
+ CHECK (length(CAST(affected_reasons_json AS BLOB)) <= 4096),
581
+ CHECK (receipt_json IS NULL OR length(CAST(receipt_json AS BLOB)) <= 16777216),
582
+ CHECK (receipt_hash IS NULL OR (
583
+ length(receipt_hash) = 64 AND receipt_hash NOT GLOB '*[^0-9a-f]*'
584
+ )),
585
+ CHECK (error_code IS NULL OR length(CAST(error_code AS BLOB)) <= 256),
586
+ CHECK (error_message IS NULL OR length(CAST(error_message AS BLOB)) <= 4096),
587
+ CHECK (
588
+ (
589
+ operation_status = 'completed'
590
+ AND receipt_json IS NOT NULL
591
+ AND receipt_hash IS NOT NULL
592
+ AND error_code IS NULL
593
+ AND error_message IS NULL
594
+ )
595
+ OR
596
+ (
597
+ operation_status = 'failed'
598
+ AND receipt_json IS NULL
599
+ AND receipt_hash IS NULL
600
+ AND error_code IS NOT NULL
601
+ AND error_message IS NOT NULL
602
+ )
603
+ )
604
+ );
605
+
606
+ CREATE TABLE IF NOT EXISTS saved_capsule_reverification_state (
607
+ singleton_id INTEGER PRIMARY KEY CHECK (singleton_id = 1),
608
+ last_processed_sequence INTEGER NOT NULL DEFAULT 0
609
+ CHECK (last_processed_sequence >= 0),
610
+ registration_epoch INTEGER NOT NULL DEFAULT 0
611
+ CHECK (registration_epoch >= 0)
612
+ );
@@ -24,6 +24,7 @@ evals/agentic/
24
24
  promotion.ts
25
25
  verified-ask-outcome.ts
26
26
  verified-ask-promotion.ts
27
+ demos/context-capsule.ts
27
28
  registry.ts
28
29
  report.ts
29
30
  report-artifacts.ts
@@ -44,6 +45,7 @@ evals/agentic/
44
45
  final-envelope.schema.json
45
46
  trajectory-receipt.schema.json
46
47
  benchmark-report.schema.json
48
+ context-capsule-demo.schema.json
47
49
 
48
50
  evals/fixtures/agentic-retrieval/
49
51
  manifest.json
@@ -61,6 +63,9 @@ evals/fixtures/agentic-retrieval/
61
63
  verified-ask-promotion.json
62
64
  verified-ask-promotion.md
63
65
  optional/{qmd,local-model}/ # local opt-in evidence; not authoritative
66
+ demos/
67
+ context-capsule.json
68
+ context-capsule.md
64
69
  ```
65
70
 
66
71
  The first fixture version contains 24 original synthetic tasks and 34 Markdown
@@ -412,6 +417,48 @@ summary. The six files are staged and directory-renamed as one baseline set.
412
417
  The verified Ask files are a separate attributable outcome lane; they do not
413
418
  rename the Capsule retrieval promotion in `report.json`.
414
419
 
420
+ ## Reproducible Context Capsule demo
421
+
422
+ `demos/context-capsule.json` is a closed, canonically fingerprinted projection
423
+ of one frozen exact-identifier task from the authoritative fixture-agent
424
+ report. It contains exactly three lanes in fixed order: the lexical-only
425
+ no-GNO baseline, shipped GNO MCP query/get primitives, and the Context Capsule.
426
+ Every lane retains its complete normalized trajectory receipt, score, exact
427
+ evidence coordinates and hashes, final stop outcome, agent/backend call counts,
428
+ model-visible UTF-8 bytes, token availability, and matching-lifecycle latency.
429
+
430
+ All three lanes must share the task, outer agent, trial, seed, lifecycle,
431
+ corpus, prompt, tool, model, runtime, and canonical effective-index
432
+ fingerprints. The generator selects exactly one receipt and score per full
433
+ identity and rejects ambiguous multi-trial input. Adapter configuration
434
+ fingerprints may differ. The Capsule projection additionally retains its
435
+ normalized `retrieval.request`, effective index fingerprint, capability states,
436
+ fallback list, and complete model-visible payload. Validation parses the
437
+ delivered evidence bundle and compares those values, then recomputes every
438
+ displayed lane metric from the embedded receipt and score.
439
+
440
+ Source provenance distinguishes each source run's clean `runGitCommit` from
441
+ the later Git commit that contains the generated demo artifact. The artifact
442
+ does not attempt to embed its own containing commit. Its report and Verified
443
+ Ask fingerprints and projected fields must match the canonical linked source
444
+ artifacts.
445
+
446
+ The readable `context-capsule.md` is generated from the JSON contract. It
447
+ states the single-trial variance limitation, reports tokens as unavailable
448
+ without one pinned comparable tokenizer, and limits its claim to the measured
449
+ controlled task. It discloses that the chosen task is the sole cold
450
+ current-GNO-failure / Capsule-success case in the 24-task authoritative cohort,
451
+ that the Capsule lane is an evaluation-only lexical prototype, and that its
452
+ latency is not shipped-product latency. It cannot be used as a general
453
+ product-superiority claim.
454
+
455
+ The adjacent Verified Ask block is an attributable but separate
456
+ `answer_enforcement` proof. It binds the clean-Git canonical fingerprint of the
457
+ frozen 22-pair `raw_ask`/`verified_ask` artifact, retains the two declared
458
+ missing-evidence exclusions, and exposes only answer-accuracy and unsupported-
459
+ substantive-claim metrics. Those metrics are never merged into or labeled as
460
+ retrieval metrics.
461
+
415
462
  ## Deterministic scoring
416
463
 
417
464
  The scorer compares typed claims and exact citations with the hidden oracle. It
@@ -551,6 +598,7 @@ Contract tests are ordinary offline tests:
551
598
 
552
599
  ```bash
553
600
  bun test test/eval/agentic
601
+ bun run eval:agentic:demo
554
602
  ```
555
603
 
556
604
  The runner is local and opt-in:
package/spec/mcp.md CHANGED
@@ -1526,6 +1526,28 @@ Use for explicit relationship questions over typed edges such as `works_at`,
1526
1526
  `attended`, or `mentions` after a seed ref is known. Use `gno_query` first if
1527
1527
  the seed document is unknown.
1528
1528
 
1529
+ ### gno_changes
1530
+
1531
+ Read-only metadata journal listing. Input fields: `since` (ISO-8601 time or
1532
+ opaque cursor), `collection`, and `limit` (1-1000, default 100). Structured
1533
+ content is contract-identical to CLI/REST/SDK `changes.schema.json`; it never
1534
+ contains source bodies.
1535
+
1536
+ ### gno_diff
1537
+
1538
+ Read-only structural diff for `ref`, optionally selecting opaque `change`.
1539
+ Structured content is `document-diff.schema.json`. Expired/purged history and
1540
+ metadata-only content are explicit output states, while unavailable prior
1541
+ structure is derived from `structureDelta.truncated`.
1542
+
1543
+ ### gno_impact
1544
+
1545
+ Read-only inbound dependency traversal for `ref`. Inputs `maxDepth`,
1546
+ `maxNodes`, `maxEdges`, `frontierLimit`, and `visitedLimit` use the same bounds
1547
+ as CLI/REST/SDK. Structured content is `impact.schema.json`; each impacted
1548
+ document includes a deterministic evidence path over typed or backlink
1549
+ projections. Truncation is explicit when any cap is reached.
1550
+
1529
1551
  ---
1530
1552
 
1531
1553
  ### gno_graph_neighbors