knowledge-rag 4.9.2__tar.gz → 4.10.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 (43) hide show
  1. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/.gitignore +4 -0
  2. knowledge_rag-4.9.2/README.md → knowledge_rag-4.10.0/PKG-INFO +138 -65
  3. knowledge_rag-4.9.2/PKG-INFO → knowledge_rag-4.10.0/README.md +89 -113
  4. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/bench/dashboard/README.md +11 -4
  5. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/config.example.yaml +19 -11
  6. knowledge_rag-4.10.0/mcp_server/__init__.py +9 -0
  7. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/mcp_server/config.py +124 -54
  8. knowledge_rag-4.10.0/mcp_server/data/config.example.yaml +444 -0
  9. {knowledge_rag-4.9.2/presets → knowledge_rag-4.10.0/mcp_server/data}/multilingual.yaml +15 -14
  10. knowledge_rag-4.10.0/mcp_server/file_transaction.py +81 -0
  11. knowledge_rag-4.10.0/mcp_server/filesystem.py +69 -0
  12. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/mcp_server/fts5_index.py +181 -91
  13. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/mcp_server/ingestion.py +134 -77
  14. knowledge_rag-4.10.0/mcp_server/instance_lock.py +260 -0
  15. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/mcp_server/metrics.py +36 -18
  16. knowledge_rag-4.10.0/mcp_server/pdf_support.py +98 -0
  17. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/mcp_server/preflight.py +2 -2
  18. knowledge_rag-4.10.0/mcp_server/publication.py +76 -0
  19. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/mcp_server/query_router.py +2 -3
  20. knowledge_rag-4.10.0/mcp_server/search_candidates.py +33 -0
  21. knowledge_rag-4.10.0/mcp_server/search_scope.py +101 -0
  22. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/mcp_server/security.py +4 -2
  23. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/mcp_server/server.py +1283 -605
  24. knowledge_rag-4.10.0/presets/cybersecurity.yaml +367 -0
  25. knowledge_rag-4.10.0/presets/developer.yaml +364 -0
  26. knowledge_rag-4.10.0/presets/general.yaml +112 -0
  27. knowledge_rag-4.10.0/presets/multilingual.yaml +119 -0
  28. knowledge_rag-4.10.0/presets/research.yaml +256 -0
  29. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/pyproject.toml +18 -11
  30. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/requirements.txt +6 -6
  31. knowledge_rag-4.9.2/mcp_server/__init__.py +0 -17
  32. knowledge_rag-4.9.2/mcp_server/instance_lock.py +0 -188
  33. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/LICENSE +0 -0
  34. {knowledge_rag-4.9.2/presets → knowledge_rag-4.10.0/mcp_server/data}/cybersecurity.yaml +0 -0
  35. {knowledge_rag-4.9.2/presets → knowledge_rag-4.10.0/mcp_server/data}/developer.yaml +0 -0
  36. {knowledge_rag-4.9.2/presets → knowledge_rag-4.10.0/mcp_server/data}/general.yaml +0 -0
  37. {knowledge_rag-4.9.2/presets → knowledge_rag-4.10.0/mcp_server/data}/research.yaml +0 -0
  38. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/mcp_server/guarded.py +0 -0
  39. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/mcp_server/health.py +0 -0
  40. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/mcp_server/logging_config.py +0 -0
  41. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/mcp_server/ratelimit.py +0 -0
  42. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/npm/README.md +0 -0
  43. {knowledge_rag-4.9.2 → knowledge_rag-4.10.0}/skills/README.md +0 -0
@@ -4,6 +4,10 @@ __pycache__/
4
4
  *.pyc
5
5
  data/
6
6
 
7
+ # Package presets are versioned resources, not runtime storage.
8
+ !/mcp_server/data/
9
+ !/mcp_server/data/**
10
+
7
11
  # User config (personal settings — use presets/ as starting point)
8
12
  config.yaml
9
13
 
@@ -1,3 +1,52 @@
1
+ Metadata-Version: 2.5
2
+ Name: knowledge-rag
3
+ Version: 4.10.0
4
+ Summary: Local RAG System for Claude Code — Hybrid search + Cross-encoder Reranking + 13 MCP Tools + 20 Format Parsers. Zero external servers.
5
+ Project-URL: Homepage, https://github.com/lyonzin/knowledge-rag
6
+ Project-URL: Repository, https://github.com/lyonzin/knowledge-rag
7
+ Project-URL: Issues, https://github.com/lyonzin/knowledge-rag/issues
8
+ Project-URL: Changelog, https://github.com/lyonzin/knowledge-rag/releases
9
+ Author-email: "Lyon." <lyonzin@users.noreply.github.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: bm25,chromadb,claude-code,embeddings,fastembed,hybrid-search,knowledge-base,local-ai,mcp,rag,reranking,retrieval-augmented-generation,semantic-search
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Classifier: Topic :: Text Processing :: Indexing
23
+ Requires-Python: >=3.11
24
+ Requires-Dist: beautifulsoup4>=4.12.0
25
+ Requires-Dist: chromadb>=1.4.0
26
+ Requires-Dist: fastembed[reranking]>=0.4.0
27
+ Requires-Dist: mcp<3.0.0,>=2.0.0
28
+ Requires-Dist: numpy>=1.24.0
29
+ Requires-Dist: openpyxl>=3.1.0
30
+ Requires-Dist: pymupdf>=1.23.0
31
+ Requires-Dist: python-docx>=1.0.0
32
+ Requires-Dist: python-pptx>=1.0.0
33
+ Requires-Dist: pyyaml>=6.0
34
+ Requires-Dist: requests>=2.33.0
35
+ Requires-Dist: watchdog>=4.0.0
36
+ Provides-Extra: gpu
37
+ Requires-Dist: nvidia-cublas-cu12<13,>=12.8; (sys_platform == 'win32' or sys_platform == 'linux') and extra == 'gpu'
38
+ Requires-Dist: nvidia-cuda-runtime-cu12<13,>=12.8; (sys_platform == 'win32' or sys_platform == 'linux') and extra == 'gpu'
39
+ Requires-Dist: nvidia-cudnn-cu12<10,>=9; (sys_platform == 'win32' or sys_platform == 'linux') and extra == 'gpu'
40
+ Requires-Dist: nvidia-cufft-cu12; (sys_platform == 'win32' or sys_platform == 'linux') and extra == 'gpu'
41
+ Requires-Dist: nvidia-curand-cu12; (sys_platform == 'win32' or sys_platform == 'linux') and extra == 'gpu'
42
+ Requires-Dist: nvidia-cusolver-cu12; (sys_platform == 'win32' or sys_platform == 'linux') and extra == 'gpu'
43
+ Requires-Dist: nvidia-cusparse-cu12; (sys_platform == 'win32' or sys_platform == 'linux') and extra == 'gpu'
44
+ Requires-Dist: nvidia-nvjitlink-cu12; (sys_platform == 'win32' or sys_platform == 'linux') and extra == 'gpu'
45
+ Requires-Dist: onnxruntime-gpu<1.27,>=1.21; (sys_platform == 'win32' or sys_platform == 'linux') and extra == 'gpu'
46
+ Provides-Extra: server
47
+ Requires-Dist: uvicorn>=0.20.0; extra == 'server'
48
+ Description-Content-Type: text/markdown
49
+
1
50
  <!--
2
51
  knowledge-rag — Local RAG server for Claude Code, Cursor, Windsurf and other MCP clients.
3
52
  SEO keywords: local rag, mcp server, self-hosted rag, hybrid search, cross-encoder reranking, claude code rag, cursor rag, python rag, chromadb rag, fastembed rag, air-gapped rag, gdpr rag, retrieval augmented generation, model context protocol server, zero cloud rag.
@@ -80,14 +129,14 @@ pip install knowledge-rag → restart Claude Code → search_knowledge("
80
129
 
81
130
  Most RAG frameworks fall into one of three traps: (1) they require you to ship your data to a cloud API, (2) they hand you 300 building blocks and 0 opinionated defaults, or (3) they bundle RAG as a 5% feature of a much bigger platform you didn't ask for.
82
131
 
83
- **knowledge-rag does one thing well:** it is the MCP-native local RAG server that Claude Code, Cursor, Windsurf, VS Code, Cline, Gemini CLI and Zed can search out of the box — with enterprise plumbing (bearer auth, Prometheus metrics, rate limiting, health probes, structured JSON logging, zero-downtime reindex) that no other RAG-focused OSS ships built-in.
132
+ **knowledge-rag is an MCP-native local RAG server** for clients such as Claude Code, Cursor, Windsurf, VS Code, Cline, Gemini CLI and Zed. It includes optional bearer authentication, Prometheus metrics, rate limiting, health probes, structured JSON logging and staging-based rebuilds. Configure the transport and access controls for the intended deployment.
84
133
 
85
134
  <table>
86
135
  <tr>
87
136
  <td width="50%" valign="top">
88
137
 
89
138
  ### 🔒 100% local, 0% cloud
90
- Your files never leave the machine. No vendor lock-in, no data-residency headache, no forced cloud dependency. **LGPD / GDPR / HIPAA compliant by architecture** — because there is nothing to comply about when nothing leaves.
139
+ Embedding generation, indexing, and retrieval run locally. Model downloads and `add_from_url` use network access, and configured MCP clients receive retrieved content. Choose the corpus, client permissions, and network exposure to fit your deployment; this project does not certify regulatory compliance.
91
140
 
92
141
  </td>
93
142
  <td width="50%" valign="top">
@@ -101,7 +150,7 @@ Your files never leave the machine. No vendor lock-in, no data-residency headach
101
150
  <td width="50%" valign="top">
102
151
 
103
152
  ### 🛡️ Production-grade OSS
104
- 7-pillar quality gate on every PR (**35+ automated checks**), 9-cell OS×Python CI matrix (Linux + Windows + macOS × 3.11/3.12/3.13), nightly chaos + 50K-iteration soak + mutation testing. **700+ tests. 0 known regressions.**
153
+ 7-pillar quality workflow, a 9-cell OS×Python CI matrix (Linux + Windows + macOS × 3.11/3.12/3.13), and nightly chaos, bounded-memory soak and mutation tests. Inspect the checks on the revision being deployed; CI coverage is not a guarantee of zero defects.
105
154
 
106
155
  </td>
107
156
  <td width="50%" valign="top">
@@ -117,31 +166,21 @@ No token bills. No SaaS tier. No paid features hidden behind a wall. **MIT licen
117
166
 
118
167
  ## 📊 How knowledge-rag compares to other RAG frameworks
119
168
 
120
- We audited **16 popular RAG frameworks and platforms** (LlamaIndex, LangChain, ChromaDB, Weaviate, Qdrant, RAGFlow, LightRAG, DSPy, GraphRAG, Haystack, RAG-Anything, kotaemon, txtai, llmware, Dify, open-webui, FastGPT) so you can pick honestly.
121
-
122
- **Legend:** ✅ built-in · 🟡 plugin / paid tier / partial · ❌ not available · ⚠️ license or default concern
123
-
124
- | Dimension | 🎯 **knowledge-rag** | LlamaIndex | LangChain | Haystack | RAGFlow | txtai | open-webui | Dify | Qdrant |
125
- |---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
126
- | **100% local, zero cloud** | ✅ | 🟡 | ✅ | 🟡 | 🟡 | ✅ | ✅ | 🟡 | 🟡 |
127
- | **MCP native (Claude/Cursor)** | ✅ 13 tools | 🟡 pkg | 🟡 adapter | 🟡 wrapper | 🟡 add-on | ✅ | ✅ consumer | ✅ | ❌ |
128
- | **Hybrid BM25 + semantic** | ✅ 128× faster | 🟡 | 🟡 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
129
- | **Cross-encoder rerank** | ✅ builtin | ❌ | 🟡 | ✅ | ✅ fused | ❌ | ✅ | 🟡 | 🟡 |
130
- | **Bearer auth builtin** | ✅ | ❌ | ❌ | ❌ core | ❌ | 🟡 | ✅ RBAC | ✅ OAuth2 | ✅ |
131
- | **Prometheus `/metrics`** | ✅ | ❌ | ❌ | ❌ core | ❌ | ❌ | ✅ OTel | ❌ | ✅ |
132
- | **Rate limiting** | ✅ sliding-window | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ |
133
- | **Health probes** (`/health`) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🟡 | 🟡 | ✅ |
134
- | **Structured JSON logging** | ✅ opt-in | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ OTel | 🟡 | ✅ |
135
- | **Zero-downtime reindex** | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
136
- | **Async background reindex** | ✅ + polling | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | 🟡 |
137
- | **GPU CUDA optional** | ✅ 12 auto | ❌ | 🟡 | ✅ | ✅ | ✅ | ✅ | 🟡 | 🟡 |
138
- | **File formats builtin** | ✅ **20** | 0 (LlamaParse=$) | 50+ plugins | ✅ **36+** | 8+ | ? | ? | ~10 | ❌ |
139
- | **Setup < 5 min POC** | ✅ pip 1-liner | ✅ | ✅ | ✅ | ❌ 16GB RAM | ✅ | ✅ docker | ✅ docker | ✅ |
140
- | **Nightly chaos + soak + mutation** | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
141
- | **License** | ✅ MIT | MIT | MIT | Apache-2.0 | Apache-2.0 | Apache-2.0 | ⚠️ preserving | ⚠️ restrictive | Apache-2.0 |
142
-
143
- > **The 5 dimensions where knowledge-rag is unique:** health probes + JSON logging + Prometheus + rate limit + bearer auth **simultaneously built-in on an OSS RAG-focused MCP server**. Zero-downtime reindex + async background reindex + nightly chaos/soak/mutation are documented on nobody else's README.
144
-
169
+ Compare the features needed for your deployment rather than treating framework
170
+ checklists as a benchmark. Knowledge-rag combines MCP tools, local embeddings,
171
+ ChromaDB persistence, BM25, optional FTS5 and optional reranking in one process.
172
+
173
+ | Decision | What to verify |
174
+ | --- | --- |
175
+ | Local or remote processing | Where models run, which client receives content, and which features need network access |
176
+ | Retrieval quality | Expected-source queries on your corpus, including its languages and identifiers |
177
+ | Performance | Cold initialization, indexing, uncached queries, memory peaks and concurrent use on comparable hardware |
178
+ | Operations | Authentication, metrics exposure, backups, recovery and one-writer ownership |
179
+ | Extensibility | Supported parsers, model profiles and the public MCP contract |
180
+
181
+ The [audit report](docs/audit-2026-10-03.md) records a reproducible local workload
182
+ and its limitations. Results against an older implementation of this project are
183
+ not speed comparisons against other RAG frameworks.
145
184
  ---
146
185
 
147
186
  ## 🚀 Quick Start (3 minutes, from zero to your first query)
@@ -191,6 +230,30 @@ knowledge-rag --transport sse
191
230
  - Prometheus scrape: `http://your-host:9179/metrics`
192
231
  - MCP dispatcher: authenticated via `Authorization: Bearer your-secret-token`
193
232
 
233
+ ### Multi-client setup (Shared Server via Streamable HTTP)
234
+
235
+ `stdio` is ideal when one MCP client owns one `knowledge-rag` process. If several clients (e.g. Claude, Cursor, LM Studio, or multiple terminal windows) should share one index and one running process, run `knowledge-rag` once with Streamable HTTP and point each HTTP-capable client at the same endpoint (prompted by [#217](https://github.com/lyonzin/knowledge-rag/pull/217) and issue [#223](https://github.com/lyonzin/knowledge-rag/issues/223)):
236
+
237
+ ```bash
238
+ knowledge-rag --transport streamable-http
239
+ # MCP endpoint: http://127.0.0.1:8179/mcp
240
+ ```
241
+
242
+ - **Local MCP clients (Cursor, LM Studio, etc.):** Point their remote-server URL directly at `http://127.0.0.1:8179/mcp`.
243
+ - **Claude Custom Connectors (Remote MCP):**
244
+ - **Network requirement:** Custom connector requests originate from Anthropic's cloud infrastructure across web, desktop, and mobile, so they cannot reach local `127.0.0.1`. You must expose your server via a secure, publicly accessible HTTPS endpoint (e.g. Cloudflare Tunnel, ngrok, or reverse proxy) at `https://your-public-domain/mcp`. Configure the proxy to send an upstream `Host` accepted by the HTTP app for `server.host` (for the default loopback configuration, use `127.0.0.1:8179`); forwarding the public hostname unchanged can produce `421 Invalid Host header`. Keep bearer authentication and HTTPS enabled. Local `claude_desktop_config.json` uses `command`/`args` for local stdio processes and does not support remote HTTP endpoints.
245
+ - **Setup & Auth:** In Claude (Pro/Max plans: **Customize > Connectors > + Add > Add custom connector**; Team/Enterprise owners: **Organization settings > Connectors**), enter your public endpoint. In **Request headers**, set header name `Authorization` with value `Bearer <your-token>` matching `server.auth.bearer_token` in `config.yaml` (see [Anthropic Custom Connectors documentation](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp)).
246
+
247
+ | Transport | Clients | Shared index / process | RAM overhead | Process management | Startup & query latency | Best fit |
248
+ |---|:---:|:---:|---|---|---|---|
249
+ | `stdio` | 1 | No | 1 runtime per client; models load lazily in each process when queried | Client manages its own process; no separate server | Spawns per client; pays preflight and first-query model load | Simplest local setup (single client) |
250
+ | `sse` | Many | Yes | Shared server process; single shared model load across clients | Operator manages one background server | Reuses warm server; first-query model load still applies | Legacy HTTP clients |
251
+ | `streamable-http` | Many | Yes | Shared server process; single shared model load across clients | Operator manages one background server | Reuses warm server; first-query model load still applies | **Preferred** shared-server setup |
252
+
253
+ When an HTTP transport is selected, `knowledge-rag` automatically enables its single-instance lock (`KNOWLEDGE_RAG_SINGLE_INSTANCE=1`) to prevent multiple servers from binding the same data directory or port.
254
+
255
+ > **Security note:** The default host is `127.0.0.1`. If you bind to `0.0.0.0` or deploy across a network, configure `server.auth.bearer_token` in `config.yaml` and terminate TLS (HTTPS) via a reverse proxy (e.g. Caddy, Nginx) to protect bearer tokens in transit; otherwise the server warns that the HTTP endpoint is unauthenticated.
256
+
194
257
  ### Path 3 — Docker (models pre-downloaded, air-gapped ready)
195
258
 
196
259
  ```bash
@@ -273,8 +336,8 @@ Every RAG framework claims "production-ready." Here is what knowledge-rag ships
273
336
 
274
337
  - **Bearer token auth** on SSE / HTTP transports — constant-time comparison (`hmac.compare_digest`), RFC 6750 challenge, 401 fenced with `WWW-Authenticate` header
275
338
  - **Path traversal + symlink escape defenses** — `validate_path_within` guarding 6 CRUD tools (CWE-22, CWE-59)
276
- - **Prompt injection 3-layer defense** — sentinel neutralization + provenance fence + `external_source` flag (OWASP LLM01:2025)
277
- - **OpenSSF Best Practices badge** verified · **CodeQL** weekly scan · **Bandit + Semgrep + Gitleaks + pip-audit** on every PR
339
+ - **External-content handling** — known-token neutralization and a stored provenance fence, with parser metadata propagation. These are limited mitigations; clients must still treat retrieved content as untrusted data. See [SECURITY.md](SECURITY.md).
340
+ - **OpenSSF Best Practices** project [#13864](https://www.bestpractices.dev/en/projects/13864) · **CodeQL** weekly scan · **Bandit + Semgrep + Gitleaks + pip-audit** workflows. Review actual check results and exceptions for the release you deploy.
278
341
  - **PyPI Trusted Publishing** via OIDC (zero long-lived tokens in CI)
279
342
 
280
343
  </td>
@@ -296,12 +359,12 @@ Every RAG framework claims "production-ready." Here is what knowledge-rag ships
296
359
  ### Scale & performance
297
360
 
298
361
  - **SSE / streamable-http transport** — 1 server serves N MCP clients, ChromaDB WAL mode enabled automatically, shared embedding model + query cache
299
- - **BM25 inverted-index** — **128× faster** than linear scan (custom implementation, replaces `rank-bm25`)
300
- - **FTS5 SQLite fast-path** (opt-in, ADR-002/003/006/008) — <10ms cold, <2ms hot on lexical queries
301
- - **Cross-encoder reranking** — Xenova/ms-marco-MiniLM-L-6-v2, +1.88pp Recall@10 (p<0.001)
302
- - **GPU CUDA 12** with auto DLL discovery + graceful CPU fallback
303
- - **Query cache** — LRU + 5-min TTL, cuts p95 latency ~40%
304
- - **Zero-downtime reindex** — staging populate + validation + atomic swap + durable metadata rollback
362
+ - **BM25 inverted index** — keyword candidate retrieval without scoring every document for every query
363
+ - **FTS5 SQLite fast path** — opt-in lexical retrieval; measure relevance and latency on your identifiers and corpus
364
+ - **Cross-encoder reranking** — Xenova/ms-marco-MiniLM-L-6-v2; optional model scoring of a candidate pool
365
+ - **NVIDIA CUDA embeddings** and experimental Windows AMD DirectML opt-in, with actual-session checks and CPU fallback; [setup and compatibility limits](docs/gpu-setup.md)
366
+ - **Query cache** — LRU + 5-minute TTL, with mutation invalidation
367
+ - **Staging rebuild** — populate and validate a replacement while the current collection remains available; handled publication failures roll back
305
368
  - **Async background reindex** with `get_reindex_status()` polling
306
369
 
307
370
  </td>
@@ -310,11 +373,11 @@ Every RAG framework claims "production-ready." Here is what knowledge-rag ships
310
373
  ### Reliability
311
374
 
312
375
  - **Nightly chaos injection** — HuggingFace Hub offline · ONNX zero-byte replay · watchdog crash recovery (3 scenarios in `tests/chaos/`)
313
- - **50 000-iteration soak test** — proves no memory leak after 1h of continuous queries (`KNOWLEDGE_RAG_SOAK_ITERATIONS=50000`)
376
+ - **50,000-iteration soak test** — checks a fixed memory-growth budget with stub embeddings (`KNOWLEDGE_RAG_SOAK_ITERATIONS=50000`); this is not a one-hour real-model endurance test
314
377
  - **Mutation testing** (mutmut) on `instance_lock` + `preflight` — catches tests that are too weak
315
378
  - **Determinism check** — full test suite × 3, catches flakes
316
- - **Backwards-compat frozen** — 13 MCP tool parameter names guarded by `tests/test_backwards_compat.py` + legacy YAML fixtures (v3.6.0 / v3.7.0) still parse
317
- - **API surface AST diff** — `check_api_surface.py` blocks any breaking change at PR time
379
+ - **Backwards compatibility** — 13 MCP tools, signature regression tests and legacy YAML fixtures; optional additions preserve existing calls
380
+ - **API surface AST diff** — checks structural signature changes alongside behavioral tests
318
381
  - **9-cell CI matrix** — Linux + Windows + macOS × 3.11 + 3.12 + 3.13
319
382
 
320
383
  </td>
@@ -329,7 +392,7 @@ Every RAG framework claims "production-ready." Here is what knowledge-rag ships
329
392
 
330
393
  **Preset:** [`cybersecurity.yaml`](presets/cybersecurity.yaml) · 8 categories · 200+ routing keywords · 69 query expansions
331
394
 
332
- Ingest MITRE ATT&CK, threat reports, exploit writeups, incident reports. Search from Claude Code with `search_knowledge("privilege escalation windows")` and get instant recall across your entire corpus. Air-gapped — nothing leaves the laptop.
395
+ Ingest MITRE ATT&CK, threat reports, exploit writeups and incident reports. Search from an MCP client with `search_knowledge("privilege escalation windows")`. Offline operation requires cached models; the chosen client receives retrieved content and determines what happens to it afterwards.
333
396
 
334
397
  ### Development Teams — Design Docs, Runbooks, Code
335
398
 
@@ -388,8 +451,8 @@ flowchart TB
388
451
 
389
452
  subgraph SEARCH["Retrieval Pipeline"]
390
453
  R[Query Router<br/>lexical vs semantic]
391
- F[FTS5 Fast-Path<br/>opt-in · lt 10ms]
392
- BM[BM25 Inverted Index<br/>128x faster than baseline]
454
+ F[FTS5 Fast-Path<br/>opt-in lexical retrieval]
455
+ BM[BM25 Inverted Index<br/>keyword candidates]
393
456
  SE[Semantic Search<br/>FastEmbed ONNX lazy-loaded]
394
457
  RRF[Reciprocal Rank Fusion]
395
458
  CE[Cross-Encoder Rerank<br/>MiniLM-L-6-v2]
@@ -405,11 +468,11 @@ flowchart TB
405
468
  subgraph INGEST["Document Ingestion"]
406
469
  FS[documents/ folder]
407
470
  WD[Watchdog<br/>10s debounce]
408
- PA[35 Parsers<br/>MD · PDF · DOCX · code · IaC · IPYNB]
471
+ PA[Format parsers<br/>MD · PDF · DOCX · code · IaC · IPYNB]
409
472
  CK[Chunker<br/>markdown-aware · code-aware]
410
473
  EM[FastEmbed ONNX<br/>384D bge-small-en-v1.5]
411
474
  DD[SHA256 Dedup]
412
- SW[Zero-downtime Staging Swap<br/>rollback on validation fail]
475
+ SW[Staging Rebuild<br/>rollback on handled publication failure]
413
476
  end
414
477
 
415
478
  subgraph OBS["Enterprise Observability (opt-in)"]
@@ -448,7 +511,7 @@ flowchart TB
448
511
 
449
512
  FS --> WD --> PA
450
513
  PA --> CK --> EM --> DD --> CH
451
- SW -.->|atomic swap| CH
514
+ SW -.->|validated publication| CH
452
515
  SW -.-> FT
453
516
  CH -.-> MD
454
517
 
@@ -480,26 +543,26 @@ flowchart TB
480
543
 
481
544
  1. **Any MCP client** — Claude Code, Cursor, Windsurf, and 5 others — connects via the transport of your choice (stdio for personal use, SSE/streamable-http for teams).
482
545
  2. **HTTP mode chains 3 ASGI middlewares in order**: health probes first (always answered), then bearer auth (fenced with `WWW-Authenticate`), then rate limiter (sliding window).
483
- 3. **All 13 MCP tools** are decorated with `@rate_limited` + `@instrument` — Prometheus counts every call, rate limiter enforces RPM+burst, both zero-cost when disabled.
546
+ 3. **All 13 MCP tools** are decorated with `@rate_limited` + `@instrument` — metrics record calls and the rate limiter enforces RPM+burst when enabled. Disabled features skip that work, while the lightweight wrapper calls remain.
484
547
  4. **`search_knowledge` checks the query cache first**; cache miss routes through the Query Router (regex classifier) to either the FTS5 fast-path (lexical) or the hybrid pipeline (BM25 + semantic + RRF + cross-encoder rerank).
485
548
  5. **Storage is 100% local**: ChromaDB (WAL mode) for vectors + metadata, SQLite FTS5 (WAL + busy-timeout) for lexical fast-path, `index_metadata.json` for durable state.
486
- 6. **Document ingestion runs continuously**: watchdog observes `documents/`, 35 parsers handle each format, chunker respects language boundaries, FastEmbed ONNX generates embeddings, SHA256 deduplicates, and a staging swap performs zero-downtime rebuilds with rollback-on-failure.
549
+ 6. **Document ingestion**: when enabled, watchdog observes `documents/`; format parsers create chunks, FastEmbed generates embeddings, and source metadata supports incremental updates. Full rebuilds use staging. See the operations guide for publication and recovery limits.
487
550
  7. **Enterprise observability** (opt-in) — Prometheus `/metrics`, structured JSON logs, `/health` payload — attaches to the same instrumentation points, no code changes required.
488
551
  8. **`config.yaml` (with 5 domain presets)** controls every subsystem — no environment variable spaghetti, no hardcoded paths.
489
552
 
490
- **Complete architecture — 4 detailed Mermaid diagrams (System Overview · Query Flow · Document Ingestion · hybrid_alpha effect):** [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
553
+ **Component ownership, query/ingestion diagrams, memory boundaries and hybrid weights:** [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
491
554
 
492
555
  ---
493
556
 
494
557
  ## 📄 35 File Formats — parsed natively, no plugins needed
495
558
 
496
- Every parser is **chunk-aware** — Markdown splits at `##` headers, code splits at function/class boundaries, notebooks skip base64 outputs, PDFs use PyMuPDF, spreadsheets extract sheet-by-sheet. **33 formats are enabled by default**; the 2 MetaTrader formats are opt-in (add to `documents.supported_formats` in `config.yaml`).
559
+ Parsers use format-specific extraction: Markdown sections, code boundaries, notebook cells without base64 outputs, PDF text and spreadsheet rows. Several extensions share one parser. The runtime fallback list contains 33 formats; the documented template and presets can select a smaller list. Inspect your effective `documents.supported_formats`. The two MetaTrader extensions are opt-in.
497
560
 
498
561
  | # | Format | Extension | Parser | Default | Notes |
499
562
  |---|--------|-----------|--------|:-------:|-------|
500
563
  | 1 | Markdown | `.md` | Section-aware (splits at `##`) | Yes | Headers preserved as chunk boundaries |
501
564
  | 2 | Plain Text | `.txt` | Fixed-size chunking | Yes | 1000 chars + 200 overlap |
502
- | 3 | PDF | `.pdf` | PyMuPDF extraction | Yes | Text-based PDFs only (no OCR) |
565
+ | 3 | PDF | `.pdf` | PyMuPDF extraction or explicit page-marked UTF-8 text | Yes | No OCR; extracted-text recognition is limited to 4 MiB |
503
566
  | 4 | Word | `.docx` | python-docx | Yes | Headings preserved as markdown |
504
567
  | 5 | Excel | `.xlsx` | openpyxl | Yes | Sheet-by-sheet extraction |
505
568
  | 6 | PowerPoint | `.pptx` | python-pptx | Yes | Slide-by-slide extraction |
@@ -533,6 +596,16 @@ Every parser is **chunk-aware** — Markdown splits at `##` headers, code splits
533
596
  | 34 | MQL4 Source | `.mq4` | Code parser | **No** | MetaTrader — opt-in via `documents.supported_formats` |
534
597
  | 35 | MQL4 Header | `.mqh` | Code parser | **No** | MetaTrader — opt-in via `documents.supported_formats` |
535
598
 
599
+ Files with a `.pdf` extension can also contain an explicit text extraction: the
600
+ first line must be `[Page N]` with a positive page number, followed by nonempty
601
+ UTF-8 text. An optional UTF-8 BOM and tab/CR/LF whitespace are accepted. This
602
+ recognition is limited to 4 MiB, rejects other C0/C1 controls and DEL, and never
603
+ reinterprets a file containing PDF magic in the first 1 KiB as text. Accepted
604
+ extractions retain their source path and are marked `content_format=extracted_text`
605
+ and `page_count_source=markers`; the marker count is not proof of the original
606
+ PDF's total page count. Binary PDFs keep the native parser and its error
607
+ diagnostics. Invalid or oversized textual lookalikes remain errors.
608
+
536
609
  > **Enable an opt-in format** — add the extension to `documents.supported_formats` in your `config.yaml`:
537
610
  > ```yaml
538
611
  > documents:
@@ -588,7 +661,7 @@ Native MCP
588
661
 
589
662
  **Complete client configuration guide with JSON schemas per client:** [docs/INSTALLATION.md#use-with-other-mcp-clients →](docs/INSTALLATION.md#use-with-other-mcp-clients)
590
663
 
591
- > ⚠️ **Operating model — read once.** Your MCP client (Claude Desktop, Code, Cursor, etc.) **spawns and owns the knowledge-rag server process**. Do **NOT** also run `knowledge-rag` in a terminal while your MCP client is open — two writer processes against the same `data_dir` corrupt the ChromaDB HNSW segment on Windows (see [issue #216](https://github.com/lyonzin/knowledge-rag/issues/216)). Recommended baseline: add `"KNOWLEDGE_RAG_SINGLE_INSTANCE": "1"` to the `env` block of your MCP config as a safety net. Full explanation + how to run CLI commands safely: [docs/single-instance.md](docs/single-instance.md).
664
+ > ⚠️ **Operating model — read once.** In `stdio` mode, your MCP client (Claude Desktop, Code, Cursor, etc.) **spawns and owns the knowledge-rag server process**. Do **NOT** also run a second `knowledge-rag` writer in a terminal while that stdio client is open — two writer processes against the same `data_dir` corrupt the ChromaDB HNSW segment on Windows (see [issue #216](https://github.com/lyonzin/knowledge-rag/issues/216)). For HTTP transports, manually running one server and connecting HTTP clients to it is the supported shared-server workflow; do not mix it with another writer using the same `data_dir`. Recommended baseline for stdio clients: add `"KNOWLEDGE_RAG_SINGLE_INSTANCE": "1"` to the `env` block of your MCP config as a safety net. Full explanation + how to run CLI commands safely: [docs/single-instance.md](docs/single-instance.md).
592
665
 
593
666
  ---
594
667
 
@@ -604,7 +677,8 @@ paths:
604
677
  models:
605
678
  embedding:
606
679
  profile: "compact" # "compact" | "quality" | "multilingual" | "custom"
607
- gpu: "auto" # "auto" | "true" | "false"
680
+ gpu: "auto" # "auto" | "true" | "false" | "directml"
681
+ device_id: null # DirectML: explicit DXGI adapter index
608
682
  reranker:
609
683
  enabled: true # cross-encoder rerank
610
684
 
@@ -642,12 +716,12 @@ knowledge-rag is designed for teams that cannot let their documents leave the pe
642
716
  | **Supply chain security** | PyPI Trusted Publishing via OIDC (no long-lived tokens) |
643
717
  | **Vulnerability disclosure** | Private security advisory via [SECURITY.md](SECURITY.md) |
644
718
  | **Signed release attestations** | GitHub release attestations on every published version |
645
- | **Reproducible builds** | Locked `requirements.txt` with pinned versions |
719
+ | **Dependency management** | Version ranges in `requirements.txt` / `pyproject.toml`; resolve and record a tested environment for reproducibility |
646
720
  | **Authenticated access** | Bearer token middleware on SSE / HTTP transports (constant-time compare, RFC 6750) |
647
721
  | **Rate limiting** | Sliding-window per-client RPM + burst (opt-in, zero-cost when disabled) |
648
722
  | **Audit-ready logging** | Opt-in structured JSON logs → ship to your SIEM |
649
723
  | **Path traversal defenses** | CWE-22 / CWE-59 guards on 6 CRUD tools |
650
- | **Prompt injection defense** | 3-layer sanitization on `add_from_url` (OWASP LLM01:2025) |
724
+ | **External-content mitigation** | Known-token neutralization and provenance fencing on `add_from_url`; not a general prompt-injection prevention guarantee |
651
725
 
652
726
  **OpenSSF Best Practices** badge: passing · project ID [#13864](https://bestpractices.coreinfrastructure.org/projects/13864)
653
727
 
@@ -655,16 +729,14 @@ knowledge-rag is designed for teams that cannot let their documents leave the pe
655
729
 
656
730
  ## 📈 Numbers that matter
657
731
 
658
- - **26 000+** total downloads on PyPI · **250+** GitHub stars · **70+** enterprise teams (private + community)
659
- - **700+ tests** collected · **1.33:1** test-to-code ratio · **codecov trend gate** ±0.5pp
660
- - **35+ status checks** on every PR (9-cell OS×Python matrix · 7 quality pillars)
661
- - **35 file formats** parsed natively · **13 MCP tools** frozen · **5 domain presets** (cyber · dev · research · multilingual · general)
662
- - **BM25 128× faster** than baseline · **cross-encoder +1.88pp** Recall@10 (p<0.001) · **cache −40%** p95 latency
663
- - **1 800+ files / 39 K chunks indexed in < 3 min** on a modern laptop (typical developer corpus)
664
- - **Verified in production** on 5 889-doc / 75 016-chunk corpora
665
-
666
- **Public benchmark dashboard:** https://lyonzin.github.io/knowledge-rag/
732
+ - **13 MCP tools**, configurable format selection and five domain presets.
733
+ - **Nine OS/Python CI combinations** configured for Linux, macOS and Windows with Python 3.11–3.13.
734
+ - **Measured CPU/CUDA indexing and retrieval, AMD validation and memory regressions:** [audit results and reproduction](docs/audit-2026-10-03.md).
735
+ - **Historical implementation benchmarks:** [v4.7.1 baseline](docs/perf-baseline-v4.7.1.md). Historical ratios apply to their recorded workloads, not every corpus or competing product.
667
736
 
737
+ The [public benchmark dashboard](https://lyonzin.github.io/knowledge-rag/) tracks
738
+ CI workloads. Mocked storage/model workloads and real-model measurements answer
739
+ different questions; inspect the methodology and units before comparing them.
668
740
  ---
669
741
 
670
742
  ## 📚 Documentation
@@ -674,15 +746,16 @@ knowledge-rag is designed for teams that cannot let their documents leave the pe
674
746
  | [**Installation guide**](docs/INSTALLATION.md) | 5 install methods · 8 MCP client integrations · GPU setup |
675
747
  | [**API reference**](docs/API.md) | Complete reference for all 13 MCP tools |
676
748
  | [**Configuration reference**](docs/CONFIGURATION.md) | Every `config.yaml` field · presets · tuning |
677
- | [**Architecture**](docs/ARCHITECTURE.md) | 4 Mermaid diagrams: System Overview · Query Flow · Ingestion · hybrid_alpha |
749
+ | [**Architecture**](docs/ARCHITECTURE.md) | Components · query/ingestion flow · memory/concurrency boundaries · hybrid weights |
678
750
  | [**Troubleshooting**](docs/TROUBLESHOOTING.md) | 11 common issues + solutions |
679
751
  | [**FTS5 fast-path guide**](docs/features/fts5_fast_path.md) | Opt-in lexical fast-path — when and how |
680
752
  | [**Reindex operations**](docs/reindex-operations.md) | Zero-downtime rebuild · resume · checkpoint |
681
- | [**GPU setup**](docs/gpu-setup.md) | CUDA 12 installation + troubleshooting |
753
+ | [**GPU setup**](docs/gpu-setup.md) | CUDA runtime compatibility · CPU fallback · AMD/macOS GPU limitations |
682
754
  | [**Migration to v4.8.0**](docs/migration-v4.8.0.md) | Embedding profile · multilingual · zero-downtime |
683
755
  | [**Security policy**](SECURITY.md) | Threat model · disclosure channel |
684
756
  | [**Contributing**](CONTRIBUTING.md) | Development · testing · PR process |
685
757
  | [**Changelog**](CHANGELOG.md) | All release notes since v1.0.0 |
758
+ | [**Memory/GPU audit**](docs/audit-2026-10-03.md) | Reproducible workloads · measured results · validation limits · open PR/issue review |
686
759
 
687
760
  ---
688
761