@gmickel/gno 2.7.0 → 2.8.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 (99) hide show
  1. package/README.md +26 -30
  2. package/assets/skill/SKILL.md +8 -1
  3. package/assets/skill/cli-reference.md +8 -1
  4. package/assets/skill/examples.md +2 -1
  5. package/assets/skill/mcp-reference.md +3 -1
  6. package/assets/spa-production.json.gz +0 -0
  7. package/browser-extension/artifacts/{gno-browser-clipper-v2.7.0.zip → gno-browser-clipper-v2.8.0.zip} +0 -0
  8. package/browser-extension/artifacts/gno-browser-clipper-v2.8.0.zip.sha256 +1 -0
  9. package/browser-extension/dist/manifest.json +1 -1
  10. package/package.json +2 -1
  11. package/spec/cli.md +48 -6
  12. package/spec/db/schema.sql +0 -1
  13. package/spec/mcp.md +18 -3
  14. package/spec/output-schemas/audit-report.schema.json +18 -4
  15. package/spec/output-schemas/backlinks.schema.json +4 -0
  16. package/spec/output-schemas/collection-list.schema.json +15 -2
  17. package/spec/output-schemas/graph.schema.json +2 -0
  18. package/spec/output-schemas/links-list.schema.json +4 -0
  19. package/spec/output-schemas/status.schema.json +27 -16
  20. package/src/cli/commands/ask.ts +31 -12
  21. package/src/cli/commands/audit.ts +23 -4
  22. package/src/cli/commands/collection/list.ts +39 -5
  23. package/src/cli/commands/embed.ts +3 -3
  24. package/src/cli/commands/links.ts +34 -131
  25. package/src/cli/commands/ls.ts +6 -1
  26. package/src/cli/commands/shared.ts +7 -0
  27. package/src/cli/commands/status.ts +5 -0
  28. package/src/cli/program.ts +12 -2
  29. package/src/config/loader.ts +43 -0
  30. package/src/config/types.ts +8 -0
  31. package/src/core/audit-contract.ts +16 -4
  32. package/src/core/audit-freshness.ts +11 -1
  33. package/src/core/audit-links.ts +145 -25
  34. package/src/core/audit-provenance.ts +11 -4
  35. package/src/core/audit-workspace.ts +19 -4
  36. package/src/core/audit.ts +67 -15
  37. package/src/core/context-compiler.ts +3 -0
  38. package/src/core/context-evidence.ts +11 -0
  39. package/src/core/graph-edge-confidence.ts +23 -1
  40. package/src/core/host-paths.ts +24 -5
  41. package/src/core/knowledge-impact.ts +28 -0
  42. package/src/core/link-workspace.ts +324 -0
  43. package/src/core/request-receipts.ts +63 -9
  44. package/src/core/retrieval-replay-candidate.ts +6 -0
  45. package/src/core/retrieval-trace-request.ts +3 -0
  46. package/src/core/windows-private-path.ts +136 -1
  47. package/src/embed/backlog.ts +22 -10
  48. package/src/embed/variant-backlog.ts +34 -9
  49. package/src/index.ts +14 -1
  50. package/src/ingestion/graph-reconciliation.ts +77 -15
  51. package/src/ingestion/source-availability/darwin-path.ts +9 -3
  52. package/src/ingestion/sync.ts +22 -1
  53. package/src/ingestion/types.ts +14 -0
  54. package/src/llm/inference-scope.ts +19 -0
  55. package/src/mcp/http-egress.ts +42 -3
  56. package/src/mcp/tools/audit.ts +11 -2
  57. package/src/mcp/tools/changes.ts +1 -0
  58. package/src/mcp/tools/links.ts +3 -0
  59. package/src/mcp/tools/sessions.ts +33 -4
  60. package/src/mcp/tools/status.ts +22 -6
  61. package/src/pipeline/expansion.ts +19 -31
  62. package/src/pipeline/graph-retrieval.ts +22 -2
  63. package/src/pipeline/hybrid.ts +1 -1
  64. package/src/pipeline/types.ts +6 -3
  65. package/src/serve/embed-scheduler.ts +2 -2
  66. package/src/serve/findings-pass.ts +1 -1
  67. package/src/serve/host-path-redaction.ts +51 -14
  68. package/src/serve/public/components/BootstrapStatus.tsx +5 -3
  69. package/src/serve/public/components/CaptureModal.tsx +1 -1
  70. package/src/serve/public/components/CollectionModelDialog.tsx +16 -13
  71. package/src/serve/public/components/CollectionsEmptyState.tsx +5 -3
  72. package/src/serve/public/components/FirstRunWizard.tsx +4 -2
  73. package/src/serve/public/components/sessions/SourcesPanel.tsx +77 -60
  74. package/src/serve/public/pages/Collections.tsx +16 -13
  75. package/src/serve/public/pages/Connectors.tsx +7 -4
  76. package/src/serve/public/pages/Dashboard.tsx +8 -6
  77. package/src/serve/public/pages/GraphView.tsx +2 -0
  78. package/src/serve/resident-runtime.ts +7 -0
  79. package/src/serve/routes/changes.ts +6 -1
  80. package/src/serve/routes/links.ts +13 -0
  81. package/src/serve/routes/sessions.ts +81 -37
  82. package/src/serve/server.ts +5 -3
  83. package/src/serve/status-model.ts +10 -6
  84. package/src/serve/status.ts +2 -7
  85. package/src/sessions/config-refresh.ts +111 -0
  86. package/src/store/migrations/033-drop-documents-active-index.ts +30 -0
  87. package/src/store/migrations/034-collection-link-workspace.ts +47 -0
  88. package/src/store/migrations/index.ts +4 -0
  89. package/src/store/sqlite/adapter.ts +392 -233
  90. package/src/store/sqlite/change-journal-store.ts +1 -1
  91. package/src/store/sqlite/eligibility.ts +8 -2
  92. package/src/store/sqlite/graph-link-resolver.ts +252 -5
  93. package/src/store/sqlite/graph-neighbors.ts +147 -40
  94. package/src/store/sqlite/graph-reference-state.ts +13 -2
  95. package/src/store/sqlite/legacy-vector-ownership.ts +2 -1
  96. package/src/store/sqlite/workspace-link-resolver.ts +654 -0
  97. package/src/store/types.ts +49 -3
  98. package/src/store/vector/stats.ts +1 -1
  99. package/browser-extension/artifacts/gno-browser-clipper-v2.7.0.zip.sha256 +0 -1
package/README.md CHANGED
@@ -139,7 +139,7 @@ See the [guide](docs/COMPILED-CONTEXT.md).
139
139
 
140
140
  <!-- public-truth:current-version -->
141
141
 
142
- > Current source version: **v2.7.0**. See [CHANGELOG.md](./CHANGELOG.md).
142
+ > Current source version: **v2.8.0**. See [CHANGELOG.md](./CHANGELOG.md).
143
143
 
144
144
  <!-- /public-truth -->
145
145
 
@@ -184,9 +184,8 @@ See the [guide](docs/COMPILED-CONTEXT.md).
184
184
  explicit read-only retrieval smoke from Connectors.
185
185
  - **One resident gateway**: `gno serve` and `gno daemon` now host stateful
186
186
  Streamable HTTP MCP at `/mcp` from the same long-lived runtime as their
187
- watcher, jobs, stores, and models. The packed npm smoke proves two-client
188
- parity, warm reuse, redacted lifecycle status, fail-closed security, restart,
189
- and shutdown.
187
+ watcher, jobs, stores, and models. Several MCP clients can share one
188
+ resident process and get the same results as stdio MCP.
190
189
  - **Knowledge Delta**: `gno changes`, `gno diff`, and `gno impact` expose
191
190
  bounded metadata-only history, structural change summaries, and explainable
192
191
  dependency paths across CLI, REST, MCP, and SDK.
@@ -215,17 +214,14 @@ See the [guide](docs/COMPILED-CONTEXT.md).
215
214
  `local_only`, `lan`, or `remote` boundary that follows mixed and derived
216
215
  evidence through resident serving, inference, publishing, exports, Capsules,
217
216
  and traces. Authentication never overrides policy.
218
- - **Source availability (`any` | `local`)**: opt-in `local` refuses
219
- cloud-placeholder materialization on the macOS File Provider layouts covered
220
- by physical evidence (Google Drive, iCloud Drive, and OneDrive for both
221
- validated immediate SharePoint library roots). Hierarchical directory
222
- classification + guarded content recheck; skips are not conversion errors;
223
- unproven prefixes preserve indexed descendants. Distinct from egress.
224
- Unsupported platforms fail closed; no claim of zero provider activity or
225
- universal provider support. On the controlled 5,000-file all-local corpus,
226
- production `any` regressed -1.1280% and hierarchical `local` added 1.1841%
227
- median traversal overhead (2 warmups, 9 samples per lane; same corpus and
228
- interleaved pre-implementation/current production walkers).
217
+ - **Source availability (`any` | `local`)**: opt-in `local` indexes only files
218
+ already on disk and never makes a cloud provider download one. Supported on
219
+ macOS with Google Drive (My Drive and Shared drives), iCloud Drive, and
220
+ OneDrive SharePoint library roots.
221
+ Cloud-only files are skipped and reported, not treated as conversion errors,
222
+ and documents under a cloud-only folder stay indexed. Other platforms fail
223
+ with an error. On a 5,000-file all-local collection, `local` scans about 1%
224
+ slower than `any`.
229
225
  - **Read-only integrity audits**: `gno audit` and MCP `gno_audit` inspect local
230
226
  links, declared provenance, and source/index freshness offline. Stable,
231
227
  bounded findings distinguish complete, partial, unavailable, and changing
@@ -240,7 +236,7 @@ See the [guide](docs/COMPILED-CONTEXT.md).
240
236
  <!-- public-truth:default-embed-model -->
241
237
  - **Default Embed Model**: all four built-in presets use `Qwen3-Embedding-0.6B-GGUF`; see the dated, fixture-scoped evidence below
242
238
  <!-- /public-truth -->
243
- - **Regression Fixes**: tightened phrase/negation/hyphen/underscore BM25 behavior, cleaned non-TTY hyperlink output, improved `gno doctor` chunking and embedding fingerprint visibility, and fixed the embedding autoresearch harness
239
+ - **Regression Fixes**: tightened phrase/negation/hyphen/underscore BM25 behavior, cleaned non-TTY hyperlink output, and improved `gno doctor` chunking and embedding fingerprint visibility
244
240
 
245
241
  ### Upgrading Existing Collections
246
242
 
@@ -1318,10 +1314,10 @@ Current product stance:
1318
1314
 
1319
1315
  Why Qwen is the current default:
1320
1316
 
1321
- - matches or exceeds `bge-m3` on the tiny canonical benchmark
1322
- - significantly beats `bge-m3` on the real GNO `src/serve` code slice
1323
- - also beats `bge-m3` on a pinned public-OSS code slice
1324
- - also beats `bge-m3` on the multilingual prose/docs benchmark lane
1317
+ - ties `bge-m3` on the small [canonical code benchmark](./evals/fixtures/code-embedding-benchmark/canonical.md) (vector nDCG@10 `0.95` each)
1318
+ - beats `bge-m3` on [GNO's own web server code](./evals/fixtures/code-embedding-benchmark/repo-serve.md) (`0.8102` vs `0.1003`)
1319
+ - beats `bge-m3` on [pinned open-source code slices](./evals/fixtures/code-embedding-benchmark/oss-slices.md) (`1.0` vs `0.6116`)
1320
+ - beats `bge-m3` on the multilingual prose/docs benchmark below
1325
1321
 
1326
1322
  Current trade-off:
1327
1323
 
@@ -1340,7 +1336,7 @@ bun run bench:general-embeddings --candidate qwen3-embedding-0.6b --write
1340
1336
 
1341
1337
  <!-- public-truth:general-embedding-benchmark -->
1342
1338
 
1343
- The immutable April 2026 FastAPI-docs run used 15 documents in five corpus
1339
+ The April 2026 FastAPI-docs run used 15 documents in five corpus
1344
1340
  languages (`en`, `de`, `fr`, `es`, `zh`) and 13 queries:
1345
1341
 
1346
1342
  - [bge-m3 incumbent](./evals/fixtures/general-embedding-benchmark/2026-04-06-bge-m3-incumbent.md): vector nDCG@10 `0.3503`, hybrid nDCG@10 `0.642`
@@ -1362,23 +1358,23 @@ languages.
1362
1358
 
1363
1359
  <!-- public-truth:cjk-lexical-benchmark -->
1364
1360
 
1365
- Lexical fallback has separate evidence. The immutable
1361
+ Lexical fallback has separate evidence. The
1366
1362
  [July 22, 2026 CJK result](./evals/fixtures/cjk-lexical-benchmark/2026-07-22.md)
1367
1363
  uses 21 synthetic documents and 25 same-language queries across Chinese,
1368
- Japanese, and Korean. Production BM25 lexical results and frozen floors:
1364
+ Japanese, and Korean. Production BM25 lexical results and the promotion floors:
1369
1365
 
1370
1366
  - Chinese: baseline Recall@10 `0.2222`, nDCG@10 `0.1481`, zero-result `0.7778`; promotion Recall@10 `0.4722`, nDCG@10 `0.3981`, maximum zero-result `0.5278`
1371
1367
  - Japanese: baseline Recall@10 `0.125`, nDCG@10 `0.125`, zero-result `0.875`; promotion Recall@10 `0.375`, nDCG@10 `0.375`, maximum zero-result `0.625`
1372
1368
  - Korean: baseline Recall@10 `0.5`, nDCG@10 `0.5`, zero-result `0.5`; promotion Recall@10 `0.75`, nDCG@10 `0.75`, maximum zero-result `0.25`
1373
1369
 
1374
- The
1370
+ The "promotion" values are the floors a CJK-aware lexical analyzer must reach
1371
+ before GNO ships one.
1375
1372
  [promotion-gates.md](./evals/fixtures/cjk-lexical-benchmark/promotion-gates.md)
1376
- also bind MRR, non-regression, and cost requirements. This lexical result does
1377
- not reduce or replace the semantic evidence above. All positive qrels use
1378
- relevance `3`, so
1379
- nDCG measures placement but not distinctions among positive gain grades.
1380
- Production tokenization is unchanged; improvements remain gated work for
1381
- `fn-109`.
1373
+ lists them along with MRR, non-regression, and cost requirements. No analyzer
1374
+ has met them, so production BM25 tokenization is unchanged. These lexical
1375
+ numbers do not measure semantic retrieval. All positive qrels use relevance
1376
+ `3`, so nDCG measures placement but not distinctions among positive gain
1377
+ grades.
1382
1378
 
1383
1379
  <!-- /public-truth -->
1384
1380
 
@@ -352,6 +352,12 @@ offline audits inspect parsed local links, explicitly declared capture/logical-
352
352
  record provenance, and observable source/index freshness. They never repair,
353
353
  rewrite, persist findings, judge factual truth, or replace retrieval.
354
354
 
355
+ `--max-findings` accepts `all` (MCP `maxFindings: "all"`) to export every
356
+ finding. Link findings carry `referenceKind`, `resolutionStatus`, and
357
+ `resolvedScope` in their evidence detail; ambiguous vault links list the tied
358
+ `candidates`. Report `truncation.snapshotTruncated` as "totals cover the
359
+ bounded snapshot, not the whole index".
360
+
355
361
  Treat exit `4` as a complete report with findings. Exit `5` or report status
356
362
  `partial`/`changed_during_audit` means evidence is unavailable, inconclusive,
357
363
  cancelled, truncated, or repeatedly changed—never healthy. Preserve stable
@@ -389,7 +395,7 @@ remaining steps apply under the default `full` profile.
389
395
  - MCP text is the compact `gno-context-agent-v1` evidence projection. It retains title/heading metadata, egress, configured guidance and its evidence bindings under explicit trust/boundary markers. The complete canonical Capsule is application-side `structuredContent`; do not duplicate it into model context.
390
396
  3. Use `gno_ask` only for explicit local verified synthesis. Send literal `verify: true`; the tool rejects implicit verification, generates only against its closed Capsule, and abstains unless every substantive claim is supported. Preserve exact spans, gaps, semantic capability state, and abstention. This does not guarantee corpus completeness or source truth.
391
397
  4. Use `gno_query` for interactive lookup or manual retrieval control. It returns snippets plus `uri`, `docid`, often `line`, and sometimes `context`. Treat `context` as user-configured guidance for interpreting that exact result; cite source content at the returned URI/lines, not the guidance itself. Bounded graph expansion is on by default; set `graph: false` or `noGraph: true` only for an explicit BM25/vector-only path.
392
- 5. Use graph/link expansion for relationship context: `gno_graph_query` for typed relationship traversal, `gno_graph_neighbors` for nearby documents, `gno_graph_path` for "how are X and Y connected?", `gno_links`/`gno_backlinks` for one-document link expansion, and `gno_similar` for semantic neighbors. Prefer explicit or typed edges over inferred, ambiguous, or similarity edges when confidence matters.
398
+ 5. Use graph/link expansion for relationship context: `gno_graph_query` for typed relationship traversal, `gno_graph_neighbors` for nearby documents, `gno_graph_path` for "how are X and Y connected?", `gno_links`/`gno_backlinks` for one-document link expansion, and `gno_similar` for semantic neighbors. Prefer explicit or typed edges over inferred, ambiguous, or similarity edges when confidence matters. Plain `[[Note]]` links resolve across collections of the same vault (link workspace), so backlinks and impact can name other collections; pass `collection`/`collections` to keep results inside the user's scope. Never tell users to rewrite links into `[[collection:Note]]` to make them resolve.
393
399
  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.
394
400
  7. Use `gno_get` with `fromLine`/`lineCount` for targeted reads, or `gno_multi_get` to batch top refs.
395
401
  8. Use `gno_section` only when you need a durable section locator or must re-resolve one after edits. Prefer search → `gno_get` for ordinary retrieval. `action=create` needs `ref` plus exactly one of `anchor`|`line`; `action=resolve` needs `ref` plus `target`. Cite or open content only for `exact`/`recovered` results, then follow the tool's ready-to-use `gno_get` guidance (`fromLine = lineStart`; `lineCount = lineEnd - lineStart + 1`). Never navigate or cite `ambiguous`/`stale`/`missing`.
@@ -418,6 +424,7 @@ changed source:
418
424
  gno changes --since 2026-07-20T00:00:00Z --json
419
425
  gno diff gno://notes/plan.md --json
420
426
  gno impact gno://notes/plan.md --max-depth 3 --json
427
+ gno impact gno://notes/plan.md --collection notes --json # stay in scope
421
428
  ```
422
429
 
423
430
  Treat cursors and change IDs as opaque. Journal results are bounded,
@@ -594,7 +594,8 @@ gno impact gno://notes/plan.md --max-depth 3 --json
594
594
  `changes` accepts an ISO time or opaque cursor and optional collection/limit.
595
595
  `diff` reports structural headings, links, and typed-relationship changes for
596
596
  one retained change. `impact` follows inbound evidence edges with explicit
597
- depth/node/edge/frontier/visited bounds. Expired journal history is reported,
597
+ depth/node/edge/frontier/visited bounds; repeat `-c, --collection <name>` to
598
+ keep the traversal (and every path step) inside those collections. Expired journal history is reported,
598
599
  not reconstructed.
599
600
 
600
601
  ## Private Retrieval Traces
@@ -679,6 +680,12 @@ gno backlinks <ref> [options]
679
680
  `--relation <type>` to query semantic typed edges instead of positional
680
681
  wiki/markdown links. Do not combine `--type` with `--edge-type`.
681
682
 
683
+ Plain `[[Note]]` and `[[Folder/Note]]` links resolve across all collections
684
+ that share one vault (the nearest `.obsidian` folder, or `workspaceRoot` in
685
+ the config): exact path, then same folder, then shallowest file; ties stay
686
+ unresolved and are listed by `gno audit links`. JSON names the other
687
+ collection (`resolvedCollection` for links, `sourceCollection` for backlinks).
688
+
682
689
  ### gno graph query
683
690
 
684
691
  Bounded typed-edge traversal from a document.
@@ -314,7 +314,8 @@ gno similar gno://notes/auth.md --cross-collection
314
314
  # In your documents:
315
315
 
316
316
  See [[API Design]] for details.
317
- Check [[work:Project Plan]] for cross-collection link.
317
+ Check [[Projects/Plan]] for a path link (resolves across collections of one vault).
318
+ Check [[work:Project Plan]] to name the target collection explicitly.
318
319
  Read [[Security#OAuth]] for specific section.
319
320
  ```
320
321
 
@@ -144,7 +144,9 @@ lives in `structuredContent`; its text projection is deliberately compact and
144
144
  should not be expanded back into duplicate model context.
145
145
 
146
146
  Use `gno_changes`, `gno_diff`, and `gno_impact` for retained metadata history
147
- and bounded dependency questions. Use `gno_trace_list` and `gno_trace_show` for
147
+ and bounded dependency questions. `gno_impact` takes optional `collections`
148
+ to keep the traversal in scope; links in a vault can resolve across
149
+ collections, so unscoped graph tools cover every collection. Use `gno_trace_list` and `gno_trace_show` for
148
150
  private local diagnostics. Invoke `gno_trace_label` only when the user
149
151
  explicitly provides a relevant, irrelevant, or missing-expected judgment.
150
152
  Trace export/replay/delete/purge and saved-Capsule watch lifecycle remain
Binary file
@@ -0,0 +1 @@
1
+ 2066003653182eb93964c5c058c86f691abf536f5093d1d0e8db2f382aedce19 gno-browser-clipper-v2.8.0.zip
@@ -21,5 +21,5 @@
21
21
  "content_security_policy": {
22
22
  "extension_pages": "script-src 'self'; object-src 'none'; connect-src http://127.0.0.1:*"
23
23
  },
24
- "version": "2.7.0"
24
+ "version": "2.8.0"
25
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gmickel/gno",
3
- "version": "2.7.0",
3
+ "version": "2.8.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",
@@ -89,6 +89,7 @@
89
89
  "smoke:serve-shutdown": "bun scripts/serve-shutdown-smoke.ts",
90
90
  "test:watcher:filesystem": "bun test test/serve/watch-service-filesystem.test.ts test/serve/resident-runtime.test.ts",
91
91
  "bench:watcher-reconciliation": "bun scripts/watcher-reconciliation-benchmark.ts",
92
+ "bench:session-import": "bun scripts/session-import-benchmark.ts",
92
93
  "smoke:watcher-reconciliation": "bun scripts/watcher-reconciliation-smoke.ts",
93
94
  "bench:code-embeddings": "bun scripts/code-embedding-benchmark.ts",
94
95
  "bench:code-embeddings:write": "bun scripts/code-embedding-benchmark.ts --write",
package/spec/cli.md CHANGED
@@ -263,6 +263,8 @@ gno status [--json|--md]
263
263
  {
264
264
  "name": "work",
265
265
  "path": "/path",
266
+ "workspaceRoot": "/vault",
267
+ "workspaceSource": "detected",
266
268
  "documentCount": 100,
267
269
  "chunkCount": 500,
268
270
  "embeddedCount": 500
@@ -624,9 +626,11 @@ refuses descent into dataless or availability-unknown directories
624
626
  (`DATALESS_DIRECTORY` skip, or the fail-closed codes above) and preserves
625
627
  previously indexed descendants under those unproven prefixes rather than
626
628
  marking them inactive. Eligible files have no availability `errorCode`.
627
- Evidence-qualified scope: Google Drive, iCloud Drive, and OneDrive only for the
628
- tested OS/provider configuration; OneDrive only for both validated immediate
629
- SharePoint library roots. No Windows/Linux guarantee; metadata/provider
629
+ Evidence-qualified scope: Google Drive (`My Drive` and immediate Shared drives
630
+ under `Shared drives/<drive>`; the `Shared drives` folder itself is
631
+ unsupported), iCloud Drive, and OneDrive only for the tested OS/provider
632
+ configuration; OneDrive only for the two validated immediate SharePoint library
633
+ roots. No Windows/Linux guarantee; metadata/provider
630
634
  bookkeeping may occur; GNO does not pin/evict/download as product behavior.
631
635
  Source availability is distinct from `egressPolicy` (where derived content may
632
636
  travel).
@@ -886,6 +890,15 @@ projection.
886
890
  content-free decision, lineage, partial disclosure, audit metadata, and
887
891
  remediation contract.
888
892
 
893
+ `workspaceSource` is `detected` (nearest `.obsidian/` ancestor-or-self of the
894
+ collection root), `configured` (`workspaceRoot` setting), `disabled`
895
+ (`workspaceRoot: false`), `unavailable` (the root or an ancestor could not be
896
+ inspected; links stay collection-scoped) or `none`. `workspaceRoot` is the
897
+ effective workspace root, present only for `detected`/`configured`, and is a
898
+ same-host-only field like `path`. Terminal output adds a `Link workspace:` line
899
+ per workspace collection. `gno collection list` reports the same per
900
+ collection as `effectiveWorkspaceRoot` and `workspaceSource`.
901
+
889
902
  ### gno audit
890
903
 
891
904
  Read-only, offline knowledge-integrity audits. This command is distinct from
@@ -901,8 +914,17 @@ gno audit [links|provenance|freshness|all] [--collection <name>...] \
901
914
  [--json] [--output <path>]
902
915
  ```
903
916
 
904
- The default category is `all`; `--max-findings` defaults to 100 and is bounded
905
- to 1–1000. Truncation limits returned findings but preserves exact totals.
917
+ The default category is `all`; `--max-findings` defaults to 100 and accepts an
918
+ integer from 1 to 100000 or `all`. `all` returns every finding of the bounded
919
+ audit snapshot, and per-rule caps follow the same value. Any other value
920
+ (zero, negative, non-integer, above 100000) is a validation error (exit 1)
921
+ that states the accepted range. Truncation limits returned findings but
922
+ preserves exact totals. The report's `truncation` block reports three separate
923
+ conditions: `findingsTruncated` (the finding cap cut the list),
924
+ `snapshotTruncated` (the bounded snapshot of 50,000 documents/links was cut, so
925
+ totals cover the snapshot only and are not complete-index totals), and
926
+ `evidenceTruncated` (evidence items, tied-candidate lists, or evidence detail
927
+ text were shortened).
906
928
  `--output` writes only the requested report artifact with local file
907
929
  permissions. Human output renders the same report represented by
908
930
  `audit-report.schema.json`.
@@ -924,6 +946,20 @@ healthy.
924
946
  - `4` — complete report with findings
925
947
  - `5` — partial, inconclusive, unavailable, or changed-during-audit evidence
926
948
 
949
+ Link findings resolve with the workspace-aware resolver (see
950
+ docs/ARCHITECTURE.md "Resolution"). Their evidence `detail` JSON carries
951
+ separate `referenceKind` (`wiki-name`, `wiki-path`, `explicit-collection`,
952
+ `markdown`), `resolutionStatus` (`unresolved`, `ambiguous`) and
953
+ `resolvedScope` (`same-collection`, `cross-collection`, `explicit-collection`,
954
+ or null when unresolved). Ambiguous workspace links add `candidateCount` and
955
+ `candidates` (tied candidate URIs in canonical path order); in a
956
+ collection-scoped audit, candidates outside the requested collections are
957
+ counted in `candidatesWithheld` and never named, and a list longer than the
958
+ detail bound sets `candidatesTruncated` (and `truncation.evidenceTruncated`).
959
+ Orphans stay "no incoming or outgoing resolved links", with connectivity drawn
960
+ from the whole index even when the audited documents are scoped; a tied link
961
+ connects nothing.
962
+
927
963
  The JSON contract is versioned as `gno://schemas/audit-report@1.0`. Finding IDs
928
964
  are stable SHA-256 identities derived from rule, normalized subject/location,
929
965
  and load-bearing evidence. Wall-clock timing and traversal order do not affect
@@ -4179,13 +4215,19 @@ Find active documents that depend on one document through inbound typed,
4179
4215
  wiki-link, or Markdown-link edges.
4180
4216
 
4181
4217
  ```bash
4182
- gno impact <doc> [--max-depth <n>] [--max-nodes <n>] [--max-edges <n>] [--frontier-limit <n>] [--visited-limit <n>] [--json]
4218
+ gno impact <doc> [-c, --collection <name>...] [--max-depth <n>] [--max-nodes <n>] [--max-edges <n>] [--frontier-limit <n>] [--visited-limit <n>] [--json]
4183
4219
  ```
4184
4220
 
4185
4221
  The traversal is cycle-safe and enforces depth, node, edge, frontier, and
4186
4222
  visited-row caps. Every impacted document includes one deterministic
4187
4223
  dependency-to-root evidence path. JSON output uses `impact.schema.json`.
4188
4224
 
4225
+ `--collection` (repeatable) limits the traversal to those collections: only
4226
+ their documents are visited, returned, or used as a path step, so a document
4227
+ outside the scope never bridges two in-scope documents. Omitted means every
4228
+ indexed collection. An unknown collection, or a `<doc>` outside the requested
4229
+ collections, is a validation error (exit 1).
4230
+
4189
4231
  **Exit Codes:**
4190
4232
 
4191
4233
  - 0: Success
@@ -172,7 +172,6 @@ CREATE TABLE IF NOT EXISTS documents (
172
172
  );
173
173
 
174
174
  CREATE INDEX IF NOT EXISTS idx_documents_collection ON documents(collection);
175
- CREATE INDEX IF NOT EXISTS idx_documents_active ON documents(active);
176
175
  CREATE INDEX IF NOT EXISTS idx_documents_mirror_hash ON documents(mirror_hash);
177
176
  CREATE INDEX IF NOT EXISTS idx_documents_docid ON documents(docid);
178
177
  CREATE INDEX IF NOT EXISTS idx_documents_uri ON documents(uri);
package/spec/mcp.md CHANGED
@@ -351,7 +351,8 @@ Collection names are case-insensitive on input and normalized to lowercase in re
351
351
  `gno_audit` is a read-only, offline tool that returns the same
352
352
  `gno://schemas/audit-report@1.0` report as `gno audit`. Its closed input accepts
353
353
  `category` (`links`, `provenance`, `freshness`, or `all`), collection/path/tag
354
- filters, and `maxFindings` (1–1000). `maxAgeDays`, `orphanRoots`, and
354
+ filters, and `maxFindings` (an integer from 1 to 100000, or `"all"` for every
355
+ finding of the bounded snapshot; default 100). `maxAgeDays`, `orphanRoots`, and
355
356
  `orphanIgnorePrefixes` are optional explicit policy inputs. Request
356
357
  cancellation returns a partial report rather than a false clean result. The
357
358
  tool is annotated with
@@ -1841,8 +1842,15 @@ pending), `sourceUnavailable`, `staleParser` and last import time, and the
1841
1842
  switches, pending and running work, last run, last success, next due time,
1842
1843
  recovery action). The result contains no host paths.
1843
1844
 
1845
+ Each call (and each `gno_sessions_import` call) first re-reads the server's
1846
+ config file and adopts it when it changed, so source changes made by another
1847
+ process show without a restart. An unchanged file is a no-op; a source-only
1848
+ change keeps open HTTP sessions.
1849
+
1844
1850
  **Errors:** `SESSIONS_NOT_CONFIGURED` when the server's config has no
1845
- `sessions` block.
1851
+ `sessions` block; `SESSIONS_RUNTIME_FAILURE` when the config file cannot be
1852
+ read (never answered from the stale config); `SESSIONS_BINDING_MISMATCH` when
1853
+ the file is now bound to a different index (not adopted).
1846
1854
 
1847
1855
  ### gno_sessions_import
1848
1856
 
@@ -2371,7 +2379,14 @@ structure is derived from `structureDelta.truncated`.
2371
2379
 
2372
2380
  ### gno_impact
2373
2381
 
2374
- Read-only inbound dependency traversal for `ref`. Inputs `maxDepth`,
2382
+ Read-only inbound dependency traversal for `ref`. Optional `collections`
2383
+ (array of collection names) limits the traversal as `gno impact --collection`
2384
+ does; omitted means every collection. Over Streamable HTTP, egress policy is
2385
+ checked on `collections` (every collection when omitted, because the result
2386
+ can reach any collection a link resolves into) and on the collection of `ref`;
2387
+ a docid `ref` is checked against every collection. The same rule applies to
2388
+ `gno_backlinks` and `gno_graph*` refs, and `gno_similar` with
2389
+ `crossCollection: true` is checked against every collection. Inputs `maxDepth`,
2375
2390
  `maxNodes`, `maxEdges`, `frontierLimit`, and `visitedLimit` use the same bounds
2376
2391
  as CLI/REST/SDK. Structured content is `impact.schema.json`; each impacted
2377
2392
  document includes a deterministic evidence path over typed or backlink
@@ -260,13 +260,27 @@
260
260
  "truncation": {
261
261
  "type": "object",
262
262
  "additionalProperties": false,
263
- "required": ["findingsTruncated", "maxFindings"],
263
+ "required": [
264
+ "findingsTruncated",
265
+ "maxFindings",
266
+ "snapshotTruncated",
267
+ "evidenceTruncated"
268
+ ],
264
269
  "properties": {
265
270
  "findingsTruncated": { "type": "boolean" },
266
271
  "maxFindings": {
267
- "type": "integer",
268
- "minimum": 1,
269
- "maximum": 1000
272
+ "oneOf": [
273
+ { "type": "integer", "minimum": 1, "maximum": 100000 },
274
+ { "const": "all" }
275
+ ]
276
+ },
277
+ "snapshotTruncated": {
278
+ "type": "boolean",
279
+ "description": "The bounded audit snapshot was cut; finding totals cover the snapshot only, not the whole index"
280
+ },
281
+ "evidenceTruncated": {
282
+ "type": "boolean",
283
+ "description": "Evidence items, candidate lists, or evidence detail text were shortened"
270
284
  }
271
285
  }
272
286
  },
@@ -28,6 +28,10 @@
28
28
  "type": "string",
29
29
  "description": "Source document title"
30
30
  },
31
+ "sourceCollection": {
32
+ "type": "string",
33
+ "description": "Collection of the linking document (may differ from the target's in a link workspace)"
34
+ },
31
35
  "linkText": {
32
36
  "type": "string",
33
37
  "description": "Link display text"
@@ -6,7 +6,7 @@
6
6
  "type": "array",
7
7
  "items": {
8
8
  "type": "object",
9
- "required": ["name", "path", "pattern", "include", "exclude"],
9
+ "required": ["name", "pattern", "include", "exclude"],
10
10
  "properties": {
11
11
  "name": {
12
12
  "type": "string",
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "path": {
17
17
  "type": "string",
18
- "description": "Absolute path to collection root directory"
18
+ "description": "Absolute path to collection root directory. Same-host callers only: omitted for a remote REST caller."
19
19
  },
20
20
  "pattern": {
21
21
  "type": "string",
@@ -39,6 +39,19 @@
39
39
  "languageHint": {
40
40
  "type": "string",
41
41
  "description": "BCP-47 language hint for the collection"
42
+ },
43
+ "workspaceRoot": {
44
+ "description": "Configured link workspace: an absolute path joins the collection to that workspace root; false keeps links inside the collection. Absent means auto-detect. Same-host callers only: omitted for a remote REST caller.",
45
+ "oneOf": [{ "type": "string" }, { "const": false }]
46
+ },
47
+ "effectiveWorkspaceRoot": {
48
+ "type": "string",
49
+ "description": "CLI list only: effective link workspace root (nearest .obsidian folder, or the configured root). Absent when links stay inside the collection."
50
+ },
51
+ "workspaceSource": {
52
+ "type": "string",
53
+ "enum": ["none", "detected", "configured", "disabled", "unavailable"],
54
+ "description": "CLI list only: how the link workspace was set"
42
55
  }
43
56
  }
44
57
  }
@@ -92,6 +92,8 @@
92
92
  "enum": [
93
93
  "exact-title",
94
94
  "exact-path",
95
+ "exact-name",
96
+ "tie-break",
95
97
  "path-fallback",
96
98
  "ambiguous-fallback",
97
99
  "similarity"
@@ -78,6 +78,10 @@
78
78
  "type": "string",
79
79
  "description": "URI of resolved target document"
80
80
  },
81
+ "resolvedCollection": {
82
+ "type": "string",
83
+ "description": "Collection of the resolved target (may differ from the source's in a link workspace)"
84
+ },
81
85
  "resolvedTitle": {
82
86
  "type": "string",
83
87
  "description": "Title of resolved target document"
@@ -90,24 +90,18 @@
90
90
  },
91
91
  "configPath": {
92
92
  "type": "string",
93
- "description": "Path to config file"
93
+ "description": "Path to config file. Same-host callers only: omitted for a remote REST or HTTP MCP caller."
94
94
  },
95
95
  "dbPath": {
96
96
  "type": "string",
97
- "description": "Path to SQLite database"
97
+ "description": "Path to SQLite database. Same-host callers only: omitted for a remote REST or HTTP MCP caller."
98
98
  },
99
99
  "collections": {
100
100
  "type": "array",
101
101
  "description": "Collection statistics",
102
102
  "items": {
103
103
  "type": "object",
104
- "required": [
105
- "name",
106
- "path",
107
- "documentCount",
108
- "chunkCount",
109
- "embeddedCount"
110
- ],
104
+ "required": ["name", "documentCount", "chunkCount", "embeddedCount"],
111
105
  "properties": {
112
106
  "name": {
113
107
  "type": "string",
@@ -115,7 +109,22 @@
115
109
  },
116
110
  "path": {
117
111
  "type": "string",
118
- "description": "Collection root path"
112
+ "description": "Collection root path. Same-host callers only: omitted for a remote REST or HTTP MCP caller."
113
+ },
114
+ "workspaceRoot": {
115
+ "type": "string",
116
+ "description": "Effective link workspace root: plain wiki links resolve across every collection under it. Present only when the collection is in a workspace. Same-host callers only: omitted for a remote REST or HTTP MCP caller."
117
+ },
118
+ "workspaceSource": {
119
+ "type": "string",
120
+ "enum": [
121
+ "none",
122
+ "detected",
123
+ "configured",
124
+ "disabled",
125
+ "unavailable"
126
+ ],
127
+ "description": "How the link workspace was set: detected (nearest .obsidian folder), configured (workspaceRoot setting), disabled (workspaceRoot: false), unavailable (root could not be inspected; links stay collection-scoped), none (no workspace)"
119
128
  },
120
129
  "documentCount": {
121
130
  "type": "integer",
@@ -595,13 +604,14 @@
595
604
  "type": "array",
596
605
  "items": {
597
606
  "type": "object",
598
- "required": ["label", "path", "reason"],
607
+ "required": ["label", "reason"],
599
608
  "properties": {
600
609
  "label": {
601
610
  "type": "string"
602
611
  },
603
612
  "path": {
604
- "type": "string"
613
+ "type": "string",
614
+ "description": "Suggested folder path. Same-host callers only: omitted for a remote REST or HTTP MCP caller."
605
615
  },
606
616
  "reason": {
607
617
  "type": "string"
@@ -883,10 +893,11 @@
883
893
  },
884
894
  "cache": {
885
895
  "type": "object",
886
- "required": ["path", "totalSizeBytes", "totalSizeLabel"],
896
+ "required": ["totalSizeBytes", "totalSizeLabel"],
887
897
  "properties": {
888
898
  "path": {
889
- "type": "string"
899
+ "type": "string",
900
+ "description": "Model cache directory. Same-host callers only: omitted for a remote REST or HTTP MCP caller."
890
901
  },
891
902
  "totalSizeBytes": {
892
903
  "type": "integer",
@@ -941,7 +952,6 @@
941
952
  "role",
942
953
  "uri",
943
954
  "cached",
944
- "path",
945
955
  "sizeBytes",
946
956
  "statusLabel"
947
957
  ],
@@ -957,7 +967,8 @@
957
967
  "type": "boolean"
958
968
  },
959
969
  "path": {
960
- "type": ["string", "null"]
970
+ "type": ["string", "null"],
971
+ "description": "Cached model file, or null when not cached. Same-host callers only: omitted for a remote REST or HTTP MCP caller."
961
972
  },
962
973
  "sizeBytes": {
963
974
  "type": ["integer", "null"],