@gmickel/gno 1.12.4 → 1.14.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 (61) hide show
  1. package/README.md +126 -59
  2. package/assets/skill/SKILL.md +8 -1
  3. package/assets/skill/cli-reference.md +18 -7
  4. package/assets/skill/mcp-reference.md +22 -3
  5. package/package.json +3 -1
  6. package/src/app/constants.ts +43 -10
  7. package/src/app/index-name.ts +127 -0
  8. package/src/cli/commands/doctor-activation.ts +151 -0
  9. package/src/cli/commands/doctor.ts +41 -16
  10. package/src/cli/commands/get.ts +18 -0
  11. package/src/cli/commands/mcp/atomic-config-write.ts +118 -0
  12. package/src/cli/commands/mcp/config-discovery.ts +42 -0
  13. package/src/cli/commands/mcp/config-editors.ts +432 -0
  14. package/src/cli/commands/mcp/config.ts +63 -160
  15. package/src/cli/commands/mcp/install.ts +75 -37
  16. package/src/cli/commands/mcp/paths.ts +141 -136
  17. package/src/cli/commands/mcp/server-entry.ts +66 -0
  18. package/src/cli/commands/mcp/status.ts +189 -57
  19. package/src/cli/commands/mcp/target-display.ts +30 -0
  20. package/src/cli/commands/mcp/uninstall.ts +29 -31
  21. package/src/cli/commands/mcp/yaml-config-editor.ts +257 -0
  22. package/src/cli/commands/mcp/yaml-layout-scanner.ts +447 -0
  23. package/src/cli/commands/multi-get.ts +31 -6
  24. package/src/cli/commands/status.ts +107 -11
  25. package/src/cli/program.ts +66 -20
  26. package/src/core/activation-connector-health.ts +19 -0
  27. package/src/core/activation-probe-plan.ts +321 -0
  28. package/src/core/activation-probe.ts +138 -0
  29. package/src/core/activation-receipt-store.ts +39 -0
  30. package/src/core/activation-status.ts +513 -0
  31. package/src/core/activation-verifier.ts +416 -0
  32. package/src/core/connector-environment.ts +68 -0
  33. package/src/core/connector-policy.ts +233 -0
  34. package/src/core/connector-verification-target.ts +150 -0
  35. package/src/core/connector-verifier.ts +497 -0
  36. package/src/core/indexed-reference.ts +33 -8
  37. package/src/core/runtime-entrypoint.ts +24 -0
  38. package/src/mcp/activation-verification-mode.ts +4 -0
  39. package/src/mcp/server.ts +9 -2
  40. package/src/sdk/client.ts +7 -0
  41. package/src/sdk/types.ts +1 -0
  42. package/src/serve/activation-health.ts +91 -0
  43. package/src/serve/background-runtime.ts +11 -1
  44. package/src/serve/connectors.ts +164 -19
  45. package/src/serve/public/components/BootstrapStatus.tsx +94 -1
  46. package/src/serve/public/components/FirstRunWizard.tsx +13 -51
  47. package/src/serve/public/components/HealthCenter.tsx +8 -2
  48. package/src/serve/public/globals.built.css +1 -1
  49. package/src/serve/public/pages/Connectors.tsx +216 -55
  50. package/src/serve/public/pages/Dashboard.tsx +1 -0
  51. package/src/serve/routes/api.ts +152 -8
  52. package/src/serve/server.ts +44 -9
  53. package/src/serve/status-model.ts +4 -0
  54. package/src/serve/status.ts +79 -35
  55. package/src/store/activation-receipts.ts +390 -0
  56. package/src/store/index.ts +8 -0
  57. package/src/store/migrations/012-activation-receipts.ts +38 -0
  58. package/src/store/migrations/013-fts-sync-marker.ts +39 -0
  59. package/src/store/migrations/index.ts +4 -0
  60. package/src/store/sqlite/adapter.ts +313 -53
  61. package/src/store/types.ts +118 -0
package/README.md CHANGED
@@ -92,9 +92,18 @@ gno daemon --detach # headless continuous indexing (background; --status / --st
92
92
 
93
93
  ## What's New
94
94
 
95
- > Latest release: [v1.8.0](./CHANGELOG.md#180---2026-06-05)
95
+ <!-- public-truth:current-version -->
96
+
97
+ > Current release: **v1.14.0** — see [CHANGELOG.md](./CHANGELOG.md)
98
+
99
+ <!-- /public-truth -->
100
+
96
101
  > Full release history: [CHANGELOG.md](./CHANGELOG.md)
97
102
 
103
+ - **Retrieval-proven activation**: `gno status`, `gno doctor`, REST, and the
104
+ Web/Desktop dashboard now share a per-folder lexical retrieval proof. Local
105
+ semantic readiness remains independent, and installed MCP targets can run an
106
+ explicit read-only retrieval smoke from Connectors.
98
107
  - **Second-brain capture**: `gno capture`, REST `/api/capture`, SDK
99
108
  `client.capture()`, MCP `gno_capture`, and Web UI Quick Capture write
100
109
  provenance-rich notes from text, stdin, or files, including typed presets for
@@ -105,7 +114,9 @@ gno daemon --detach # headless continuous indexing (background; --status / --st
105
114
  - **Publish to [gno.sh](https://gno.sh/publish)**: new `gno publish export` CLI and Web UI action produce a self-contained artifact you upload to the hosted reader — public, secret, invite-only, or locally encrypted before upload
106
115
  - **Retrieval Quality Upgrade**: stronger BM25 lexical handling, code-aware chunking, terminal result hyperlinks, and per-collection model overrides
107
116
  - **Code Embedding Benchmarks**: new benchmark workflow across canonical, real-GNO, and pinned OSS slices for comparing alternate embedding models
108
- - **Default Embed Model**: built-in presets now use `Qwen3-Embedding-0.6B-GGUF` after it beat `bge-m3` on both code and multilingual prose benchmark lanes
117
+ <!-- public-truth:default-embed-model -->
118
+ - **Default Embed Model**: all four built-in presets use `Qwen3-Embedding-0.6B-GGUF`; see the dated, fixture-scoped evidence below
119
+ <!-- /public-truth -->
109
120
  - **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
110
121
 
111
122
  ### Upgrading Existing Collections
@@ -197,7 +208,11 @@ Manage the detached process with `gno daemon --status` and `gno daemon --stop`.
197
208
 
198
209
  ### Install GNO
199
210
 
200
- Requires [Bun](https://bun.sh/) >= 1.3.0.
211
+ <!-- public-truth:runtime -->
212
+
213
+ Requires [Bun](https://bun.sh/) >=1.3.0.
214
+
215
+ <!-- /public-truth -->
201
216
 
202
217
  ```bash
203
218
  bun install -g @gmickel/gno
@@ -209,16 +224,27 @@ bun install -g @gmickel/gno
209
224
  brew install sqlite3
210
225
  ```
211
226
 
212
- Verify everything works:
227
+ Verify the local installation and corpus-derived lexical retrieval:
213
228
 
214
229
  ```bash
215
230
  gno doctor
231
+ gno status --json
216
232
  ```
217
233
 
218
- **Windows**: current validated target is `windows-x64`, with a packaged
234
+ `gno status` is passive with respect to models and connectors and exits 0 even
235
+ when its structured activation state is degraded. `gno doctor` exits 2 when any
236
+ configured folder fails the lexical proof; semantic models may still be pending
237
+ without blocking BM25 search.
238
+
239
+ <!-- public-truth:supported-platforms -->
240
+
241
+ GNO supports macOS, Linux, and Windows. The current validated Windows target is
242
+ `windows-x64`, with a packaged
219
243
  desktop beta zip now published on GitHub Releases. See
220
244
  [docs/WINDOWS.md](./docs/WINDOWS.md) for support scope and validation notes.
221
245
 
246
+ <!-- /public-truth -->
247
+
222
248
  Keep an index fresh continuously without opening the Web UI:
223
249
 
224
250
  ```bash
@@ -248,9 +274,16 @@ gno mcp install --target codex # OpenAI Codex CLI
248
274
  gno mcp install --target opencode # OpenCode
249
275
  gno mcp install --target amp # Amp
250
276
  gno mcp install --target lmstudio # LM Studio
251
- gno mcp install --target librechat # LibreChat
277
+ gno mcp install --target librechat --scope project # LibreChat
252
278
  ```
253
279
 
280
+ Each install records an absolute Bun/package entrypoint plus the active index,
281
+ config, data directory, and model cache, so desktop clients open the same GNO
282
+ workspace without relying on shell `PATH` or `GNO_*` inheritance. Inspect the
283
+ exact command, arguments, and workspace values with
284
+ `gno mcp install --dry-run --json`. If GNO is already configured in that
285
+ target, add `--force` to preview the replacement without writing it.
286
+
254
287
  Check status: `gno mcp status`
255
288
 
256
289
  #### Skills (Claude Code, Codex, OpenCode, OpenClaw)
@@ -340,6 +373,7 @@ import { createGnoClient } from "@gmickel/gno";
340
373
 
341
374
  const client = await createGnoClient({
342
375
  configPath: "/Users/me/.config/gno/index.yml",
376
+ indexName: "research",
343
377
  });
344
378
 
345
379
  // Fast exact search
@@ -372,7 +406,7 @@ await client.close();
372
406
 
373
407
  Core SDK surface:
374
408
 
375
- - `createGnoClient({ config | configPath, dbPath? })`
409
+ - `createGnoClient({ config | configPath, dbPath?, indexName? })`
376
410
  - `search`, `vsearch`, `query`, `ask`
377
411
  - `get`, `multiGet`, `list`, `status`
378
412
  - `update`, `embed`, `index`
@@ -514,7 +548,9 @@ Connect GNO to Claude Desktop, Cursor, Raycast, and more:
514
548
 
515
549
  ![GNO MCP](./assets/screenshots/mcp.jpg)
516
550
 
517
- GNO exposes tools via [Model Context Protocol](https://modelcontextprotocol.io):
551
+ GNO exposes 17 tools by default via [Model Context Protocol](https://modelcontextprotocol.io),
552
+ including the core retrieval tools below. Starting MCP with `--enable-write`
553
+ adds 11 opt-in mutation tools, for 28 total.
518
554
 
519
555
  | Tool | Description |
520
556
  | :-------------- | :------------------------------------ |
@@ -529,7 +565,9 @@ GNO exposes tools via [Model Context Protocol](https://modelcontextprotocol.io):
529
565
  | `gno_graph` | Get knowledge graph (nodes and edges) |
530
566
  | `gno_status` | Index health check |
531
567
 
532
- **Design**: MCP tools are retrieval-only. Your AI assistant (Claude, GPT-4) synthesizes answers from retrieved context. Best retrieval (GNO) + best reasoning (your LLM).
568
+ **Design**: Default MCP mode is read-only: retrieval, graph, status, and job
569
+ inspection. Your AI assistant synthesizes answers from retrieved context. Write
570
+ tools are available only through the explicit `--enable-write` opt-in.
533
571
 
534
572
  [MCP setup guide →](https://gno.sh/docs/MCP/)
535
573
 
@@ -556,7 +594,11 @@ Open `http://localhost:3000` to:
556
594
  - **Same capture contract everywhere**: CLI, MCP `gno_capture`, REST `/api/capture`, SDK `client.capture()`, and Web UI Quick Capture return the same provenance receipt shape
557
595
  - **Ask**: AI-powered Q&A with citations
558
596
  - **Manage Collections**: Add, remove, and re-index collections
559
- - **Connect agents**: Install core Skill/MCP integrations from the app
597
+ - **Verify retrieval**: See each folder's lexical proof, exact failed stage,
598
+ and remediation without waiting for semantic models
599
+ - **Connect agents**: Install core Skill/MCP integrations; explicitly verify
600
+ configured MCP retrieval without changing client config. Skill installation
601
+ is visible, but client runtime execution cannot be proven automatically
560
602
  - **Manage files safely**: Rename, reveal, or move editable files to Trash with explicit index-vs-disk semantics
561
603
  - **Refactor files safely**: Move, duplicate, and organize editable notes with reference warnings
562
604
  - **Switch presets**: Change models live without restart
@@ -622,7 +664,10 @@ Interactive visualization of document connections. Wiki links, markdown links, a
622
664
 
623
665
  Ask questions in natural language. GNO searches your documents and synthesizes answers with inline citations linking to sources.
624
666
 
625
- Everything runs locally. No cloud, no accounts, no data leaving your machine.
667
+ The Web UI and local-model path run on your machine with no account or
668
+ telemetry. Network access occurs when GNO downloads models, when you configure
669
+ an HTTP model backend, or when you explicitly upload an exported artifact to
670
+ gno.sh.
626
671
 
627
672
  > **Detailed docs**: [Web UI Guide](https://gno.sh/docs/WEB-UI/)
628
673
 
@@ -697,32 +742,37 @@ curl -X POST http://localhost:3000/api/ask \
697
742
 
698
743
  # Index status
699
744
  curl http://localhost:3000/api/status
745
+
746
+ # Process liveness only
747
+ curl http://localhost:3000/api/health
700
748
  ```
701
749
 
702
- | Endpoint | Method | Description |
703
- | :---------------------------- | :----- | :-------------------------- |
704
- | `/api/query` | POST | Hybrid search (recommended) |
705
- | `/api/search` | POST | BM25 keyword search |
706
- | `/api/ask` | POST | AI-powered Q&A |
707
- | `/api/docs` | GET | List documents |
708
- | `/api/docs` | POST | Create document |
709
- | `/api/docs/:id` | PUT | Update document content |
710
- | `/api/docs/:id/move` | POST | Move editable document |
711
- | `/api/docs/:id/duplicate` | POST | Duplicate editable document |
712
- | `/api/docs/:id/refactor-plan` | POST | Preview file-op warnings |
713
- | `/api/docs/:id/deactivate` | POST | Remove from index |
714
- | `/api/doc` | GET | Get document content |
715
- | `/api/doc/:id/sections` | GET | Get document sections |
716
- | `/api/collections` | POST | Add collection |
717
- | `/api/collections/:name` | DELETE | Remove collection |
718
- | `/api/folders` | POST | Create folder |
719
- | `/api/sync` | POST | Trigger re-index |
720
- | `/api/status` | GET | Index statistics |
721
- | `/api/note-presets` | GET | List note presets |
722
- | `/api/presets` | GET | List model presets |
723
- | `/api/presets` | POST | Switch preset |
724
- | `/api/models/pull` | POST | Download models |
725
- | `/api/models/status` | GET | Download progress |
750
+ | Endpoint | Method | Description |
751
+ | :---------------------------- | :----- | :--------------------------- |
752
+ | `/api/query` | POST | Hybrid search (recommended) |
753
+ | `/api/search` | POST | BM25 keyword search |
754
+ | `/api/ask` | POST | AI-powered Q&A |
755
+ | `/api/docs` | GET | List documents |
756
+ | `/api/docs` | POST | Create document |
757
+ | `/api/docs/:id` | PUT | Update document content |
758
+ | `/api/docs/:id/move` | POST | Move editable document |
759
+ | `/api/docs/:id/duplicate` | POST | Duplicate editable document |
760
+ | `/api/docs/:id/refactor-plan` | POST | Preview file-op warnings |
761
+ | `/api/docs/:id/deactivate` | POST | Remove from index |
762
+ | `/api/doc` | GET | Get document content |
763
+ | `/api/doc/:id/sections` | GET | Get document sections |
764
+ | `/api/collections` | POST | Add collection |
765
+ | `/api/collections/:name` | DELETE | Remove collection |
766
+ | `/api/folders` | POST | Create folder |
767
+ | `/api/sync` | POST | Trigger re-index |
768
+ | `/api/status` | GET | Index and activation state |
769
+ | `/api/health` | GET | Process liveness only |
770
+ | `/api/connectors/verify` | POST | Explicit read-only MCP proof |
771
+ | `/api/note-presets` | GET | List note presets |
772
+ | `/api/presets` | GET | List model presets |
773
+ | `/api/presets` | POST | Switch preset |
774
+ | `/api/models/pull` | POST | Download models |
775
+ | `/api/models/status` | GET | Download progress |
726
776
 
727
777
  No authentication. No rate limits. Build custom tools, automate workflows, integrate with any language.
728
778
 
@@ -775,13 +825,13 @@ graph TD
775
825
  | **REST API** | HTTP API for custom tools and integrations |
776
826
  | **Multi-Format** | Markdown, PDF, DOCX, XLSX, PPTX, plain text |
777
827
  | **Local LLM** | AI answers via llama.cpp, no API keys |
778
- | **Remote Inference** | Offload to GPU servers via HTTP (llama-server, Ollama, LocalAI) |
779
- | **Privacy First** | 100% offline, zero telemetry, your data stays yours |
780
- | **MCP Server** | Works with Claude Desktop, Cursor, Zed, + 8 more |
828
+ | **Remote Inference** | Optional HTTP endpoints for embedding, reranking, expansion, and generation |
829
+ | **Privacy First** | Local by default; no telemetry; network use is explicit or model provisioning |
830
+ | **MCP Server** | 10 automatic client targets; 17 read-only tools, 28 with writes enabled |
781
831
  | **Collections** | Organize sources with patterns, excludes, contexts |
782
832
  | **Tag Filtering** | Frontmatter tags with hierarchical paths, filter via `--tags-any`/`--tags-all` |
783
833
  | **Note Linking** | Wiki links, backlinks, related notes, cross-collection navigation |
784
- | **Multilingual** | 30+ languages, auto-detection, cross-lingual search |
834
+ | **Multilingual** | Query classification, 7-language document detection, multilingual embeddings |
785
835
  | **Incremental** | SHA-256 tracking, only changed files re-indexed |
786
836
  | **Keyboard First** | ⌘N capture, ⌘K search, ⌘/ shortcuts, ⌘S save |
787
837
 
@@ -791,20 +841,20 @@ graph TD
791
841
 
792
842
  Models auto-download on first use to `~/.cache/gno/models/`. GNO validates cached GGUF files before loading and removes intercepted HTML/non-GGUF cache entries with a clear recovery error. For deterministic startup, set `GNO_NO_AUTO_DOWNLOAD=1` and use `gno models pull` explicitly. Alternatively, offload to a GPU server on your network using HTTP backends.
793
843
 
794
- | Model | Purpose | Size |
795
- | :--------------------- | :------------------------------------ | :----------- |
796
- | Qwen3-Embedding-0.6B | Embeddings (multilingual) | ~640MB |
797
- | Qwen3-Reranker-0.6B | Cross-encoder reranking (32K context) | ~700MB |
798
- | Qwen3 / Qwen2.5 family | Query expansion + AI answers | ~600MB-2.5GB |
844
+ | Model | Purpose |
845
+ | :--------------------- | :----------------------------------------------- |
846
+ | Qwen3-Embedding-0.6B | Embeddings |
847
+ | Qwen3-Reranker-0.6B | Best-chunk-per-document cross-encoder reranking |
848
+ | Qwen3 / Qwen2.5 family | Query expansion and standalone answer generation |
799
849
 
800
850
  ### Model Presets
801
851
 
802
- | Preset | Disk | Best For |
803
- | :----------- | :----- | :------------------------------------------------------ |
804
- | `slim-tuned` | ~1GB | Current default, tuned retrieval in a compact footprint |
805
- | `slim` | ~1GB | Fast, good quality |
806
- | `balanced` | ~2GB | Slightly larger model |
807
- | `quality` | ~2.5GB | Best answers |
852
+ | Preset | Best For |
853
+ | :----------- | :------------------------------------------- |
854
+ | `slim-tuned` | Current default; tuned query expansion |
855
+ | `slim` | Untuned slim query expansion |
856
+ | `balanced` | Qwen2.5 3B expansion and answers |
857
+ | `quality` | Qwen3 4B expansion and standalone AI answers |
808
858
 
809
859
  ```bash
810
860
  gno models use slim-tuned
@@ -822,7 +872,9 @@ GNO now has a published promoted retrieval model for the default slim path:
822
872
 
823
873
  Use it when you want the tuned retrieval expansion path immediately, without running local fine-tuning yourself.
824
874
 
825
- For private/internal products, use the same workflow but keep the final GGUF private and point `gen:` at a `file:` URI instead of publishing to Hugging Face.
875
+ For private/internal products, use the same workflow but keep the final GGUF
876
+ private and point `expand:` at a `file:` URI instead of publishing it to
877
+ Hugging Face. The `gen:` role remains the standalone answer model.
826
878
 
827
879
  See:
828
880
 
@@ -846,7 +898,10 @@ models:
846
898
  gen: "http://192.168.1.100:8083/v1/chat/completions#qwen3-4b"
847
899
  ```
848
900
 
849
- Works with llama-server, Ollama, LocalAI, vLLM, or any OpenAI-compatible server.
901
+ The HTTP adapter expects the OpenAI-compatible endpoint shapes documented in
902
+ [Configuration](./docs/CONFIGURATION.md). Remote servers receive the query,
903
+ chunk, or answer context sent to their configured model role; they are outside
904
+ GNO's local trust boundary.
850
905
 
851
906
  > **Configuration**: [Model Setup](https://gno.sh/docs/CONFIGURATION/)
852
907
 
@@ -962,16 +1017,28 @@ bun run bench:general-embeddings --candidate bge-m3-incumbent --write
962
1017
  bun run bench:general-embeddings --candidate qwen3-embedding-0.6b --write
963
1018
  ```
964
1019
 
965
- Current signal on the public multilingual FastAPI-docs fixture:
1020
+ <!-- public-truth:general-embedding-benchmark -->
1021
+
1022
+ The immutable April 2026 FastAPI-docs run used 15 documents in five corpus
1023
+ languages (`en`, `de`, `fr`, `es`, `zh`) and 13 queries:
966
1024
 
967
- - `bge-m3`: vector nDCG@10 `0.3508`, hybrid nDCG@10 `0.6756`
968
- - `Qwen3-Embedding-0.6B-GGUF`: vector nDCG@10 `0.9891`, hybrid nDCG@10 `0.9891`
1025
+ - [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`
1026
+ - [Qwen3 Embedding 0.6B](./evals/fixtures/general-embedding-benchmark/2026-04-06-qwen3-embedding-0-6b.md): vector nDCG@10 `0.8594`, hybrid nDCG@10 `0.947`
1027
+ <!-- /public-truth -->
969
1028
 
970
- Interpretation:
1029
+ A separate [July 2026 Nemotron screen](./research/embeddings/2026-07-21-nemotron-3-embed-1b.md)
1030
+ reran the same 13-query multilingual lane after runtime/profile changes. It
1031
+ measured Qwen at `0.9891` vector / `0.9891` hybrid nDCG@10 and Nemotron 3 Embed
1032
+ 1B at `0.9023` / `0.9461`. Nemotron used a temporary PyTorch HTTP adapter;
1033
+ Qwen used GNO's production GGUF path. Their timings are not comparable, and no
1034
+ official production GGUF was validated for Nemotron.
971
1035
 
972
- - Qwen is now the strongest general multilingual embedding model we have tested
973
- - built-in presets now use Qwen by default
974
- - existing users may need to run `gno embed` again after upgrading so current collections catch up
1036
+ These small fixture results support keeping Qwen as the built-in default; they
1037
+ do not establish general language superiority. Query-language classification
1038
+ supports a broader set than the indexed-document detector (`en`, `de`, `fr`,
1039
+ `it`, `zh`, `ja`, `ko`), and the committed fixture covers only five languages.
1040
+ The BM25-only multilingual eval remains a legacy sanity lane; dedicated lexical
1041
+ CJK benchmarking is pending.
975
1042
 
976
1043
  ---
977
1044
 
@@ -6,7 +6,9 @@ allowed-tools: Bash(gno:*) Read
6
6
 
7
7
  # GNO - Local Knowledge Engine
8
8
 
9
- Fast local semantic search. Index once, search instantly. No cloud, no API keys.
9
+ Fast local semantic search. Index once, search instantly. Local inference needs
10
+ no API key; configured HTTP backends and explicit gno.sh publishing are separate
11
+ network boundaries.
10
12
 
11
13
  ## When to Use This Skill
12
14
 
@@ -226,6 +228,11 @@ gno graph --from gno://notes/a.md --to gno://notes/b.md
226
228
  --no-pager Disable paging
227
229
  ```
228
230
 
231
+ Index names follow the CLI filesystem-identity contract: 1–64 UTF-16 code
232
+ units, letter/number first, no trailing space or `.`, no `..`, separators, or
233
+ platform-invalid punctuation. NFC/case-equivalent names share one identity.
234
+ See `docs/CLI.md` under Global Options for the complete byte limits.
235
+
229
236
  Non-default index search results may include `?index=<name>` on `gno://` URIs.
230
237
  Keep that query string when passing the URI to `gno get`, SDK `get()`, MCP
231
238
  `gno_get`, or an MCP resource read: it selects the named database. Batch reads
@@ -17,6 +17,11 @@ All commands accept:
17
17
  | `--no-pager` | Disable automatic paging |
18
18
  | `--offline` | Use cached models only |
19
19
 
20
+ Index names use 1–64 UTF-16 code units, start with a letter or number, and
21
+ reject trailing space/dot, `..`, separators, controls, and platform-invalid
22
+ punctuation. NFC/case-equivalent spellings share one identity. See
23
+ `docs/CLI.md` under Global Options for the complete canonical-byte contract.
24
+
20
25
  ## Initialization
21
26
 
22
27
  ### gno init
@@ -448,7 +453,8 @@ gno models list [--json|--md]
448
453
  gno models use <preset>
449
454
  ```
450
455
 
451
- Presets: `slim` (~1GB), `balanced` (~2GB), `quality` (~2.5GB)
456
+ Built-ins: `slim-tuned` (default), `slim`, `balanced`, `quality`. Actual
457
+ download/cache use depends on the selected artifacts and existing shared cache.
452
458
 
453
459
  ### gno models pull
454
460
 
@@ -523,12 +529,17 @@ Install GNO as MCP server in client configurations.
523
529
  gno mcp install [options]
524
530
  ```
525
531
 
526
- | Option | Default | Description |
527
- | -------------- | -------------- | ------------------------------------------------ |
528
- | `-t, --target` | claude-desktop | Target: `claude-desktop`, `claude-code`, `codex` |
529
- | `-s, --scope` | user | Scope: `user`, `project` |
530
- | `-f, --force` | false | Overwrite existing config |
531
- | `--dry-run` | false | Preview changes |
532
+ | Option | Default | Description |
533
+ | -------------- | -------------- | ------------------------- |
534
+ | `-t, --target` | claude-desktop | Target client (see below) |
535
+ | `-s, --scope` | target default | Scope: `user`, `project` |
536
+ | `-f, --force` | false | Overwrite existing config |
537
+ | `--dry-run` | false | Preview changes |
538
+
539
+ Targets: `claude-desktop`, `claude-code`, `codex`, `cursor`, `zed`,
540
+ `windsurf`, `opencode`, `amp`, `lmstudio`, and `librechat`. Project scope is
541
+ supported by Claude Code, Codex, Cursor, OpenCode, and LibreChat.
542
+ LibreChat is project-only; all other targets default to user scope.
532
543
 
533
544
  Examples:
534
545
 
@@ -21,14 +21,27 @@ gno mcp install --enable-write
21
21
 
22
22
  ### Claude Desktop
23
23
 
24
- Add to `claude_desktop_config.json`:
24
+ Run `gno mcp install --dry-run --json`, then add the reported absolute values to
25
+ `claude_desktop_config.json`:
25
26
 
26
27
  ```json
27
28
  {
28
29
  "mcpServers": {
29
30
  "gno": {
30
- "command": "gno",
31
- "args": ["mcp"]
31
+ "command": "/absolute/path/to/bun",
32
+ "args": [
33
+ "run",
34
+ "/absolute/path/to/@gmickel/gno/src/index.ts",
35
+ "--index",
36
+ "default",
37
+ "--config",
38
+ "/absolute/path/to/index.yml",
39
+ "mcp"
40
+ ],
41
+ "env": {
42
+ "GNO_DATA_DIR": "/absolute/path/to/data",
43
+ "GNO_CACHE_DIR": "/absolute/path/to/cache"
44
+ }
32
45
  }
33
46
  }
34
47
  }
@@ -47,6 +60,12 @@ gno mcp install -t claude-code -s user # User scope
47
60
  gno mcp install -t claude-code -s project # Project scope
48
61
  ```
49
62
 
63
+ Installed entries deliberately pin the current Bun/package entrypoint, active
64
+ index, absolute config, data directory, and model cache. Standard clients use
65
+ `env`; OpenCode uses `environment`; Codex uses `~/.codex/config.toml` or project
66
+ `.codex/config.toml` with `[mcp_servers.gno]` and `[mcp_servers.gno.env]`.
67
+ Do not shorten a generated entry to `gno mcp`.
68
+
50
69
  ## Check Status
51
70
 
52
71
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gmickel/gno",
3
- "version": "1.12.4",
3
+ "version": "1.14.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",
@@ -118,6 +118,7 @@
118
118
  "research:finetune:mlx:fuse": "bun research/finetune/scripts/fuse-mlx.ts",
119
119
  "research:finetune:mlx:smoke": "bun research/finetune/scripts/smoke-mlx.ts",
120
120
  "reset": "bun run src/index.ts reset --confirm",
121
+ "docs:truth": "bun run scripts/public-truth.ts",
121
122
  "docs:verify": "bun run scripts/docs-verify.ts",
122
123
  "website:install": "cd website && bundle install",
123
124
  "website:dev": "cd website && make serve",
@@ -160,6 +161,7 @@
160
161
  "commander": "14.0.3",
161
162
  "embla-carousel-react": "8.6.0",
162
163
  "franc": "6.2.0",
164
+ "jsonc-parser": "3.3.1",
163
165
  "lucide-react": "1.8.0",
164
166
  "markitdown-ts": "0.0.9",
165
167
  "minimatch": "10.2.3",
@@ -10,6 +10,11 @@ import { basename, join } from "node:path";
10
10
 
11
11
  // Bun supports JSON imports natively - version single source of truth
12
12
  import pkg from "../../package.json";
13
+ import {
14
+ assertValidIndexName,
15
+ indexNamesMatch,
16
+ resolveIndexDbFilename,
17
+ } from "./index-name";
13
18
 
14
19
  // ─────────────────────────────────────────────────────────────────────────────
15
20
  // Brand / Product Identity
@@ -218,7 +223,26 @@ export function getIndexDbPath(
218
223
  indexName: string = DEFAULT_INDEX_NAME,
219
224
  dirs: ResolvedDirs = resolveDirs()
220
225
  ): string {
221
- return join(dirs.data, `index-${indexName}.sqlite`);
226
+ assertValidIndexName(indexName);
227
+ let existingFilenames: string[] = [];
228
+ try {
229
+ existingFilenames = [
230
+ ...new Bun.Glob("index-*.sqlite").scanSync({
231
+ cwd: dirs.data,
232
+ onlyFiles: false,
233
+ }),
234
+ ];
235
+ } catch (error) {
236
+ if (
237
+ !error ||
238
+ typeof error !== "object" ||
239
+ !("code" in error) ||
240
+ error.code !== "ENOENT"
241
+ ) {
242
+ throw error;
243
+ }
244
+ }
245
+ return join(dirs.data, resolveIndexDbFilename(indexName, existingFilenames));
222
246
  }
223
247
 
224
248
  /**
@@ -265,8 +289,12 @@ export function buildUri(
265
289
  .map((segment) => encodeURIComponent(segment))
266
290
  .join("/");
267
291
  const uri = `${URI_PREFIX}${collection}/${encodedPath}`;
268
- const indexName = options.indexName?.trim();
269
- if (!indexName || indexName === DEFAULT_INDEX_NAME) {
292
+ const indexName = options.indexName;
293
+ if (indexName === undefined) {
294
+ return uri;
295
+ }
296
+ assertValidIndexName(indexName);
297
+ if (indexNamesMatch(indexName, DEFAULT_INDEX_NAME)) {
270
298
  return uri;
271
299
  }
272
300
  return `${uri}?index=${encodeURIComponent(indexName)}`;
@@ -287,8 +315,8 @@ export function parseUri(uri: string): ParsedGnoUri | null {
287
315
  if (slashIndex === -1) {
288
316
  // gno://collection (no path)
289
317
  const [collectionWithQuery, query = ""] = rest.split("?", 2);
290
- const indexName = new URLSearchParams(query).get("index")?.trim();
291
- return indexName
318
+ const indexName = new URLSearchParams(query).get("index");
319
+ return indexName !== null
292
320
  ? {
293
321
  collection: collectionWithQuery ?? rest,
294
322
  path: "",
@@ -307,8 +335,10 @@ export function parseUri(uri: string): ParsedGnoUri | null {
307
335
  // decodeURIComponent throws on malformed percent-encoding
308
336
  try {
309
337
  const path = decodeURIComponent(encodedPath);
310
- const indexName = new URLSearchParams(query).get("index")?.trim();
311
- return indexName ? { collection, path, indexName } : { collection, path };
338
+ const indexName = new URLSearchParams(query).get("index");
339
+ return indexName !== null
340
+ ? { collection, path, indexName }
341
+ : { collection, path };
312
342
  } catch {
313
343
  return null;
314
344
  }
@@ -319,12 +349,15 @@ export function parseUri(uri: string): ParsedGnoUri | null {
319
349
  */
320
350
  export function decorateUriForIndex(uri: string, indexName?: string): string {
321
351
  const parsed = parseUri(uri);
322
- const normalizedIndex = indexName?.trim();
323
- if (!parsed || !normalizedIndex || normalizedIndex === DEFAULT_INDEX_NAME) {
352
+ if (!parsed || indexName === undefined) {
353
+ return stripUriIndex(uri);
354
+ }
355
+ assertValidIndexName(indexName);
356
+ if (indexNamesMatch(indexName, DEFAULT_INDEX_NAME)) {
324
357
  return stripUriIndex(uri);
325
358
  }
326
359
  return buildUri(parsed.collection, parsed.path, {
327
- indexName: normalizedIndex,
360
+ indexName,
328
361
  });
329
362
  }
330
363