ragx-cli 0.3.3__tar.gz → 0.5.0__tar.gz

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 (100) hide show
  1. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/CHANGELOG.md +46 -0
  2. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/CLAUDE.md +16 -4
  3. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/PKG-INFO +80 -12
  4. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/README.md +79 -11
  5. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/pyproject.toml +1 -1
  6. ragx_cli-0.5.0/research/lm-studio-model-download-api-and-curated-embedding-reranker-catalog-for-ragx-models-command.md +119 -0
  7. ragx_cli-0.5.0/skills/ragx-cli/SKILL.md +90 -0
  8. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/cli/app.py +19 -2
  9. ragx_cli-0.5.0/src/ragx/cli/models_cmd.py +230 -0
  10. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/cli/pipeline.py +10 -3
  11. ragx_cli-0.5.0/src/ragx/core/catalog.py +138 -0
  12. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/config.py +11 -2
  13. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/indexer.py +57 -23
  14. ragx_cli-0.5.0/src/ragx/core/lmstudio.py +106 -0
  15. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/query.py +1 -1
  16. ragx_cli-0.5.0/src/ragx/providers/llama_embedder.py +53 -0
  17. ragx_cli-0.5.0/src/ragx/providers/llama_process.py +108 -0
  18. ragx_cli-0.5.0/src/ragx/providers/llama_server.py +45 -0
  19. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/providers/registry.py +28 -0
  20. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/test_cli.py +26 -2
  21. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/test_integration.py +54 -8
  22. ragx_cli-0.5.0/tests/test_llama_server.py +135 -0
  23. ragx_cli-0.5.0/tests/test_models.py +312 -0
  24. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/SKILL.md +0 -0
  25. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/api-cheatsheet.md +0 -0
  26. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/collection-management/python.md +0 -0
  27. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/collection-management/typescript.md +0 -0
  28. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/configuration.md +0 -0
  29. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/data-model.md +0 -0
  30. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/data-operations/python.md +0 -0
  31. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/data-operations/typescript.md +0 -0
  32. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/embedding.md +0 -0
  33. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/hybrid-search/python.md +0 -0
  34. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/hybrid-search/typescript.md +0 -0
  35. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/multimodal-search/python.md +0 -0
  36. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/multimodal-search/typescript.md +0 -0
  37. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/quick-start/python.md +0 -0
  38. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/quick-start/typescript.md +0 -0
  39. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/rag-system/python.md +0 -0
  40. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/rag-system/typescript.md +0 -0
  41. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/reranker.md +0 -0
  42. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/troubleshooting.md +0 -0
  43. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/vector-search/python.md +0 -0
  44. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.agents/skills/zvec/vector-search/typescript.md +0 -0
  45. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.github/workflows/publish.yml +0 -0
  46. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/.gitignore +0 -0
  47. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/AGENTS.md +0 -0
  48. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/CONTRACTS-PHASE23.md +0 -0
  49. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/CONTRACTS.md +0 -0
  50. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/LICENSE +0 -0
  51. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/docs/feature-temporal-weighting.md +0 -0
  52. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/ragx-cli-plan.md +0 -0
  53. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/research/bge-m3-colbert-multi-vector-late-interaction-for-ragx-rerank-alternative-and-token-level-graph-edges.md +0 -0
  54. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/research/bge-m3-dense-embeddings-as-ragx-provider-multilingual-quality-and-threshold-calibration.md +0 -0
  55. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/research/bge-m3-dense-q8-vs-nomic-q4-benchmark-2026-07-12-worktree-eval-results.md +0 -0
  56. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/research/bge-m3-sparse-lexical-weights-hybrid-retrieval-leg-for-ragx-vs-sqlite-fts5-bm25.md +0 -0
  57. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/research/bge-m3-subchunk-edge-ablation-2026-07-13-ties-again-and-beta-zero-shortlist-mechanism.md +0 -0
  58. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/research/fine-grained-sub-chunk-edges-with-coarse-chunk-nodes-multi-granularity-graph-rag-literature-validation.md +0 -0
  59. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/research/subchunk-edge-ablation-2026-07-12-two-round-experiment-protocol-results-and-verdict.md +0 -0
  60. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/skills-lock.json +0 -0
  61. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/__init__.py +0 -0
  62. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/cli/__init__.py +0 -0
  63. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/cli/detect.py +0 -0
  64. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/cli/eval_cmd.py +0 -0
  65. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/cli/init_prompt.py +0 -0
  66. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/cli/inspect_cmd.py +0 -0
  67. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/cli/output.py +0 -0
  68. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/__init__.py +0 -0
  69. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/chunking.py +0 -0
  70. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/communities.py +0 -0
  71. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/discovery.py +0 -0
  72. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/errors.py +0 -0
  73. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/eval.py +0 -0
  74. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/expansion.py +0 -0
  75. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/fusion.py +0 -0
  76. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/graph.py +0 -0
  77. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/models.py +0 -0
  78. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/scoring.py +0 -0
  79. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/store.py +0 -0
  80. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/traversal.py +0 -0
  81. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/core/vectors.py +0 -0
  82. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/providers/__init__.py +0 -0
  83. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/providers/base.py +0 -0
  84. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/providers/openai_compat.py +0 -0
  85. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/src/ragx/providers/st_reranker.py +0 -0
  86. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/__init__.py +0 -0
  87. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/conftest.py +0 -0
  88. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/test_chunking.py +0 -0
  89. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/test_communities.py +0 -0
  90. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/test_config_rc.py +0 -0
  91. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/test_discovery.py +0 -0
  92. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/test_eval.py +0 -0
  93. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/test_expansion.py +0 -0
  94. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/test_fusion.py +0 -0
  95. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/test_graph.py +0 -0
  96. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/test_inspect.py +0 -0
  97. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/test_providers.py +0 -0
  98. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/test_store.py +0 -0
  99. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/test_traversal.py +0 -0
  100. {ragx_cli-0.3.3 → ragx_cli-0.5.0}/tests/test_vectors.py +0 -0
@@ -4,6 +4,52 @@ All notable changes to `ragx-cli` are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
5
5
  [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [0.5.0] — 2026-07-15
8
+
9
+ ### Added
10
+
11
+ - **`ragx-cli models`**: recommends an embedding + reranker combo (quality tier,
12
+ RAM/macOS detection), downloads models through LM Studio (`lms get --yes`), and writes
13
+ the config to `ragx.toml` (with an `index --full` warning when the embedding model
14
+ changed). Scriptable: `--quality fast|balanced|best|jina-nano`, `--embed-engine`,
15
+ `--rerank-engine`, `--yes`, `--dry-run`, `--json` (schema `ragx.models.v1`).
16
+ Interactive `init` offers the flow as its final step. Embedding catalog:
17
+ EmbeddingGemma-300M / BGE-M3 / Qwen3-Embedding-0.6B / Jina-v5-nano (CC-BY-NC,
18
+ llama-server engine only); reranker: bge-reranker-v2-m3 (multilingual).
19
+ - **`llama-server` rerank engine** (`rerank.provider = "llama-server"`): reranking via
20
+ llama.cpp's `/v1/rerank` on a GGUF (`rerank.gguf`), auto-spawning `llama-server`
21
+ (`rerank.server_bin`, `rerank.base_url`) when nothing is listening and terminating it
22
+ at exit. Reranker GGUFs download through LM Studio (`ragx-cli models --rerank-engine
23
+ llama-server`), so reranking needs **no direct huggingface.co access** and no torch/
24
+ sentence-transformers install. Q8_0 GGUFs validated against the safetensors originals
25
+ (scores within ~0.5 logit, identical ordering).
26
+ - **`llama-server` embedding engine** (`embeddings.provider = "llama-server"`): embeddings
27
+ served by an auto-spawned `llama-server --embedding` on `embeddings.gguf` (same managed
28
+ lifecycle as the rerank engine; default port 9813). `ragx-cli models --embed-engine
29
+ llama-server` wires it up. With both engines on llama-server, LM Studio is purely a
30
+ model downloader — nothing but ragx-managed processes run at query time. Also unblocks
31
+ EuroBERT models (e.g. `jina-embeddings-v5-text-nano-retrieval-GGUF`) that LM Studio
32
+ downloads but cannot serve.
33
+
34
+ ## [0.4.0] — 2026-07-15
35
+
36
+ ### Changed (BREAKING)
37
+
38
+ - **`ragx-cli index` is now incremental by default** (previously a full rebuild).
39
+ It hash-diffs the corpus and re-processes only new/modified/deleted files. The old
40
+ behavior moved to `ragx-cli index --full`; `--changed` remains as a deprecated,
41
+ hidden alias for the (now default) incremental mode.
42
+ - **Chunking params joined the index manifest**: changing `chunking.size_tokens` or
43
+ `chunking.overlap` now fails loud on an incremental run (previously it silently left
44
+ old files chunked under the old params). Fix is `ragx-cli index --full`.
45
+
46
+ ### Added
47
+
48
+ - **`ragx-cli status` reports corpus drift**: a `drift` object
49
+ (`{"new": N, "changed": N, "deleted": N}`, same in text output) diffing the corpus
50
+ on disk against the stored file hashes, so agents and humans can see when a
51
+ re-index is due without running one.
52
+
7
53
  ## [0.3.3] — 2026-07-15
8
54
 
9
55
  ### Added
@@ -22,6 +22,9 @@ API contracts for every core module. Deferred feature specs live in `docs/`.
22
22
  hashing), pathspec (gitignore globs).
23
23
  - Providers speak **OpenAI-compatible HTTP**. Local default: LM Studio at
24
24
  `http://localhost:1234/v1`. `provider="ollama"` auto-switches to `:11434/v1`.
25
+ `embeddings.provider="llama-server"` instead auto-spawns `llama-server --embedding` on
26
+ `embeddings.gguf` (port 9813; shared lifecycle code in `providers/llama_process.py`) —
27
+ with the llama-server rerank engine, LM Studio is downloader-only at query time.
25
28
  Env fallbacks: `OPENAI_BASE_URL` (only while base_url is still the default) and
26
29
  `OPENAI_API_KEY` (only when `api_key_env` is unset); explicit config always wins.
27
30
  - Machine-level provider settings live in `~/.ragxrc` (TOML; ONLY the embeddings/
@@ -29,8 +32,11 @@ API contracts for every core module. Deferred feature specs live in `docs/`.
29
32
  ragx.toml < ~/.ragxrc — the rc OVERRIDES corpus values and logs a stderr warning
30
33
  per overridden key. Write via `ragx-cli config set --global <key> <value>`.
31
34
  `Config.save` never bakes rc values into the corpus file.
32
- - Reranker is always local: sentence-transformers CrossEncoder `BAAI/bge-reranker-v2-m3`
33
- (optional extra `ragx-cli[rerank]`). LM Studio has NO /v1/rerank endpoint — verified; don't try.
35
+ - Reranker is always local, two engines: sentence-transformers CrossEncoder (default,
36
+ `BAAI/bge-reranker-v2-m3`, optional extra `ragx-cli[rerank]`) or `rerank.provider=
37
+ "llama-server"` (llama.cpp `/v1/rerank` on a GGUF, auto-spawned from `rerank.gguf`;
38
+ GGUFs download via LM Studio — validated ≈ safetensors scores). LM Studio itself has
39
+ NO /v1/rerank endpoint — verified; don't try.
34
40
 
35
41
  ## Layout (core/CLI split is the one architectural rule — MCP server later rides on it)
36
42
 
@@ -57,10 +63,16 @@ src/ragx/
57
63
  indexer.py # run_index: discover->hash->chunk->embed->HNSW+store->kNN edges
58
64
  query.py # run_query: expansion->fan-out->RRF->traversal->rerank->combine; JSON serializers
59
65
  eval.py # recall@5/@10 + MRR over file-level ranking, injected query_fn
66
+ catalog.py # curated embedding/reranker catalog (tiers, prefixes) + spec detect
67
+ lmstudio.py # `lms` CLI wrapper: find/download (`lms get --yes`)/`lms ls --json`;
68
+ # LM Studio can't download plain safetensors — rerankers stay on HF
60
69
  providers/ # base.py protocols (Embedder/Generator/Reranker); openai_compat.py;
61
- # st_reranker.py; registry.py factories (env-var + api_key_env resolution)
70
+ # st_reranker.py; llama_process.py (managed llama-server lifecycle) +
71
+ # llama_server.py (rerank) + llama_embedder.py (embeddings);
72
+ # registry.py factories (env-var + api_key_env resolution)
62
73
  cli/ # thin shells only: app.py (init/status/config + registration),
63
- # pipeline.py (index/query), inspect_cmd.py, eval_cmd.py, output.py
74
+ # pipeline.py (index/query), inspect_cmd.py, eval_cmd.py, models_cmd.py
75
+ # (recommend/download/configure models), output.py
64
76
  tests/ # 177 tests; mocked HTTP (respx), FakeEmbedder integration tests, no live network
65
77
  ```
66
78
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ragx-cli
3
- Version: 0.3.3
3
+ Version: 0.5.0
4
4
  Summary: Similarity-graph RAG CLI: index a corpus into a chunk-level embedding graph and query it
5
5
  Project-URL: Repository, https://github.com/alber70g/ragx-cli
6
6
  Project-URL: Issues, https://github.com/alber70g/ragx-cli/issues
@@ -49,9 +49,10 @@ that can justify every result via the exact graph path that produced it.
49
49
  ```bash
50
50
  uv tool install ragx-cli --with ragx-cli[rerank] # install and use `ragx-cli`
51
51
  ragx-cli init # create ragx.toml next to your corpus (interactive on a TTY; --yes for defaults)
52
- ragx-cli index # chunk -> embed -> HNSW + kNN similarity graph
52
+ ragx-cli index # chunk -> embed -> HNSW + kNN similarity graph (incremental after the first run)
53
53
  ragx-cli query "why did we switch build tools?" --json --files-only
54
- ragx-cli index --changed # incremental: only new/modified/deleted files
54
+ ragx-cli index --full # full rebuild: re-chunk + re-embed everything
55
+ ragx-cli models # recommend + download an embedding/reranker combo via LM Studio
55
56
  ```
56
57
 
57
58
  Runs against any OpenAI-compatible embedding endpoint (LM Studio, Ollama, OpenAI). Reranking
@@ -93,7 +94,7 @@ mixing several concepts gets one sharp edge per concept instead of a diluted ave
93
94
  between near-duplicate chunks (whole-chunk cosine ≥ `near_dup_sim`) are dropped — those are the
94
95
  measured precision-killers. Costs roughly 5–10× more embedding calls at index time; retrieval
95
96
  units, traversal, and query flow are unchanged. Switching `edge_source` (or the sub-chunk size)
96
- requires a full re-index; `--changed` fails loud on the mismatch. Literature grounding:
97
+ requires `index --full`; incremental runs fail loud on the mismatch. Literature grounding:
97
98
  `research/fine-grained-sub-chunk-edges-with-coarse-chunk-nodes-multi-granularity-graph-rag-literature-validation.md`.
98
99
  In this mode `k` counts links per *sub-chunk* with no per-chunk cap, so the graph is denser and
99
100
  shallower traversal suffices. Measured on the tuned eval corpus (2026-07): at `hops=2` it ties
@@ -116,8 +117,13 @@ flowchart TD
116
117
  G --> F
117
118
  ```
118
119
 
119
- Incremental runs (`--changed`) re-embed only changed files and repair only the edge lists that
120
- those chunks touch. Content hashes make `touch`-ed but unchanged files free.
120
+ `ragx-cli index` is **incremental by default** (0.4.0; `--changed` is a deprecated alias): it
121
+ re-embeds only new/modified files, drops deleted ones, and repairs only the edge lists those
122
+ chunks touch. Content hashes make `touch`-ed but unchanged files free, and include/exclude glob
123
+ changes converge to the same file set a rebuild would produce. `--full` rebuilds from scratch;
124
+ changing `embeddings.model`, `chunking.*`, or `graph.edge_source` requires it — incremental runs
125
+ fail loud on the manifest mismatch. `ragx-cli status` reports **drift** (files new/changed/deleted
126
+ since the last index) so you can see when a re-index is due without running one.
121
127
 
122
128
  ### Querying
123
129
 
@@ -314,6 +320,53 @@ Full write-ups: `research/bge-m3-dense-q8-vs-nomic-q4-benchmark-2026-07-12-workt
314
320
 
315
321
  ---
316
322
 
323
+ ## Picking models: `ragx-cli models`
324
+
325
+ `ragx-cli models` recommends an embedding + reranker combo, downloads the embedding model
326
+ **through LM Studio** (`lms get` — one download path, plays well with restricted networks),
327
+ pre-fetches the reranker from Hugging Face, and writes both to `ragx.toml`. Interactive on a
328
+ TTY (quality tier + engine questions, RAM auto-detected); scriptable via flags:
329
+
330
+ ```bash
331
+ ragx-cli models # interactive
332
+ ragx-cli models --quality balanced --yes --json # agents
333
+ ragx-cli models --quality fast --dry-run # recommend only, change nothing
334
+ ```
335
+
336
+ The curated catalog (every entry verified working end-to-end):
337
+
338
+ | tier | embedding model | notes |
339
+ |---|---|---|
340
+ | `fast` | EmbeddingGemma 300M | 308M, 100+ languages, 2048-token context |
341
+ | `balanced` | BGE-M3 | ragx's benchmarked production model (~100 languages) |
342
+ | `best` | Qwen3-Embedding-0.6B | 100+ languages, 32K context |
343
+ | `jina-nano` | Jina embeddings v5 nano | 239M, best-in-class sub-500M; **CC-BY-NC (non-commercial)**; llama-server engine only — LM Studio downloads it but can't serve EuroBERT |
344
+
345
+ **Serving engines.** Embeddings run through `--embed-engine`: **`llama-server`** (default when
346
+ llama.cpp is installed — ragx auto-spawns `llama-server --embedding` on the downloaded GGUF and
347
+ terminates it at exit; LM Studio is only the downloader) or **`lm-studio`** (LM Studio serves
348
+ `/v1/embeddings`; zero extra processes, LM Studio must be running). The reranker —
349
+ `BAAI/bge-reranker-v2-m3` (multilingual) — runs through `--rerank-engine`:
350
+
351
+ - **`llama-server`** (default when llama.cpp is installed): the reranker's Q8_0 GGUF is also
352
+ downloaded via LM Studio, and ragx auto-spawns/terminates a `llama-server --rerank` process
353
+ at query time (`rerank.provider="llama-server"`, `rerank.gguf`, `rerank.base_url`,
354
+ `rerank.server_bin`). **No huggingface.co access needed anywhere.** GGUF scores are validated
355
+ within ~0.5 logit of the safetensors originals.
356
+ - **`sentence-transformers`**: the classic CrossEncoder path; model pre-fetched from Hugging
357
+ Face (needs the `ragx-cli[rerank]` extra).
358
+
359
+ With both engines on `llama-server` the whole stack is ragx-managed: LM Studio downloads the
360
+ GGUFs, ragx spawns and reaps the servers, and neither LM Studio nor huggingface.co is needed
361
+ at query time. Under 8 GB RAM the embedding tier drops to `fast`; on macOS
362
+ `lms get --yes` picks MLX variants where LM Studio's catalog offers them. Switching the
363
+ embedding model invalidates the index — the command tells you to run `ragx-cli index --full`.
364
+ `init` offers this flow as its final step; rerun `ragx-cli models` anytime to switch.
365
+
366
+ Why not `jina-embeddings-v5-text-nano`? Excellent model, but its EuroBERT architecture needs
367
+ Jina's llama.cpp fork — stock LM Studio can't load it (and the license is CC-BY-NC). See
368
+ `research/lm-studio-model-download-api-and-curated-embedding-reranker-catalog-for-ragx-models-command.md`.
369
+
317
370
  ## Agent-first conventions
318
371
 
319
372
  - `--json` emits exactly one JSON document on stdout (versioned schemas: `ragx.query.v1`,
@@ -322,6 +375,8 @@ Full write-ups: `research/bge-m3-dense-q8-vs-nomic-q4-benchmark-2026-07-12-workt
322
375
  - Every chunk carries `file`, `line_start/line_end`, `byte_start/byte_end` — agents jump to the
323
376
  exact source location and read the full text themselves (JSON chunk text is truncated).
324
377
  - `--files-only` aggregates chunk scores per file (sum of top-3) — the mode coding agents use most.
378
+ - `ragx-cli status` includes a `drift` object (`new`/`changed`/`deleted` file counts vs the index) —
379
+ agents check it to decide whether to run `ragx-cli index` before querying.
325
380
  - `ragx-cli query -` reads the query from stdin; `ragx-cli inspect chunk|file|neighbors|communities|community`
326
381
  debugs the graph.
327
382
 
@@ -341,7 +396,8 @@ questions; fall back to grep for exact identifiers.
341
396
  `file` + `line_start/line_end`; the JSON `text` is truncated, so read the file yourself
342
397
  for full context.
343
398
  - Fast mode (no LLM call, no cross-encoder): add `--no-expand --no-rerank`.
344
- - After adding or editing files: `ragx-cli index --changed` (cheap, hash-based).
399
+ - After adding or editing files: `ragx-cli index` (incremental and cheap — hash-based).
400
+ `ragx-cli status --json` shows `drift` counts if you want to check staleness first.
345
401
  - stdout is exactly one JSON document; logs are on stderr.
346
402
  Exit codes: 0 = results, 1 = no results (not an error), 2 = error.
347
403
  - Why did this result appear? `ragx-cli query "..." --explain`.
@@ -401,9 +457,19 @@ detects the mismatch and asks you to run a full `ragx-cli index`.
401
457
 
402
458
  ### Reranker on restricted networks (no huggingface.co)
403
459
 
404
- The reranker model (`BAAI/bge-reranker-v2-m3`, ~2.3 GB) is downloaded from huggingface.co on
405
- first use. If your network blocks huggingface.co, ragx-cli degrades gracefully — queries run
406
- without reranking and a warning explains why — but you have three ways to get reranking working:
460
+ With the default `sentence-transformers` engine, the reranker model
461
+ (`BAAI/bge-reranker-v2-m3`, ~2.3 GB) is downloaded from huggingface.co on first use. If your
462
+ network blocks huggingface.co, ragx-cli degrades gracefully — queries run without reranking
463
+ and a warning explains why — and the easiest fix is to skip huggingface.co entirely:
464
+
465
+ **Option 0 — the `llama-server` engine (recommended).** `ragx-cli models --rerank-engine
466
+ llama-server` downloads a validated Q8_0 GGUF of the reranker **through LM Studio** (same
467
+ download path as the embedding model) and reranks via llama.cpp's `llama-server --rerank`,
468
+ which ragx starts and stops automatically. Requires a recent llama.cpp
469
+ (`brew install llama.cpp`); no torch, no sentence-transformers, no huggingface.co. The GGUFs
470
+ score within ~0.5 logit of the safetensors originals with identical ordering.
471
+
472
+ Prefer the sentence-transformers engine? Three more ways:
407
473
 
408
474
  **Option A — copy the model and point `rerank.model` at the directory** (recommended).
409
475
  On any machine with access:
@@ -499,7 +565,7 @@ Checked features are built and validated per [the implementation plan](ragx-cli-
499
565
  unchecked ones are next up. Release history: [CHANGELOG.md](CHANGELOG.md).
500
566
 
501
567
  - [x] **CLI & storage**: typer CLI, SQLite schema, provider abstraction (Embedder/Generator/Reranker)
502
- - [x] **Baseline vector RAG**: discovery, chunking, embeddings, HNSW search, incremental `--changed`
568
+ - [x] **Baseline vector RAG**: discovery, chunking, embeddings, HNSW search, incremental indexing
503
569
  - [x] **Similarity graph**: kNN edge construction, heat-propagation traversal, `inspect`, `--explain`
504
570
  - [x] **Quality & measurement**: multi-query/HyDE expansion, RRF fusion, cross-encoder rerank, `eval` harness
505
571
  - [x] **Communities**: Leiden detection over the edge list (index-time, read-only via status/inspect)
@@ -507,11 +573,13 @@ unchecked ones are next up. Release history: [CHANGELOG.md](CHANGELOG.md).
507
573
  - [x] **Committable config**: `ragx.toml` at the corpus root (0.3.0; was `.ragx/config.toml`), index data stays gitignored in `.ragx/`
508
574
  - [x] **Offline-friendly rerank**: graceful degradation + pre-seeding docs when huggingface.co is unreachable
509
575
  - [x] **Sub-chunk edges** (opt-in `graph.edge_source="subchunk"`): edge weight = max cosine over sentence-aligned sub-chunk pairs, for corpora with long multi-concept chunks
576
+ - [x] **Incremental by default** (0.4.0): `index` hash-diffs, `--full` rebuilds, `status` reports corpus drift, chunking params are manifest-guarded
577
+ - [x] **`ragx-cli models`**: curated embedding/reranker recommendation (quality tier + RAM detection), downloads via LM Studio's `lms get`, serving via llama-server or LM Studio
510
578
  - [ ] **Community labels**: name the Leiden communities so they're browsable without reading member chunks
511
579
  - [ ] **query --global** for corpus-level questions (answer from community summaries, not individual chunks)
512
580
  - [ ] **MCP server**: a second thin shell over `ragx.core` (the core/CLI split it needs is already enforced)
513
581
  - [ ] **[Temporal weighting](docs/feature-temporal-weighting.md)**: opt-in `--since`/`--until`/`--temporal recent|oldest`, date cascade filename/frontmatter → git → mtime
514
582
  - [x] **Release**: publish to PyPI as `ragx-cli` (plain `ragx` is name-blocked, too similar to an existing project) so `uvx ragx-cli` works out of the box
515
583
 
516
- Development: `uv sync --group dev && uv run pytest`. 177 tests; module contracts live in
584
+ Development: `uv sync --group dev && uv run pytest`. 183 tests; module contracts live in
517
585
  `CONTRACTS.md` / `CONTRACTS-PHASE23.md`.
@@ -21,9 +21,10 @@ that can justify every result via the exact graph path that produced it.
21
21
  ```bash
22
22
  uv tool install ragx-cli --with ragx-cli[rerank] # install and use `ragx-cli`
23
23
  ragx-cli init # create ragx.toml next to your corpus (interactive on a TTY; --yes for defaults)
24
- ragx-cli index # chunk -> embed -> HNSW + kNN similarity graph
24
+ ragx-cli index # chunk -> embed -> HNSW + kNN similarity graph (incremental after the first run)
25
25
  ragx-cli query "why did we switch build tools?" --json --files-only
26
- ragx-cli index --changed # incremental: only new/modified/deleted files
26
+ ragx-cli index --full # full rebuild: re-chunk + re-embed everything
27
+ ragx-cli models # recommend + download an embedding/reranker combo via LM Studio
27
28
  ```
28
29
 
29
30
  Runs against any OpenAI-compatible embedding endpoint (LM Studio, Ollama, OpenAI). Reranking
@@ -65,7 +66,7 @@ mixing several concepts gets one sharp edge per concept instead of a diluted ave
65
66
  between near-duplicate chunks (whole-chunk cosine ≥ `near_dup_sim`) are dropped — those are the
66
67
  measured precision-killers. Costs roughly 5–10× more embedding calls at index time; retrieval
67
68
  units, traversal, and query flow are unchanged. Switching `edge_source` (or the sub-chunk size)
68
- requires a full re-index; `--changed` fails loud on the mismatch. Literature grounding:
69
+ requires `index --full`; incremental runs fail loud on the mismatch. Literature grounding:
69
70
  `research/fine-grained-sub-chunk-edges-with-coarse-chunk-nodes-multi-granularity-graph-rag-literature-validation.md`.
70
71
  In this mode `k` counts links per *sub-chunk* with no per-chunk cap, so the graph is denser and
71
72
  shallower traversal suffices. Measured on the tuned eval corpus (2026-07): at `hops=2` it ties
@@ -88,8 +89,13 @@ flowchart TD
88
89
  G --> F
89
90
  ```
90
91
 
91
- Incremental runs (`--changed`) re-embed only changed files and repair only the edge lists that
92
- those chunks touch. Content hashes make `touch`-ed but unchanged files free.
92
+ `ragx-cli index` is **incremental by default** (0.4.0; `--changed` is a deprecated alias): it
93
+ re-embeds only new/modified files, drops deleted ones, and repairs only the edge lists those
94
+ chunks touch. Content hashes make `touch`-ed but unchanged files free, and include/exclude glob
95
+ changes converge to the same file set a rebuild would produce. `--full` rebuilds from scratch;
96
+ changing `embeddings.model`, `chunking.*`, or `graph.edge_source` requires it — incremental runs
97
+ fail loud on the manifest mismatch. `ragx-cli status` reports **drift** (files new/changed/deleted
98
+ since the last index) so you can see when a re-index is due without running one.
93
99
 
94
100
  ### Querying
95
101
 
@@ -286,6 +292,53 @@ Full write-ups: `research/bge-m3-dense-q8-vs-nomic-q4-benchmark-2026-07-12-workt
286
292
 
287
293
  ---
288
294
 
295
+ ## Picking models: `ragx-cli models`
296
+
297
+ `ragx-cli models` recommends an embedding + reranker combo, downloads the embedding model
298
+ **through LM Studio** (`lms get` — one download path, plays well with restricted networks),
299
+ pre-fetches the reranker from Hugging Face, and writes both to `ragx.toml`. Interactive on a
300
+ TTY (quality tier + engine questions, RAM auto-detected); scriptable via flags:
301
+
302
+ ```bash
303
+ ragx-cli models # interactive
304
+ ragx-cli models --quality balanced --yes --json # agents
305
+ ragx-cli models --quality fast --dry-run # recommend only, change nothing
306
+ ```
307
+
308
+ The curated catalog (every entry verified working end-to-end):
309
+
310
+ | tier | embedding model | notes |
311
+ |---|---|---|
312
+ | `fast` | EmbeddingGemma 300M | 308M, 100+ languages, 2048-token context |
313
+ | `balanced` | BGE-M3 | ragx's benchmarked production model (~100 languages) |
314
+ | `best` | Qwen3-Embedding-0.6B | 100+ languages, 32K context |
315
+ | `jina-nano` | Jina embeddings v5 nano | 239M, best-in-class sub-500M; **CC-BY-NC (non-commercial)**; llama-server engine only — LM Studio downloads it but can't serve EuroBERT |
316
+
317
+ **Serving engines.** Embeddings run through `--embed-engine`: **`llama-server`** (default when
318
+ llama.cpp is installed — ragx auto-spawns `llama-server --embedding` on the downloaded GGUF and
319
+ terminates it at exit; LM Studio is only the downloader) or **`lm-studio`** (LM Studio serves
320
+ `/v1/embeddings`; zero extra processes, LM Studio must be running). The reranker —
321
+ `BAAI/bge-reranker-v2-m3` (multilingual) — runs through `--rerank-engine`:
322
+
323
+ - **`llama-server`** (default when llama.cpp is installed): the reranker's Q8_0 GGUF is also
324
+ downloaded via LM Studio, and ragx auto-spawns/terminates a `llama-server --rerank` process
325
+ at query time (`rerank.provider="llama-server"`, `rerank.gguf`, `rerank.base_url`,
326
+ `rerank.server_bin`). **No huggingface.co access needed anywhere.** GGUF scores are validated
327
+ within ~0.5 logit of the safetensors originals.
328
+ - **`sentence-transformers`**: the classic CrossEncoder path; model pre-fetched from Hugging
329
+ Face (needs the `ragx-cli[rerank]` extra).
330
+
331
+ With both engines on `llama-server` the whole stack is ragx-managed: LM Studio downloads the
332
+ GGUFs, ragx spawns and reaps the servers, and neither LM Studio nor huggingface.co is needed
333
+ at query time. Under 8 GB RAM the embedding tier drops to `fast`; on macOS
334
+ `lms get --yes` picks MLX variants where LM Studio's catalog offers them. Switching the
335
+ embedding model invalidates the index — the command tells you to run `ragx-cli index --full`.
336
+ `init` offers this flow as its final step; rerun `ragx-cli models` anytime to switch.
337
+
338
+ Why not `jina-embeddings-v5-text-nano`? Excellent model, but its EuroBERT architecture needs
339
+ Jina's llama.cpp fork — stock LM Studio can't load it (and the license is CC-BY-NC). See
340
+ `research/lm-studio-model-download-api-and-curated-embedding-reranker-catalog-for-ragx-models-command.md`.
341
+
289
342
  ## Agent-first conventions
290
343
 
291
344
  - `--json` emits exactly one JSON document on stdout (versioned schemas: `ragx.query.v1`,
@@ -294,6 +347,8 @@ Full write-ups: `research/bge-m3-dense-q8-vs-nomic-q4-benchmark-2026-07-12-workt
294
347
  - Every chunk carries `file`, `line_start/line_end`, `byte_start/byte_end` — agents jump to the
295
348
  exact source location and read the full text themselves (JSON chunk text is truncated).
296
349
  - `--files-only` aggregates chunk scores per file (sum of top-3) — the mode coding agents use most.
350
+ - `ragx-cli status` includes a `drift` object (`new`/`changed`/`deleted` file counts vs the index) —
351
+ agents check it to decide whether to run `ragx-cli index` before querying.
297
352
  - `ragx-cli query -` reads the query from stdin; `ragx-cli inspect chunk|file|neighbors|communities|community`
298
353
  debugs the graph.
299
354
 
@@ -313,7 +368,8 @@ questions; fall back to grep for exact identifiers.
313
368
  `file` + `line_start/line_end`; the JSON `text` is truncated, so read the file yourself
314
369
  for full context.
315
370
  - Fast mode (no LLM call, no cross-encoder): add `--no-expand --no-rerank`.
316
- - After adding or editing files: `ragx-cli index --changed` (cheap, hash-based).
371
+ - After adding or editing files: `ragx-cli index` (incremental and cheap — hash-based).
372
+ `ragx-cli status --json` shows `drift` counts if you want to check staleness first.
317
373
  - stdout is exactly one JSON document; logs are on stderr.
318
374
  Exit codes: 0 = results, 1 = no results (not an error), 2 = error.
319
375
  - Why did this result appear? `ragx-cli query "..." --explain`.
@@ -373,9 +429,19 @@ detects the mismatch and asks you to run a full `ragx-cli index`.
373
429
 
374
430
  ### Reranker on restricted networks (no huggingface.co)
375
431
 
376
- The reranker model (`BAAI/bge-reranker-v2-m3`, ~2.3 GB) is downloaded from huggingface.co on
377
- first use. If your network blocks huggingface.co, ragx-cli degrades gracefully — queries run
378
- without reranking and a warning explains why — but you have three ways to get reranking working:
432
+ With the default `sentence-transformers` engine, the reranker model
433
+ (`BAAI/bge-reranker-v2-m3`, ~2.3 GB) is downloaded from huggingface.co on first use. If your
434
+ network blocks huggingface.co, ragx-cli degrades gracefully — queries run without reranking
435
+ and a warning explains why — and the easiest fix is to skip huggingface.co entirely:
436
+
437
+ **Option 0 — the `llama-server` engine (recommended).** `ragx-cli models --rerank-engine
438
+ llama-server` downloads a validated Q8_0 GGUF of the reranker **through LM Studio** (same
439
+ download path as the embedding model) and reranks via llama.cpp's `llama-server --rerank`,
440
+ which ragx starts and stops automatically. Requires a recent llama.cpp
441
+ (`brew install llama.cpp`); no torch, no sentence-transformers, no huggingface.co. The GGUFs
442
+ score within ~0.5 logit of the safetensors originals with identical ordering.
443
+
444
+ Prefer the sentence-transformers engine? Three more ways:
379
445
 
380
446
  **Option A — copy the model and point `rerank.model` at the directory** (recommended).
381
447
  On any machine with access:
@@ -471,7 +537,7 @@ Checked features are built and validated per [the implementation plan](ragx-cli-
471
537
  unchecked ones are next up. Release history: [CHANGELOG.md](CHANGELOG.md).
472
538
 
473
539
  - [x] **CLI & storage**: typer CLI, SQLite schema, provider abstraction (Embedder/Generator/Reranker)
474
- - [x] **Baseline vector RAG**: discovery, chunking, embeddings, HNSW search, incremental `--changed`
540
+ - [x] **Baseline vector RAG**: discovery, chunking, embeddings, HNSW search, incremental indexing
475
541
  - [x] **Similarity graph**: kNN edge construction, heat-propagation traversal, `inspect`, `--explain`
476
542
  - [x] **Quality & measurement**: multi-query/HyDE expansion, RRF fusion, cross-encoder rerank, `eval` harness
477
543
  - [x] **Communities**: Leiden detection over the edge list (index-time, read-only via status/inspect)
@@ -479,11 +545,13 @@ unchecked ones are next up. Release history: [CHANGELOG.md](CHANGELOG.md).
479
545
  - [x] **Committable config**: `ragx.toml` at the corpus root (0.3.0; was `.ragx/config.toml`), index data stays gitignored in `.ragx/`
480
546
  - [x] **Offline-friendly rerank**: graceful degradation + pre-seeding docs when huggingface.co is unreachable
481
547
  - [x] **Sub-chunk edges** (opt-in `graph.edge_source="subchunk"`): edge weight = max cosine over sentence-aligned sub-chunk pairs, for corpora with long multi-concept chunks
548
+ - [x] **Incremental by default** (0.4.0): `index` hash-diffs, `--full` rebuilds, `status` reports corpus drift, chunking params are manifest-guarded
549
+ - [x] **`ragx-cli models`**: curated embedding/reranker recommendation (quality tier + RAM detection), downloads via LM Studio's `lms get`, serving via llama-server or LM Studio
482
550
  - [ ] **Community labels**: name the Leiden communities so they're browsable without reading member chunks
483
551
  - [ ] **query --global** for corpus-level questions (answer from community summaries, not individual chunks)
484
552
  - [ ] **MCP server**: a second thin shell over `ragx.core` (the core/CLI split it needs is already enforced)
485
553
  - [ ] **[Temporal weighting](docs/feature-temporal-weighting.md)**: opt-in `--since`/`--until`/`--temporal recent|oldest`, date cascade filename/frontmatter → git → mtime
486
554
  - [x] **Release**: publish to PyPI as `ragx-cli` (plain `ragx` is name-blocked, too similar to an existing project) so `uvx ragx-cli` works out of the box
487
555
 
488
- Development: `uv sync --group dev && uv run pytest`. 177 tests; module contracts live in
556
+ Development: `uv sync --group dev && uv run pytest`. 183 tests; module contracts live in
489
557
  `CONTRACTS.md` / `CONTRACTS-PHASE23.md`.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ragx-cli"
3
- version = "0.3.3"
3
+ version = "0.5.0"
4
4
  description = "Similarity-graph RAG CLI: index a corpus into a chunk-level embedding graph and query it"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -0,0 +1,119 @@
1
+ # LM Studio model downloads + curated embedding/reranker catalog for `ragx-cli models`
2
+
3
+ Date: 2026-07-15. Sources: lmstudio.ai official docs, lmstudio-ai/lms + lmstudio-python source,
4
+ Hugging Face model cards, live tests on LM Studio 0.4.12 (this machine). Full agent reports
5
+ summarized here; doc URLs at the bottom.
6
+
7
+ ## 1. How to trigger LM Studio downloads programmatically
8
+
9
+ Three mechanisms exist; capabilities verified live on 0.4.12:
10
+
11
+ | Mechanism | Unattended | Needs server up | Notes |
12
+ |---|---|---|---|
13
+ | `lms get <ref> --yes` | yes (exit 0/1, ANSI noise on stdout) | **no** | `<ref>` = catalog id (`google/embedding-gemma-300m`), search term, or full HF URL; `@quant` suffix; `--gguf`/`--mlx` filters. `--yes` auto-picks the hardware-preferred variant. |
14
+ | REST `POST /api/v1/models/download` + poll `GET /api/v1/models/download/status/:job_id` | yes (clean JSON) | yes, ≥0.4.0 | structured errors (`model_not_found`); optional bearer auth off by default. |
15
+ | Python SDK `lmstudio` (`client.repository.search_models → get_download_options → download`) | yes (blocking + progress callback) | yes | extra dependency; nicest API. |
16
+
17
+ - `lms` ships with the app (linked at `~/.lmstudio/bin/lms` after first app run); detect via
18
+ `shutil.which("lms")` + that fallback path. `lms version` prints no semver (use the app plist
19
+ on macOS if ever needed).
20
+ - Verify success + resolve the served model key via `lms ls --json`: entries carry `modelKey`,
21
+ `type` (`"embedding"`/`"llm"`), `format` (`gguf`/`mlx`), `path` (relative to models root),
22
+ `sizeBytes`, `architecture`.
23
+ - Downloads land in `<lmstudio-home>/models/{publisher}/{repo}/…`; home found via
24
+ `~/.lmstudio-home-pointer` (internal, not contractual).
25
+ - REST has **no** catalog-search endpoint; SDK does.
26
+
27
+ **Hard limitation (verified live, twice):** LM Studio only downloads GGUF or MLX-converted
28
+ artifacts. Plain transformers safetensors repos are rejected at resolution time —
29
+ `lms get https://huggingface.co/Alibaba-NLP/gte-reranker-modernbert-base --yes` → exit 1,
30
+ "No download options available". A GGUF conversion of that reranker exists
31
+ (`jolleyboy/gte-reranker-modernbert-base-GGUF`) and downloads fine, but sentence-transformers
32
+ cannot load GGUF, and LM Studio has no /v1/rerank endpoint to serve it. **Conclusion: the
33
+ reranker cannot ride the LM Studio download path in any usable form; it stays on the
34
+ HF/sentence-transformers path** (huggingface_hub `snapshot_download` for pre-fetching).
35
+
36
+ ## 2. Requested models — verdicts
37
+
38
+ ### jina-embeddings-v5-text-nano (`jinaai/jina-embeddings-v5-text-nano`)
39
+ Real (released 2026-02-18): 239M EuroBERT-based, 768 dims (Matryoshka 32–768), 8192 ctx,
40
+ 71.0 MTEB-en — best-in-class sub-500M. BUT:
41
+ - **EuroBERT is not supported by stock llama.cpp** — Jina's cards say to use *their fork*;
42
+ LM Studio ships stock llama.cpp, so the GGUF repos (`…-nano-retrieval[-GGUF]`) won't load.
43
+ - The MLX ports (`…-nano-mlx`) are custom-code (own `model.py`), not LM Studio-loadable.
44
+ - License **CC-BY-NC-4.0** (non-commercial) — bad default for a recommendation catalog.
45
+ → Excluded from the catalog until upstream llama.cpp support lands. Revisit: watch
46
+ ggml-org/llama.cpp for EuroBERT and ollama/ollama#14641.
47
+
48
+ ### gte-reranker-modernbert-base (`Alibaba-NLP/gte-reranker-modernbert-base`)
49
+ 149M ModernBERT cross-encoder, 8192 ctx, Apache-2.0, loads in `CrossEncoder(...)` natively
50
+ (transformers ≥4.48, no trust_remote_code). BEIR 56.73; third-party Feb-2026 benchmark: tied
51
+ best Hit@1 at 8× smaller than a 1.2B competitor, ahead of bge-reranker-v2-m3 — on **English**.
52
+ It is English-only; ragx's eval corpus is EN+NL where bge-reranker-v2-m3's multilingual
53
+ training is the reason the Dutch recall win exists. → Catalog **English tier** reranker;
54
+ bge-reranker-v2-m3 stays the multilingual tier/default.
55
+
56
+ ## 3. Curated catalog (all embedding entries verified LM Studio-loadable)
57
+
58
+ | Tier | Model | Why | Prefixes |
59
+ |---|---|---|---|
60
+ | fast | `lmstudio-community/embeddinggemma-300m-qat-GGUF` (curated catalog id `google/embedding-gemma-300m`) | 308M, 100+ langs, in LM Studio's own catalog; 2048 ctx / 768 dims cap quality | query `"task: search result \| query: "`, doc `"title: none \| text: "` |
61
+ | balanced | BGE-M3 GGUF (`gaianet/bge-m3-GGUF`) | current ragx production model; ~100 langs, 1024 dims, 8192 ctx, MIT; benchmarked best on the ragx eval corpus | none |
62
+ | best | `Qwen/Qwen3-Embedding-0.6B-GGUF` | Apache-2.0, 100+ langs, 32K ctx, MRL 1024 dims; top multilingual MTEB family; runs on upstream llama.cpp (early 0.3.16/0.3.17 LM Studio bugs since fixed) | query instruct prefix, doc none |
63
+ | reranker (multilingual, default) | `BAAI/bge-reranker-v2-m3` | current default; only clean multilingual CrossEncoder without trust_remote_code | – |
64
+ | reranker (English) | `Alibaba-NLP/gte-reranker-modernbert-base` | 149M, faster, beats bge-v2-m3 on EN benchmarks | – |
65
+
66
+ Rejected alternatives: `gte-multilingual-reranker-base` (306M, good numbers, but needs
67
+ trust_remote_code — security/UX friction), `jina-reranker-v2-base-multilingual` (NC license,
68
+ trust_remote_code, 1024-tok window), `Qwen3-Reranker-0.6B` (causal-LM yes/no scoring, doesn't
69
+ fit the CrossEncoder wrapper).
70
+
71
+ All three embedding tiers are multilingual, so the "multilingual?" question only steers the
72
+ reranker (EN → gte, otherwise bge-v2-m3). Spec detection: total RAM (<8 GB → force fast tier);
73
+ macOS → let `lms get --yes` hardware-preselect MLX where LM Studio's catalog offers it
74
+ (pinned GGUF URLs stay GGUF — they run on Metal fine; that's how bge-m3 Q8 runs today).
75
+
76
+ ## 4. Design consequences for `ragx-cli models`
77
+
78
+ - Prefer `lms` CLI subprocess over REST/SDK: works with the server down, zero new deps.
79
+ Absent `lms` → graceful message pointing at lmstudio.ai.
80
+ - After `lms get` exit 0: re-run `lms ls --json`, match the new entry by repo fragment, use its
81
+ `modelKey` as `embeddings.model`, and write the tier's doc/query prefixes to config.
82
+ - Reranker pre-fetch: `huggingface_hub.snapshot_download` (ships with the `rerank` extra);
83
+ degrade to a printed hint when the extra isn't installed.
84
+ - Changing `embeddings.model` invalidates the index (manifest guard) → command must end with a
85
+ loud `ragx-cli index --full` pointer, never auto-reindex.
86
+
87
+ ## Decision outcomes (2026-07-15, reviewed by Albert — folded from the session's DECISIONS.md)
88
+
89
+ 1. **jina-embeddings-v5-text-nano**: first excluded (stock LM Studio couldn't load EuroBERT),
90
+ then EuroBERT landed in upstream llama.cpp and the retrieval GGUF proved out end-to-end via
91
+ `llama-server --embedding` → **included as the 4th catalog option** (`--quality jina-nano`),
92
+ llama-server engine only, CC-BY-NC warning attached. LM Studio still downloads-but-misclassifies
93
+ it (`type: "llm"` → its /v1/embeddings refuses; candidate LM Studio bug report).
94
+ 2. **Reranker delivery**: HF-only at first (LM Studio rejects safetensors; ST can't read GGUF);
95
+ superseded the same day by `rerank.provider="llama-server"` — GGUF via LM Studio, served by
96
+ an auto-spawned `llama-server --rerank`. Q8_0 GGUFs validated ≈ safetensors (within ~0.5
97
+ logit, identical ordering — the all-negative bge logits on toy Dutch pairs match safetensors
98
+ exactly; model behavior, not conversion loss). Verified on brew llama.cpp 9960.
99
+ 3. **gte-reranker-modernbert-base (English-only) dropped entirely** per Albert — one multilingual
100
+ reranker (bge-reranker-v2-m3) keeps the measured Dutch-recall win; the multilingual question
101
+ left the CLI with it.
102
+ 4. **Downloads**: `lms get --yes` subprocess (works with the server down, zero deps) over REST/SDK.
103
+ 5. **MLX**: no hard pinning; `lms get --yes` hardware-preselects; explicit `gguf_ref`s exist per
104
+ entry because the llama-server engine can't load MLX.
105
+ 6. **Embedding tiers**: embeddinggemma-300m / bge-m3 / qwen3-embedding-0.6b confirmed by Albert.
106
+ 7. **Single-engine mode** (Albert's direction): `embeddings.provider="llama-server"` mirrors the
107
+ rerank engine (shared `providers/llama_process.py`, ports 9813/9814, atexit reaping); both
108
+ engine prompts default to llama-server when the binary exists — LM Studio becomes
109
+ downloader-only at query time. Trade-off: ~1–2 s cold-spawn per engine per process lifetime.
110
+ 8. **No auto-reindex on model switch** — loud `ragx-cli index --full` pointer instead; rebuild
111
+ spend stays explicit.
112
+
113
+ ## Doc URLs
114
+
115
+ lmstudio.ai/docs/cli · /docs/cli/get · /docs/developer/rest · /docs/developer/rest/download ·
116
+ /docs/developer/rest/download-status · /docs/python · github.com/lmstudio-ai/lms ·
117
+ github.com/lmstudio-ai/lmstudio-python · huggingface.co/jinaai/jina-embeddings-v5-text-nano ·
118
+ huggingface.co/Alibaba-NLP/gte-reranker-modernbert-base · huggingface.co/Qwen/Qwen3-Embedding-0.6B-GGUF ·
119
+ lmstudio.ai/models/google/embedding-gemma-300m · huggingface.co/BAAI/bge-reranker-v2-m3
@@ -0,0 +1,90 @@
1
+ ---
2
+ name: ragx-cli
3
+ description: |
4
+ Query a ragx-cli semantic index instead of grepping. Use when the user asks a conceptual or
5
+ natural-language question about a corpus ("where is X discussed/decided?", "find notes about Y"),
6
+ when you are about to grep/rg for a concept (not an exact identifier) in a directory that contains
7
+ a `.ragx/` folder or `ragx.toml`, or when the user says `/ragx`, "search my notes", or "semantic
8
+ search". Covers running queries, interpreting the JSON output, and keeping the index fresh.
9
+ ---
10
+
11
+ # ragx-cli — semantic search over an indexed corpus
12
+
13
+ Indexes files into a chunk-level embedding similarity graph; answers queries via vector search +
14
+ graph traversal + cross-encoder rerank. Agent-first: one JSON doc on stdout, logs on stderr,
15
+ deterministic exit codes, byte-exact source locations.
16
+
17
+ ## When
18
+
19
+ A corpus is ragx-indexed if its root has `ragx.toml` and `.ragx/`.
20
+
21
+ - Use ragx-cli for conceptual, natural-language questions ("where do we discuss auth tradeoffs?",
22
+ cross-language queries). Full questions beat keywords.
23
+ - Use grep/rg for exact identifiers and literal strings. ragx does not replace it.
24
+ - Not on PATH: `uvx ragx-cli …` works (PyPI name is `ragx-cli`). Run from anywhere inside the
25
+ corpus — root is found upward.
26
+
27
+ ## Commands
28
+
29
+ ```bash
30
+ ragx-cli status --json # root, model, counts, and drift (new/changed/deleted vs index)
31
+ ragx-cli query "question" --json --files-only # which files are relevant — most-used mode
32
+ ragx-cli query "..." --json --top 8 # ranked chunks with exact locations
33
+ ragx-cli query "..." --json --no-expand --no-rerank # fast: skip LLM call + cross-encoder
34
+ echo "..." | ragx-cli query - --json # long/multiline query from stdin
35
+ ragx-cli index # incremental reindex (hash-based, cheap) — the default
36
+ ragx-cli index --full # full rebuild: re-chunks + re-embeds everything
37
+ ```
38
+
39
+ Other query flags: `--no-graph`, `--hops N`, `--explain`.
40
+
41
+ ## Output
42
+
43
+ - stdout is exactly one JSON doc (`ragx.query.v1` / `ragx.files.v1` / `ragx.status.v1`); logs go
44
+ to stderr. Never parse stderr.
45
+ - Exit codes: `0` results, `1` success-but-empty (report "nothing found", don't retry as failure),
46
+ `2` error.
47
+ - Chunk results carry `file`, `line_start/end`, `byte_start/end`, `score`, `breakdown`. JSON
48
+ `text` is truncated — read the file at the line range for full context.
49
+ - Typical flow: `--files-only` to pick files → `--top 8` for locations → read files at ranges.
50
+
51
+ ## Freshness
52
+
53
+ - `status` includes `drift` counts; nonzero means the index is stale → run `ragx-cli index`
54
+ (incremental, safe, converges even after include/exclude glob changes).
55
+ - Changing `embeddings.model`, `chunking.*`, or `graph.edge_source` invalidates the index:
56
+ commands fail loud on the manifest mismatch, and the fix is `ragx-cli index --full` —
57
+ re-embeds everything, so confirm before running on a large corpus.
58
+ - `ragx-cli models` picks + downloads an embedding/reranker combo. All files download via
59
+ LM Studio; serving is per engine — `--embed-engine llama-server|lm-studio` and
60
+ `--rerank-engine llama-server|sentence-transformers`. With both on `llama-server`
61
+ (the default when llama.cpp is installed), ragx auto-spawns/reaps the servers and
62
+ needs neither LM Studio nor huggingface.co at query time. Other flags: `--quality
63
+ fast|balanced|best|jina-nano`, `--yes`, `--dry-run`, `--json`.
64
+
65
+ ## Why did/didn't a result appear?
66
+
67
+ - `ragx-cli query "..." --explain` — per-result trace: seed, graph edge, hop.
68
+ - `ragx-cli inspect neighbors <chunk_id>` / `inspect chunk <id>` / `inspect file <path>` /
69
+ `inspect communities` / `inspect community <id>`.
70
+
71
+ ## Gotchas
72
+
73
+ - The embedding provider must be reachable (default: LM Studio at `localhost:1234`; Ollama and
74
+ any OpenAI-compatible endpoint via config). On connection error, report it and suggest starting
75
+ the provider — never silently fall back to grep.
76
+ - Query expansion degrades gracefully (LLM down → no-op); embeddings do not.
77
+ - `--changed` is a deprecated alias — incremental is the default now.
78
+ - The corpus may be someone's personal notes repo: never `git add`/commit there. Querying and
79
+ `ragx-cli index` are safe.
80
+
81
+ ## New corpus (only when asked)
82
+
83
+ ```bash
84
+ ragx-cli init
85
+ ragx-cli config set embeddings.model <model-id> # match what the provider serves
86
+ ragx-cli index
87
+ ```
88
+
89
+ Provider recipes are in the ragx-cli README. Check `ragx-cli status` and
90
+ `curl -s http://localhost:1234/v1/models` before guessing model ids.