@gmickel/gno 2.12.2 → 2.13.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 (58) hide show
  1. package/README.md +1 -1
  2. package/assets/skill/SKILL.md +1 -1
  3. package/assets/skill/cli-reference.md +23 -10
  4. package/assets/skill/mcp-reference.md +2 -0
  5. package/assets/spa-production.json.gz +0 -0
  6. package/browser-extension/artifacts/{gno-browser-clipper-v2.12.2.zip → gno-browser-clipper-v2.13.0.zip} +0 -0
  7. package/browser-extension/artifacts/gno-browser-clipper-v2.13.0.zip.sha256 +1 -0
  8. package/browser-extension/dist/manifest.json +1 -1
  9. package/package.json +1 -1
  10. package/spec/cli.md +66 -5
  11. package/spec/mcp.md +96 -1
  12. package/spec/output-schemas/convert.schema.json +97 -0
  13. package/spec/output-schemas/mcp-job-status.schema.json +17 -1
  14. package/spec/output-schemas/mcp-sync-result.schema.json +9 -2
  15. package/spec/output-schemas/search-results.schema.json +7 -0
  16. package/src/cli/commands/index-cmd.ts +50 -12
  17. package/src/cli/commands/query.ts +21 -8
  18. package/src/cli/commands/search.ts +11 -0
  19. package/src/cli/commands/vsearch.ts +17 -4
  20. package/src/cli/options.ts +19 -0
  21. package/src/cli/program.ts +79 -10
  22. package/src/core/collection-scope.ts +105 -0
  23. package/src/core/errors.ts +5 -0
  24. package/src/core/job-manager.ts +238 -19
  25. package/src/core/reindex-paths.ts +167 -0
  26. package/src/core/retrieval-trace-request.ts +1 -0
  27. package/src/ingestion/convert-file.ts +181 -0
  28. package/src/llm/registry.ts +20 -0
  29. package/src/mcp/http-egress.ts +21 -2
  30. package/src/mcp/tools/collection-scope.ts +25 -0
  31. package/src/mcp/tools/index-cmd.ts +66 -48
  32. package/src/mcp/tools/index.ts +74 -10
  33. package/src/mcp/tools/job-status.ts +7 -0
  34. package/src/mcp/tools/query.ts +28 -7
  35. package/src/mcp/tools/search.ts +4 -0
  36. package/src/mcp/tools/sync.ts +68 -60
  37. package/src/mcp/tools/vsearch.ts +9 -3
  38. package/src/pipeline/filters.ts +18 -3
  39. package/src/pipeline/graph-retrieval.ts +1 -0
  40. package/src/pipeline/hybrid.ts +15 -2
  41. package/src/pipeline/hydration.ts +7 -2
  42. package/src/pipeline/owner-fusion.ts +1 -0
  43. package/src/pipeline/search.ts +2 -0
  44. package/src/pipeline/types.ts +7 -0
  45. package/src/pipeline/vsearch.ts +10 -5
  46. package/src/sdk/client.ts +39 -11
  47. package/src/sdk/convert.ts +27 -0
  48. package/src/sdk/index.ts +2 -0
  49. package/src/sdk/types.ts +1 -1
  50. package/src/serve/jobs.ts +4 -1
  51. package/src/serve/public/components/IndexingProgress.tsx +25 -3
  52. package/src/serve/routes/api.ts +164 -24
  53. package/src/store/sqlite/adapter.ts +97 -27
  54. package/src/store/sqlite/eligibility.ts +4 -0
  55. package/src/store/types.ts +7 -0
  56. package/src/store/vector/sqlite-vec.ts +67 -15
  57. package/src/store/vector/variant-search.ts +41 -4
  58. package/browser-extension/artifacts/gno-browser-clipper-v2.12.2.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.12.2**. See [CHANGELOG.md](./CHANGELOG.md).
142
+ > Current source version: **v2.13.0**. See [CHANGELOG.md](./CHANGELOG.md).
143
143
 
144
144
  <!-- /public-truth -->
145
145
 
@@ -160,7 +160,7 @@ missing: `gno query diagnose` before falling back to grep.
160
160
 
161
161
  ```
162
162
  -n <num> Max results (default: 5)
163
- -c, --collection Filter to collection
163
+ -c, --collection Filter to collection (repeat for several; search/vsearch/query)
164
164
  --tags-any <t1,t2> Has ANY of these tags
165
165
  --tags-all <t1,t2> Has ALL of these tags
166
166
  --since <date> Modified after date (ISO: 2026-03-01)
@@ -151,6 +151,19 @@ gno index [options]
151
151
  | `--models-pull` | Download models if missing |
152
152
  | `--git-pull` | Git pull before indexing |
153
153
 
154
+ ### gno convert
155
+
156
+ Print the Markdown GNO would index for one file. Needs no config or index and
157
+ writes nothing.
158
+
159
+ ```bash
160
+ gno convert <file> [--json]
161
+ ```
162
+
163
+ `--json` adds `title`, `converter`, `mirrorHash` and `warnings`. Mail archives,
164
+ calendars and other multi-record formats are refused (`MULTI_DOCUMENT`); index
165
+ them in a collection instead.
166
+
154
167
  ### gno embed
155
168
 
156
169
  Generate embeddings only.
@@ -393,16 +406,16 @@ BM25 keyword search.
393
406
  gno search <query> [options]
394
407
  ```
395
408
 
396
- | Option | Default | Description |
397
- | ------------------ | ------- | -------------------------------- |
398
- | `-n` | 5 | Max results |
399
- | `--min-score` | 0 | Minimum score (0-1) |
400
- | `-c, --collection` | all | Filter to collection |
401
- | `--tags-any` | - | Filter: has ANY tag (comma-sep) |
402
- | `--tags-all` | - | Filter: has ALL tags (comma-sep) |
403
- | `--full` | false | Full content (not snippets) |
404
- | `--line-numbers` | false | Include line numbers |
405
- | `--lang` | auto | Language filter |
409
+ | Option | Default | Description |
410
+ | ------------------ | ------- | ------------------------------------------------------ |
411
+ | `-n` | 5 | Max results |
412
+ | `--min-score` | 0 | Minimum score (0-1) |
413
+ | `-c, --collection` | all | Filter to collection; repeat (`-c a -c b`) for several |
414
+ | `--tags-any` | - | Filter: has ANY tag (comma-sep) |
415
+ | `--tags-all` | - | Filter: has ALL tags (comma-sep) |
416
+ | `--full` | false | Full content (not snippets) |
417
+ | `--line-numbers` | false | Include line numbers |
418
+ | `--lang` | auto | Language filter |
406
419
 
407
420
  Output formats: `--json`, `--files`, `--csv`, `--md`, `--xml`
408
421
 
@@ -114,6 +114,8 @@ abstains unless every substantive claim is supported. This is a support
114
114
  classification against the retained Capsule, not a guarantee that the corpus
115
115
  is complete or its sources are true. Bounded graph expansion is on by default;
116
116
  set `graph: false` or `noGraph: true` only for an explicit BM25/vector-only path.
117
+ To search several collections, pass `collections: ["a", "b"]` to `gno_query`,
118
+ `gno_search` or `gno_vsearch` instead of `collection` (not both).
117
119
  Check `gno_peek` first for counts, backlog, serve liveness, or recent files.
118
120
  Use `gno_status` for activation, onboarding, or heavy health (missing vectors,
119
121
  stale embeddings). Use `gno_query_diagnose` when a known target document
Binary file
@@ -0,0 +1 @@
1
+ 477bb4440a241369687ec7c27d3720e4ce46b8f7139dfec842c5eee10d09e0ea gno-browser-clipper-v2.13.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.12.2"
24
+ "version": "2.13.0"
25
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gmickel/gno",
3
- "version": "2.12.2",
3
+ "version": "2.13.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",
package/spec/cli.md CHANGED
@@ -91,6 +91,7 @@ equivalent files fail closed as ambiguous.
91
91
  | sessions | yes | no | no | no | no | terminal |
92
92
  | get | yes | no | no | yes | no | terminal |
93
93
  | multi-get | yes | yes | no | yes | no | terminal |
94
+ | convert | yes | no | no | no | no | Markdown |
94
95
  | ls | yes | yes | no | yes | no | terminal |
95
96
  | daemon | yes¹ | no | no | no | no | terminal |
96
97
  | context add | no | no | no | no | no | terminal |
@@ -1245,13 +1246,14 @@ Build or update the index end-to-end (update + embed).
1245
1246
  **Synopsis:**
1246
1247
 
1247
1248
  ```bash
1248
- gno index [collection] [--no-embed] [--models-pull] [--git-pull] [--json] [--yes] [--lock-wait <duration>] [--no-wait]
1249
+ gno index [collection] [--path <path...>] [--no-embed] [--models-pull] [--git-pull] [--json] [--yes] [--lock-wait <duration>] [--no-wait]
1249
1250
  ```
1250
1251
 
1251
1252
  **Options:**
1252
1253
  | Option | Type | Description |
1253
1254
  |--------|------|-------------|
1254
1255
  | `--collection` | string | Scope to single collection |
1256
+ | `--path <path...>` | string[] | Reindex only these files of the collection (relative to its root, or absolute inside it); at most 256, not directories; requires a collection, not combinable with `--git-pull` |
1255
1257
  | `--no-embed` | boolean | Run ingestion only, skip embedding |
1256
1258
  | `--models-pull` | boolean | Download models if missing (prompts unless `--yes`) |
1257
1259
  | `--git-pull` | boolean | Run `git pull` in git repositories |
@@ -1264,6 +1266,7 @@ gno index [collection] [--no-embed] [--models-pull] [--git-pull] [--json] [--yes
1264
1266
 
1265
1267
  - Runs two separable stages: `lexical` (`update`) then `embed`
1266
1268
  - With `--no-embed`, runs the `lexical` stage only (embed stage `skipped`)
1269
+ - With `--path`, the `lexical` stage re-reads only the listed files and marks a listed file that no longer exists inactive; the collection's update command does not run. A path outside the collection root (including through a symlink), `--path` without a collection, or `--path` with `--git-pull` exits 1 (`VALIDATION`) before anything is written
1267
1270
  - Waits by default for the shared write lease; `--no-wait` fails immediately with exit 4
1268
1271
 
1269
1272
  **Staged, resumable contract:** each stage persists its own progress inside
@@ -1472,7 +1475,7 @@ BM25 keyword search over indexed documents.
1472
1475
  **Synopsis:**
1473
1476
 
1474
1477
  ```bash
1475
- gno search [query] [--query-file <path>] [-n <num>] [--min-score <num>] [-c <collection>] [--since <date>] [--until <date>] [--category <values>] [--author <text>] [--intent <text>] [--exclude <values>] [--tags-all <tags>] [--tags-any <tags>] [--full] [--line-numbers] [--lang <bcp47>] [--json|--files|--csv|--md|--xml]
1478
+ gno search [query] [--query-file <path>] [-n <num>] [--min-score <num>] [-c <collection>]... [--since <date>] [--until <date>] [--category <values>] [--author <text>] [--intent <text>] [--exclude <values>] [--tags-all <tags>] [--tags-any <tags>] [--full] [--line-numbers] [--lang <bcp47>] [--json|--files|--csv|--md|--xml]
1476
1479
  ```
1477
1480
 
1478
1481
  **Arguments:**
@@ -1488,7 +1491,7 @@ gno search [query] [--query-file <path>] [-n <num>] [--min-score <num>] [-c <col
1488
1491
  | `--query-file` | string | none | Read the query from a file; `-` reads stdin so the query never appears on argv. Do not also pass a positional query. |
1489
1492
  | `-n` | integer | 5 (20 for --json/--files) | Max results |
1490
1493
  | `--min-score` | number | 0 | Minimum score threshold |
1491
- | `-c, --collection` | string | all | Filter to collection |
1494
+ | `-c, --collection` | string[] | all | Filter to collection; repeat to search several collections (at most 256) |
1492
1495
  | `--since` | string | none | Modified-at lower bound (ISO date/time or relative token) |
1493
1496
  | `--until` | string | none | Modified-at upper bound (ISO date/time or relative token) |
1494
1497
  | `--category` | string | none | Filter to docs with matching category/content type (comma-separated) |
@@ -1621,6 +1624,19 @@ gno search "deploy staging" -n 10 --collection work
1621
1624
  gno search "contract" --json | jq '.[] | .uri'
1622
1625
  ```
1623
1626
 
1627
+ **Collection scope (`search`, `vsearch`, `query`):** one `-c` filters to that
1628
+ collection. Repeating `-c` (`-c work -c notes`) searches only those
1629
+ collections; the filter applies before every candidate limit, so other
1630
+ collections never take result slots, graph neighbours or rerank budget. Names
1631
+ are trimmed, lowercased, de-duplicated and sorted, and `--json` echoes them as
1632
+ `meta.collections` (`meta.collection` stays the single-collection field). More
1633
+ than 256 names after normalization exits 1 (`VALIDATION`); names that are not
1634
+ configured exit 2 with `Collection not found: <name>` or
1635
+ `Collections not found: <a>, <b>`, the same as a single unknown `-c`. When the
1636
+ listed collections resolve different embed, expand or rerank models, that role
1637
+ uses the unscoped default; when they agree, their shared model is used.
1638
+ `gno query diagnose` accepts one `-c` and exits 1 when given several.
1639
+
1624
1640
  ---
1625
1641
 
1626
1642
  Keyword retrieval applies collection/path scope, caller allowlists, tags, modified-date bounds, category and author filters, managed-memory visibility, and whole-document exclusions before its ranked candidate limit. Higher-ranked ineligible documents cannot consume that window; fewer eligible matches still produce a short result. Existing BM25 weights, query syntax, recency/project-affinity reranking and minimum-score behavior are unchanged.
@@ -1632,7 +1648,7 @@ Vector semantic search over indexed documents.
1632
1648
  **Synopsis:**
1633
1649
 
1634
1650
  ```bash
1635
- gno vsearch <query> [-n <num>] [--min-score <num>] [-c <collection>] [--since <date>] [--until <date>] [--category <values>] [--author <text>] [--intent <text>] [--exclude <values>] [--tags-all <tags>] [--tags-any <tags>] [--full] [--line-numbers] [--lang <bcp47>] [--json|--files|--csv|--md|--xml]
1651
+ gno vsearch <query> [-n <num>] [--min-score <num>] [-c <collection>]... [--since <date>] [--until <date>] [--category <values>] [--author <text>] [--intent <text>] [--exclude <values>] [--tags-all <tags>] [--tags-any <tags>] [--full] [--line-numbers] [--lang <bcp47>] [--json|--files|--csv|--md|--xml]
1636
1652
  ```
1637
1653
 
1638
1654
  **Options:** Same as `gno search` (including temporal/category/author, tag, and
@@ -1677,7 +1693,7 @@ Hybrid search combining BM25 and vector retrieval with optional expansion and re
1677
1693
  **Synopsis:**
1678
1694
 
1679
1695
  ```bash
1680
- gno query [query...] [--query-file <path>] [-n <num>] [--min-score <num>] [-c <collection>] [--since <date>] [--until <date>] [--category <values>] [--author <text>] [--intent <text>] [--exclude <values>] [-C <num>] [--tags-all <tags>] [--tags-any <tags>] [--full] [--line-numbers] [--lang <bcp47>] [--no-expand] [--no-rerank] [--graph] [--no-graph] [--query-mode <mode:text>]... [--explain] [--json|--files|--csv|--md|--xml]
1696
+ gno query [query...] [--query-file <path>] [-n <num>] [--min-score <num>] [-c <collection>]... [--since <date>] [--until <date>] [--category <values>] [--author <text>] [--intent <text>] [--exclude <values>] [-C <num>] [--tags-all <tags>] [--tags-any <tags>] [--full] [--line-numbers] [--lang <bcp47>] [--no-expand] [--no-rerank] [--graph] [--no-graph] [--query-mode <mode:text>]... [--explain] [--json|--files|--csv|--md|--xml]
1681
1697
  gno query diagnose <query> --target <doc> [-n <num>] [--min-score <num>] [-c <collection>] [--since <date>] [--until <date>] [--category <values>] [--author <text>] [--intent <text>] [--exclude <values>] [-C <num>] [--tags-all <tags>] [--tags-any <tags>] [--lang <bcp47>] [--no-expand] [--no-rerank] [--graph] [--no-graph] [--json]
1682
1698
  ```
1683
1699
 
@@ -2496,6 +2512,51 @@ See [Output Schemas](./output-schemas/multi-get.schema.json)
2496
2512
 
2497
2513
  ---
2498
2514
 
2515
+ ### gno convert
2516
+
2517
+ Print the Markdown GNO would index for one file. The file goes through the
2518
+ same conversion path as indexing (MIME detection, converter, canonical
2519
+ Markdown, mirror hash) with the default indexing limits, so the output equals
2520
+ the mirror `gno update` stores for the same bytes. No config, index, store or
2521
+ cache is read or written, and the command works with no GNO config present.
2522
+
2523
+ **Synopsis:**
2524
+
2525
+ ```bash
2526
+ gno convert <file> [--json]
2527
+ ```
2528
+
2529
+ **Arguments:**
2530
+ | Arg | Type | Description |
2531
+ |-----|------|-------------|
2532
+ | `<file>` | path | One regular file (a symlink to a regular file is followed) |
2533
+
2534
+ **Output:**
2535
+
2536
+ - Terminal: exactly the Markdown on stdout; conversion warnings go to stderr.
2537
+ - `--json`: [convert@1.0](./output-schemas/convert.schema.json) with `source`
2538
+ (`path`, `mime`, `ext`, `sizeBytes`), `converter` (`id`, `version`),
2539
+ `title`, `languageHint`, `markdown`, `mirrorHash` (SHA-256 hex, as stored by
2540
+ indexing) and `warnings`.
2541
+
2542
+ Single-document formats are supported. Formats whose adapters split one file
2543
+ into several records (mail archives, calendars and the other record adapters)
2544
+ are refused, because their record identity comes from the collection and path.
2545
+
2546
+ **Errors:** the standard error envelope, with `details.reason`:
2547
+
2548
+ | Case | `details.reason` | Exit |
2549
+ | ------------------------------------------------------------ | -------------------------------------------------------------- | ---- |
2550
+ | Path missing, a directory or another non-regular file | `NOT_FOUND` | 1 |
2551
+ | Larger than the indexing size limit (checked before reading) | `TOO_LARGE` | 1 |
2552
+ | No converter for the type | `UNSUPPORTED` | 1 |
2553
+ | Multi-record format (`details.format` names it) | `MULTI_DOCUMENT` | 1 |
2554
+ | Converter failure, timeout, memory limit or corrupt input | the converter's code (`CORRUPT`, `PERMISSION`, `TIMEOUT`, ...) | 2 |
2555
+
2556
+ The SDK exposes the same operation as `convertFile(path)`.
2557
+
2558
+ ---
2559
+
2499
2560
  ### gno ls
2500
2561
 
2501
2562
  List documents in a collection or prefix.
package/spec/mcp.md CHANGED
@@ -230,6 +230,50 @@ All write tools acquire an OS-backed advisory lock at `.mcp-write.lock` under th
230
230
  If another process holds the lock, tools return `LOCKED`.
231
231
  For async jobs, the lock is held for the full job duration.
232
232
 
233
+ ### Reindex Queue
234
+
235
+ `gno_sync` and `gno_index` (and REST `POST /api/sync`) never reject a request
236
+ because another job in the same server is running:
237
+
238
+ - With no job running or waiting, the request starts at once (`status:
239
+ "started"`), taking the write lock as above; another process holding it
240
+ returns `LOCKED`.
241
+ - Otherwise it is queued (`status: "queued"`) and starts when the jobs ahead
242
+ of it finish, taking the write lock then. A queued job that cannot get the
243
+ lock fails with `LOCKED` in its job status.
244
+ - A request joins a waiting job of the same tool and collection and returns
245
+ its `jobId`, so any number of requests cause at most one more pass:
246
+ - a request with `paths` joins any such job (its files are added to the
247
+ pass, or covered by a whole-collection pass);
248
+ - a whole-collection request joins a job that only has path requests
249
+ (widening it and setting its options) or a whole-collection job with the
250
+ same `gitPull` / `runUpdateCmd`. Whole-collection requests with different
251
+ options stay separate passes, and a path-only pass never runs `gitPull`
252
+ or an update command.
253
+ - a path-only job whose merged files pass 256 becomes a whole-collection
254
+ pass with no `gitPull` or update command.
255
+ - A queued pass uses the configuration of the latest request that joined it;
256
+ `gno_index` resolves its embedding model when the pass starts, so a model
257
+ or preset change while it waits is picked up.
258
+ - At most 64 distinct scopes wait at once; a new scope beyond that returns
259
+ `QUEUE_FULL`. Retry after the running job finishes.
260
+ - The queue lives in the server process. Jobs still waiting when it stops are
261
+ failed at shutdown and unknown after a restart (`NOT_FOUND` from
262
+ `gno_job_status`); the index stays consistent.
263
+
264
+ ### Path-Level Reindex
265
+
266
+ `paths` on `gno_sync` / `gno_index` reindexes only the listed files of one
267
+ collection: each path is relative to the collection root or absolute inside
268
+ it, and only those files are re-read. A listed file that no longer exists is
269
+ marked inactive. `paths` requires `collection` and cannot be combined with
270
+ `gitPull` or `runUpdateCmd`; an empty list, more than 256 paths, a
271
+ directory, a path outside the root (including through a symlink) or a
272
+ non-string entry is rejected before anything is queued (`INVALID_INPUT` /
273
+ `INVALID_PATH`), and so is a path the collection's own `pattern`, `include`
274
+ or `exclude` rules leave out. To reindex a directory or more than 256 files,
275
+ reindex the whole collection.
276
+
233
277
  `gno_remember` is the one write tool whose adapter takes no lock of its own:
234
278
  the core memory service acquires the same `.mcp-write.lock` lease for every
235
279
  memory write, so an MCP remember and a CLI writer serialise on one lease. A
@@ -603,6 +647,19 @@ opaque remote hints. The server never stats, realpaths, discovers repositories,
603
647
  or infers its cwd from them; remote hints produce redacted zero-affinity
604
648
  metadata and no ranking change.
605
649
 
650
+ `gno_search`, `gno_vsearch` and `gno_query` also accept an optional
651
+ `collections` allowlist. The filter applies before every candidate limit (BM25,
652
+ vector, fusion, graph expansion, hydration and rerank), so unlisted collections
653
+ never take result slots. Names are trimmed, lowercased, de-duplicated and
654
+ sorted; responses echo them as `meta.collections`, and `meta.collection` keeps
655
+ its single-collection meaning. Passing both `collection` and `collections`, an
656
+ empty list, a non-string member, or more than 256 names after normalization is
657
+ a `VALIDATION` error; unconfigured names give `Collection not found: <name>` /
658
+ `Collections not found: <a>, <b>`. Over HTTP the egress check covers exactly
659
+ the listed collections, so the most restrictive listed collection decides.
660
+ When the listed collections resolve different models for a role, that role uses
661
+ the unscoped default. `gno_query_diagnose` does not accept `collections`.
662
+
606
663
  **Input Schema:**
607
664
 
608
665
  ```json
@@ -617,6 +674,11 @@ metadata and no ranking change.
617
674
  "type": "string",
618
675
  "description": "Optional collection name to filter results"
619
676
  },
677
+ "collections": {
678
+ "type": "array",
679
+ "items": { "type": "string" },
680
+ "description": "Optional allowlist: filter to any of these collection names (1-256); use instead of collection"
681
+ },
620
682
  "limit": {
621
683
  "type": "integer",
622
684
  "description": "Maximum number of results (1-100)",
@@ -738,6 +800,11 @@ Vector semantic search over indexed documents.
738
800
  "type": "string",
739
801
  "description": "Optional collection name to filter results"
740
802
  },
803
+ "collections": {
804
+ "type": "array",
805
+ "items": { "type": "string" },
806
+ "description": "Optional allowlist: filter to any of these collection names (1-256); use instead of collection"
807
+ },
741
808
  "limit": {
742
809
  "type": "integer",
743
810
  "description": "Maximum number of results (1-100)",
@@ -822,6 +889,11 @@ Hybrid search combining BM25 and vector retrieval with optional expansion and re
822
889
  "type": "string",
823
890
  "description": "Optional collection name to filter results"
824
891
  },
892
+ "collections": {
893
+ "type": "array",
894
+ "items": { "type": "string" },
895
+ "description": "Optional allowlist: filter to any of these collection names (1-256); use instead of collection"
896
+ },
825
897
  "limit": {
826
898
  "type": "integer",
827
899
  "description": "Maximum number of results (1-100)",
@@ -2719,6 +2791,12 @@ Reindex one or all collections (write-enabled).
2719
2791
  "type": "boolean",
2720
2792
  "description": "Run updateCmd before indexing (default: false for MCP)",
2721
2793
  "default": false
2794
+ },
2795
+ "paths": {
2796
+ "type": "array",
2797
+ "items": { "type": "string" },
2798
+ "maxItems": 256,
2799
+ "description": "Reindex only these files of the collection (see Path-Level Reindex); requires collection"
2722
2800
  }
2723
2801
  }
2724
2802
  }
@@ -2726,6 +2804,9 @@ Reindex one or all collections (write-enabled).
2726
2804
 
2727
2805
  **Output Schema:** `gno://schemas/mcp-sync-result@1.0`
2728
2806
 
2807
+ `status` is `started` or `queued` (see [Reindex Queue](#reindex-queue));
2808
+ `paths` echoes the resolved collection-relative paths of a path-level sync.
2809
+
2729
2810
  ---
2730
2811
 
2731
2812
  ### gno_embed
@@ -2818,6 +2899,12 @@ Full index: sync files + generate embeddings (write-enabled). Runs as background
2818
2899
  "type": "boolean",
2819
2900
  "description": "Run git pull before sync",
2820
2901
  "default": false
2902
+ },
2903
+ "paths": {
2904
+ "type": "array",
2905
+ "items": { "type": "string" },
2906
+ "maxItems": 256,
2907
+ "description": "Reindex only these files of the collection (see Path-Level Reindex); requires collection"
2821
2908
  }
2822
2909
  }
2823
2910
  }
@@ -2852,6 +2939,7 @@ Full index: sync files + generate embeddings (write-enabled). Runs as background
2852
2939
 
2853
2940
  - Requires `--enable-write` flag
2854
2941
  - Runs sync phase first, then embed phase
2942
+ - `status` is `started` or `queued` (see [Reindex Queue](#reindex-queue)); a path-level index adds `paths`
2855
2943
  - `runUpdateCmd` is always false for MCP (security)
2856
2944
  - Fails fast if embedding model not cached
2857
2945
  - Poll job status with `gno_job_status`
@@ -2902,6 +2990,11 @@ Get status of a background job.
2902
2990
 
2903
2991
  **Output Schema:** `gno://schemas/mcp-job-status@1.0`
2904
2992
 
2993
+ `status` is `queued` while a reindex job waits behind another job, then
2994
+ `running`, `completed` or `failed`. Reindex jobs also report `scope`: the
2995
+ collection (`null` for all) and the merged `paths` (`null` for the whole
2996
+ collection).
2997
+
2905
2998
  ---
2906
2999
 
2907
3000
  ### gno_list_jobs
@@ -3062,8 +3155,9 @@ Resource errors use standard MCP error responses.
3062
3155
  - `HAS_REFERENCES` — Collection referenced by contexts
3063
3156
  - `INVALID_PATH` — Path violates safety rules
3064
3157
  - `PATH_NOT_FOUND` — Path does not exist
3065
- - `JOB_CONFLICT` — Another job is already running
3158
+ - `JOB_CONFLICT` — Another job is already running (not returned by `gno_sync` / `gno_index`, which queue instead)
3066
3159
  - `LOCKED` — Another MCP process holds the write lock
3160
+ - `QUEUE_FULL` — Too many reindex scopes are already waiting; retry later
3067
3161
  - `CAPTURE_SYNC_FAILED` — `gno_capture` wrote the file but lexical sync failed
3068
3162
  - `WRITE_DISABLED` — Write tool dispatched while writes are disabled
3069
3163
  - `MEMORY_*` — Memory contract errors from `gno_recall` / `gno_remember`;
@@ -3106,6 +3200,7 @@ Clients should check schema version for compatibility.
3106
3200
  - No persistent state between tool calls
3107
3201
  - Each tool call is independent
3108
3202
  - Server handles concurrent tool calls sequentially; an accepted background job (`gno_sync`, `gno_embed`, `gno_index`) waits for the call in progress, then runs without holding that queue, so reads are not blocked while it runs
3203
+ - The retrieval tools (`gno_search`, `gno_vsearch`, `gno_query`, `gno_get`, `gno_multi_get`, `gno_status`, `gno_list_tags`, `gno_links`, `gno_backlinks`, `gno_similar`) read on a second connection, so they see only committed index data, never a sync batch still being written
3109
3204
 
3110
3205
  ---
3111
3206
 
@@ -0,0 +1,97 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "gno://schemas/convert@1.0",
4
+ "title": "GNO Convert Result",
5
+ "description": "Output of gno convert --json and SDK convertFile: the Markdown GNO would index for one file",
6
+ "type": "object",
7
+ "required": [
8
+ "schemaVersion",
9
+ "source",
10
+ "converter",
11
+ "title",
12
+ "languageHint",
13
+ "markdown",
14
+ "mirrorHash",
15
+ "warnings"
16
+ ],
17
+ "additionalProperties": false,
18
+ "properties": {
19
+ "schemaVersion": {
20
+ "const": "convert@1.0"
21
+ },
22
+ "source": {
23
+ "type": "object",
24
+ "required": ["path", "mime", "ext", "sizeBytes"],
25
+ "additionalProperties": false,
26
+ "properties": {
27
+ "path": {
28
+ "type": "string",
29
+ "minLength": 1,
30
+ "description": "Absolute path of the converted file"
31
+ },
32
+ "mime": {
33
+ "type": "string",
34
+ "minLength": 1,
35
+ "description": "Detected MIME type"
36
+ },
37
+ "ext": {
38
+ "type": "string",
39
+ "description": "File extension, including the dot"
40
+ },
41
+ "sizeBytes": {
42
+ "type": "integer",
43
+ "minimum": 0
44
+ }
45
+ }
46
+ },
47
+ "converter": {
48
+ "type": "object",
49
+ "required": ["id", "version"],
50
+ "additionalProperties": false,
51
+ "properties": {
52
+ "id": {
53
+ "type": "string",
54
+ "minLength": 1
55
+ },
56
+ "version": {
57
+ "type": "string",
58
+ "minLength": 1
59
+ }
60
+ }
61
+ },
62
+ "title": {
63
+ "type": ["string", "null"],
64
+ "description": "Title from conversion, or null"
65
+ },
66
+ "languageHint": {
67
+ "type": ["string", "null"],
68
+ "description": "BCP-47 language hint from conversion, or null"
69
+ },
70
+ "markdown": {
71
+ "type": "string",
72
+ "description": "Canonical Markdown, identical to the mirror indexing stores"
73
+ },
74
+ "mirrorHash": {
75
+ "type": "string",
76
+ "pattern": "^[a-f0-9]{64}$",
77
+ "description": "SHA-256 hex of the canonical Markdown, as stored by indexing"
78
+ },
79
+ "warnings": {
80
+ "type": "array",
81
+ "items": {
82
+ "type": "object",
83
+ "required": ["code", "message"],
84
+ "additionalProperties": false,
85
+ "properties": {
86
+ "code": {
87
+ "type": "string",
88
+ "minLength": 1
89
+ },
90
+ "message": {
91
+ "type": "string"
92
+ }
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
@@ -223,7 +223,7 @@
223
223
  "status": {
224
224
  "type": "string",
225
225
  "description": "Job status",
226
- "enum": ["running", "completed", "failed"]
226
+ "enum": ["queued", "running", "completed", "failed"]
227
227
  },
228
228
  "startedAt": {
229
229
  "type": "string",
@@ -247,6 +247,22 @@
247
247
  "type": "string",
248
248
  "description": "Error message if failed"
249
249
  },
250
+ "scope": {
251
+ "type": "object",
252
+ "description": "Reindex jobs: what the job covers after merging requests",
253
+ "required": ["collection", "paths"],
254
+ "properties": {
255
+ "collection": {
256
+ "type": ["string", "null"],
257
+ "description": "Collection name, or null for all collections"
258
+ },
259
+ "paths": {
260
+ "type": ["array", "null"],
261
+ "description": "Collection-relative files, or null for the whole collection",
262
+ "items": { "type": "string" }
263
+ }
264
+ }
265
+ },
250
266
  "serverInstanceId": {
251
267
  "type": "string",
252
268
  "description": "Server instance UUID",
@@ -19,8 +19,15 @@
19
19
  },
20
20
  "status": {
21
21
  "type": "string",
22
- "description": "Job status",
23
- "enum": ["started"]
22
+ "description": "started: the job is running; queued: it waits behind another write job (requests for the same scope share one queued job)",
23
+ "enum": ["started", "queued"]
24
+ },
25
+ "paths": {
26
+ "type": "array",
27
+ "description": "Collection-relative files this sync reindexes; absent for a whole-collection sync",
28
+ "items": {
29
+ "type": "string"
30
+ }
24
31
  },
25
32
  "options": {
26
33
  "type": "object",
@@ -454,6 +454,13 @@
454
454
  "type": "string",
455
455
  "description": "Collection filter if applied"
456
456
  },
457
+ "collections": {
458
+ "type": "array",
459
+ "items": { "type": "string" },
460
+ "minItems": 1,
461
+ "maxItems": 256,
462
+ "description": "Normalized collection allowlist if applied (sorted, lowercase)"
463
+ },
457
464
  "intent": {
458
465
  "type": "string",
459
466
  "description": "Disambiguating context used to steer retrieval without being searched directly"