quillrag
quillrag
Un solo archivo. Cero dependencias. Listo antes de que tu editor termine de cargar.
Un motor RAG local en un único binario estático: embeddings MiniLM compilados dentro, recuperación híbrida densa + BM25, nativo para MCP. Sin Node, sin Python, sin descarga de modelos en la primera consulta.
Por qué quillrag
~20 ms para estar listo | El handshake de MCP se completa antes de que el modelo siquiera cargue |
Cero dependencias en tiempo de ejecución | sin Node, sin Python, sin pip/npm, sin descargas de modelos — nunca |
Recuperación híbrida | coseno denso ⊕ BM25 fusionados con Reciprocal Rank Fusion |
Privado por construcción | sin ruta de código de red después de la instalación |
Un archivo, tres SO | ~105 MB (el modelo vive dentro), compilado por CI para linux/macOS/Windows |
Related MCP server: mcp-fts5-starter
Inicio rápido
# 1. grab a prebuilt binary (or cargo install --path .)
gh release download --repo Ayush-yadav11/quillrag -p '*linux*'
tar xzf quillrag-x86_64-linux.tar.gz && chmod +x quillrag
# 2. point it at any folder of notes/docs/code
./quillrag index ~/notes # incremental walk
# 3. ask it something
./quillrag search "how does backpropagation work"O conéctalo directamente a Claude Desktop / Cursor y deja que la IA busque en tus notas a mitad de conversación — configuración abajo.
$ ./quillrag serve --data-dir ~/.local/share/quillrag
2026-08-26 INFO quillrag 0.1.2 ready in 41ms <- handshake-ready before the model loadsPor qué es rápido
Etapa | Costo |
Inicio del binario + inicialización de MCP | ~20 ms (medido: apertura de almacén + registro de herramientas únicamente) |
Primera llamada a | +~300 ms una sola vez (mmap safetensors, construir grafo BERT) |
Búsquedas posteriores | ~25 ms por consulta (CPU de 2 núcleos, corpus pequeño) |
Re-indexación de corpus sin cambios | casi cero (omisión por hash de contenido FNV) |
El modelo de embeddings es perezoso: el handshake de MCP y rag_status nunca lo
tocan, así que los editores ven un servidor instantáneo.
Instalación
Descarga un archivo precompilado desde la última versión — Windows x86_64, macOS Apple Silicon y Linux x86_64 son compilados por CI en cada etiqueta de versión:
# linux/macOS example: fetch + extract the latest release
gh release download --repo Ayush-yadav11/quillrag -p '*linux*' | tar xz
chmod +x quillrag && ./quillrag --versionO compila desde el código fuente:
cargo install --path .Objetivos de compilación cruzada usados por CI: x86_64-unknown-linux-gnu,
aarch64-apple-darwin, x86_64-pc-windows-msvc.
Conéctalo a tu editor
Claude Desktop / Cursor / cualquier cliente MCP:
{
"mcpServers": {
"quillrag": {
"command": "/usr/local/bin/quillrag",
"args": ["serve"],
"env": { "QUILLRAG_DATA": "~/.local/share/quillrag" }
}
}
}O simplemente ejecuta ./quillrag serve y apunta cualquier cliente stdio hacia él.
Herramientas
Herramienta | Qué hace |
| Indexa incrementalmente un directorio/archivo. Omite archivos sin cambios, elimina los borrados, re-embediza solo las diferencias. |
| Recuperación híbrida: coseno denso MiniLM + palabras clave BM25, fusionados con Reciprocal Rank Fusion. Devuelve fragmentos clasificados con rutas de origen. |
| Conteos de documentos/fragmentos, bytes indexados, desglose por tipo de archivo. |
| Borra todo. |
Equivalentes CLI (mismo motor):
quillrag index ~/notes # incremental walk
quillrag search "auth flow" -k 5 # one-shot search
quillrag status # stats
quillrag clear # wipeDiseño
Embeddings: candle (Rust puro) ejecutando
sentence-transformers/all-MiniLM-L6-v2— pooling de media enmascarada + norma L2, coincidiendo numéricamente con sentence-transformers en CPU. Los pesos se incluyen coninclude_bytes!en el binario y se mapean con mmap desde una caché materializada en la primera carga.Almacenamiento: un único archivo redb — texto de fragmentos, vectores f32 crudos, metadatos de documentos. Commits atómicos; seguro ante fallos.
Palabras clave: índice secundario BM25 de tantivy reconstruido en cada pasada de indexación (barato a escala de bolsillo).
Fusión: Reciprocal Rank Fusion (
Σ 1/(60+rank)) — sin ajuste de escala de puntuaciones, robusto ante rankings heterogéneos.Fragmentación: primero por párrafos con límite de 1000 caracteres y solapamiento de 120; los párrafos demasiado grandes se dividen en límites de oración.
Tipos de archivo indexados por defecto
md markdown txt rst json yaml yml toml csv tsv html htm xml log rs py js jsx ts tsx go c h cpp hpp java rb sh bash zsh sql proto graphql dockerfile makefile ini cfg conf env — amplía con -e ext1,ext2 / "extensions": [...].
Directorios ignorados: todos los directorios con punto (.git .obsidian .vscode …) más
node_modules target dist build venv __pycache__ vendor.
Privacidad y huella
Todo se ejecuta localmente: embeddings, almacenamiento, búsqueda. Nada sale de la máquina — no hay ninguna ruta de código de red después de la instalación.
Binario ≈ 105 MB (el modelo vive dentro). RAM ≈ 120 MB residentes en reposo, subiendo a ~250 MB durante el embedding por lotes.
Escalado y límites
quillrag almacena todo en un único archivo redb y ejecuta la recuperación densa como
un escaneo lineal exacto de un solo hilo sobre todos los vectores — aún sin índice ANN.
Eso hace que el límite relevante sea la latencia de consulta, no el almacenamiento. El
almacenamiento escala a millones de fragmentos; la velocidad de recuperación es O(N) por consulta.
Corpus | Vectores | RAM aprox. (f32) | Consulta en estado estable |
1K fragmentos | 1K | ~1.5 MB | ~25 ms (medido) |
10K fragmentos | 10K | ~15 MB | ~250 ms (extrapolado) |
100K fragmentos | 100K | ~154 MB | ~2–5 s (extrapolado) |
1M fragmentos | 1M | ~1.5 GB | 20–60 s (extrapolado — no viable sin ANN) |
Verificado en un corpus de 1K fragmentos (5/5 pruebas incluyendo e2e real de JSON-RPC sobre stdio); las cifras por encima de 1K son extrapoladas del costo del escaneo denso O(N), no medidas. Existe una sonda de escala sintética (src/bin/quillbench.rs) para medir la curva en tu propio hardware — ejecuta cargo build --release && ./target/release/quillbench.
Qué significa esto en la práctica:
Gran ajuste: bases de conocimiento personales/locales, documentación de proyectos, notas, código — hasta decenas de miles de fragmentos donde la latencia de sub-segundo a interactiva se mantiene.
Fuera del punto óptimo: corpus de cientos de miles o más donde necesitas recuperación interactiva (<200 ms) — querrás un índice ANN (ver Roadmap).
Cómo se compara con alternativas comunes en el eje de relevancia:
Solo embeddings (p. ej., FAISS flat crudo / almacén de vectores simple): el mismo techo de
all-MiniLM-L6-v2que la ruta densa de quillrag, pero quillrag añade fusión BM25 + RRF, que gana en consultas con muchas palabras clave (códigos de error, IDs, tokens exactos). quillrag no tiene reranker ni filtrado de metadatos, que llama-index ofrece además.Backends locales de llama-index: recuperación híbrida funcionalmente similar (BM25 + vector + RRF). quillrag cambia el rico reranking/fragmentación padre-hijo/expansión de consultas de llama-index por un binario único sin dependencias y arranque instantáneo. La relevancia en un conjunto de datos estándar (BEIR/MS MARCO) aún no está comparada — ver el issue abierto que rastrea ANN + una línea base de relevancia.
Roadmap
quillrag es deliberadamente mínimo hoy. El gran desbloqueo es un índice de vecinos más cercanos aproximados:
ANN (HNSW / IVF) sobre los vectores densos — convierte el escaneo O(N) en búsqueda ANN de sub-milisegundo, empujando el techo interactivo de ~10K a millones de fragmentos en una sola máquina.
Cuantización (PQ / SQ) — reduce la RAM de vectores de 4 bytes/dim a ~1 byte/dim, así que 1M de fragmentos ≈ 380 MB en lugar de 1.5 GB.
Escaneo multi-hilo — paraleliza la ruta exacta actual como solución provisional.
Gancho de reranker — rerank opcional con cross-encoder del top-k fusionado.
Benchmark de relevancia — BEIR / MS MARCO nDCG@10 frente a líneas base de llama-index.
Sigue el trabajo de ANN aquí: issue #1 — "Índice ANN para <1M de fragmentos."
FAQ
¿Es realmente un solo archivo? Sí. Los pesos de MiniLM + el tokenizador están compilados
dentro vía include_bytes!. Sin npm install, sin Python, sin descarga de modelos en la
primera consulta. El binario es ~105 MB porque el modelo vive dentro.
¿Por qué el arranque es tan rápido? El modelo de embeddings es perezoso. El handshake de MCP y
rag_status nunca lo tocan — los editores ven un servidor listo en ~20 ms. El modelo
solo se carga en la primera rag_search / rag_index (~300 ms una sola vez).
¿Cuál es el corpus más grande que maneja? Verificado en 1K fragmentos (~25 ms/consulta). La arquitectura escala a millones de fragmentos almacenados; la recuperación interactiva se mantiene hasta decenas de miles hoy, y un índice ANN (Roadmap) lo extiende a 1M+.
¿En qué se diferencia de llama-index? Calidad de recuperación híbrida similar, pero quillrag es un binario estático único sin huella de dependencias en tiempo de ejecución y arranque instantáneo. llama-index añade rerankers, fragmentación sofisticada y expansión de consultas que quillrag aún no tiene.
¿Qué tipos de archivo se indexan? md markdown txt rst json yaml yml toml csv tsv html htm xml log rs py js jsx ts tsx go c h cpp hpp java rb sh bash zsh sql proto graphql dockerfile makefile ini cfg conf env — amplía con -e.
¿Hace llamadas a casa? No. No hay ninguna ruta de código de red después de la instalación.
Historial de cambios
v0.1.3 — Descripciones de herramientas MCP reescritas para claridad, semántica de parámetros y transparencia de comportamiento (banderas de solo lectura/destructivas, guía de uso); server.json incluido en el repositorio para publicación en el Registro MCP.
v0.1.2 — omitir todos los directorios con punto al indexar (las configuraciones de plugins de
.obsidianya no contaminan los resultados); primera versión CI totalmente automatizada para 3 plataformas. Nota de actualización: ejecutaquillrag clearuna vez y re-indexa.v0.1.1 — Artefactos de versión compilados por CI para linux/macos/windows con sumas de verificación.
v0.1.0 — versión pública inicial; renombrado desde pocketrag.
Desarrollo
cargo test # unit + end-to-end (spawns real stdio servers)
cargo run -- serve # dev server
RUST_LOG=debug cargo run ... # verbose logs (stderr only)Licencia: MIT
Available Tools
4 toolsrag_clearA
Destructive: permanently deletes ALL indexed documents, chunks, and embeddings from the knowledge base. Cannot be undone — source files on disk are not touched, but re-indexing from scratch is required afterwards. Confirm with the user before calling.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Since there are no annotations, the description carries the full burden of behavioral disclosure. It explicitly states the operation is destructive and permanent, describes what is deleted (documents, chunks, embeddings), what is not deleted (source files on disk), and the necessity of re-indexing. It also includes a confirmation requirement. This is exemplary transparency for a destructive tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded with the critical warning 'Destructive'. Each sentence adds essential information: scope, permanence, what is preserved, and the confirmation requirement. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, no-output-schema destructive tool, the description covers all necessary aspects: what it does, consequences, side effects, and a required user interaction. An agent has everything needed to call it correctly and safely. The absence of an output schema does not matter since no output is described.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so there is nothing to explain beyond the schema. The baseline for 0-parameter tools is 4, and the description does add relevant context about the scale of the deletion, which is useful. No additional parameter details are needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the specific verb 'delete' and the resource (all indexed documents, chunks, and embeddings from the knowledge base). It distinguishes this tool from siblings like rag_search, rag_status, and rag_index by emphasizing it is a destructive clear-all operation. The scope is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context (destructive, permanent) and an explicit instruction to confirm with the user. It also notes that re-indexing is required afterwards, which implies it should only be used when a full reset is intended. However, it does not explicitly name alternatives or say when not to use it, but the destructive nature makes the usage context obvious.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rag_indexA
Index local documents into the knowledge base before searching. Pass an absolute directory path for a recursive incremental walk (skips unchanged files by content hash, prunes entries for deleted files) or a single file path. Idempotent and safe to re-run; only changed content is re-embedded. Supported types: md/txt/code files (see README for the full list); dot-directories like .git and .obsidian are skipped automatically. After indexing completes, use rag_search to query. To remove everything instead, use rag_clear.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Absolute path to a directory of documents (or a single file) to index. | |
| extensions | No | Extra file extensions to include beyond the defaults |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It thoroughly covers the tool's behavior: recursive incremental walk, content-hash change detection, deletion pruning, idempotency, re-embedding only changed content, and automatic skipping of dot-directories. No contradictions with any structured metadata exist.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise (four sentences), front-loaded with the primary purpose, and each sentence contributes meaningful information. No redundancy or filler; it efficiently packs behavioral details and sibling references without bloat.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description adequately explains the tool's actions and effects for an indexing operation, given that no output schema exists. It mentions the workflow step ('After indexing completes, use rag_search') but does not specify the response format or return value. This is a minor gap; for a tool like this, the key context is what gets destroyed/created and when to use it, which is well covered.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents both parameters. The description adds value by clarifying that 'path' accepts an absolute directory or a single file, and mentions supported types (md/txt/code) which relates to the 'extensions' parameter's defaults. This goes beyond the schema's basic explanation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear verb ('Index') and resource ('local documents into the knowledge base'), and explicitly distinguishes itself from siblings by noting that rag_search is for querying and rag_clear is for removal. This makes the tool's role unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit usage context: 'before searching', and directs users to use rag_search after indexing and rag_clear for removal. This effectively routes the agent to the correct workflow and alternatives, leaving no ambiguity about when to invoke this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rag_searchA
Search the local knowledge base using hybrid retrieval (dense MiniLM embeddings + BM25 keyword matching, fused via Reciprocal Rank Fusion). Returns up to top_k ranked chunks with source file paths, chunk indices, and relevance scores. Read-only: never modifies the index. If results are empty, call rag_index first to populate the knowledge base. Prefer this over rag_status when answering a user's question about their documents.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | The natural-language question or keywords to search for. | |
| top_k | No | Max results to return (default 5, max 25) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full behavioral burden. It clearly discloses the read-only nature ('never modifies the index') and the output structure (chunks, source paths, indices, scores). It also notes the empty‑result behavior and suggests a follow‑up action. It omits potential error conditions or performance nuances, but the disclosure is substantial for a search tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is appropriately sized—four sentences, each contributing distinct information: mechanism, output, read‑only guarantee, and usage routing. It is front-loaded with the core purpose and avoids redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description supplies essential return information (file paths, chunk indices, scores) and explains the retrieval approach. It also addresses the empty‑index scenario and distinguishes from sibling tools. Minor gaps (e.g., exact result JSON structure, authentication) are not critical for a tool of this simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for both parameters. The description reiterates the role of top_k ('up to top_k ranked chunks') but does not add syntax, formats, or constraints beyond the schema's own descriptions ('default 5, max 25'). The hybrid retrieval detail is tool-level, not parameter-specific. Minimal added value per baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Search the local knowledge base'), the retrieval method (hybrid), and the output (ranked chunks with file paths, indices, scores). It explicitly contrasts with sibling tools by noting 'Prefer this over rag_status when answering a user's question about their documents', making the tool's role unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit guidance: when to use (answering a user's question about documents), when not to (prefer rag_status for other purposes), and a conditional fallback ('If results are empty, call rag_index first to populate the knowledge base'). This fully equips the agent to choose and sequence the tool correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rag_statusA
Report knowledge base statistics: document count, chunk count, total indexed bytes, and per-file-type breakdown. Read-only and instant (does not load the embedding model). Use it to check whether anything is indexed before running a search.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It discloses that the tool is read-only, instant, and does not load the embedding model. This is good behavior disclosure for a report tool, though it doesn't mention potential limitations like staleness or exact response format, which is minor given the simplicity.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with zero waste. The first sentence lists the precise report contents, and the second gives usage and behavioral context. Information is front-loaded, making it easy to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no parameters and no output schema, the description fully covers what it does, what it returns (stats and breakdown), and when to use it. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the baseline is 4. The description doesn't need to explain parameters; it appropriately stays silent on them. No additional meaning is required beyond what the schema (empty) provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool reports knowledge base statistics (document count, chunk count, total indexed bytes, per-file-type breakdown). It uses a specific verb and resource, and the content distinguishes it from sibling tools like rag_search, rag_clear, and rag_index.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says to use it 'to check whether anything is indexed before running a search,' providing a clear context of use. It doesn't explicitly list when not to use it or alternatives, but the intended use case is clear and the siblings are evident from the tool names.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.1.3- First observed
rag_clear - First observed
rag_index - First observed
rag_search - First observed
rag_status
TDQS
Scored across 4 tools
Each tool has a single, clear responsibility: search, status, index, and clear. There is no overlap—even search and status are distinguished by read-only purpose versus metadata reporting. The descriptions explicitly note when to prefer one over the other.
All tools follow the same 'rag_' prefix followed by a lowercase verb or noun, all in snake_case. The pattern is uniform and predictable: rag_search, rag_status, rag_clear, rag_index. No mixed conventions or stylistic deviations.
With 4 tools, the server is well-scoped for a RAG knowledge base service. It covers the core operations without unnecessary bloat or missing essentials. This is within the ideal 3-15 range and each tool earns its place.
The tools cover the full lifecycle: index (create/update), search (read), status (read metadata), and clear (delete). The only minor gap is the lack of a selective document deletion, but incremental indexing and pruning handle updates well, so agents can work around this limitation.
Maintenance
Related MCP Connectors
An MCP server for search and retrieval over a local LanceDB database
Self-hosted AI workspace: semantic RAG document search, long-term memory, and AI chat via MCP.
Cloud or self-hosted knowledge for AI agents: hybrid search, reranking, GraphRAG, scoped MCP tools.
RAG-as-a-service MCP sunucusu — çok-kiracılı koleksiyon yönetimi, metin ingest (chunk+embed+upsert,…
Related MCP Servers
- AlicenseAqualityDmaintenanceLocal-first RAG indexing and semantic search MCP server. Enables document retrieval and context-aware queries using local embedding models.314 npmMIT
- AlicenseNot gradedqualityCmaintenanceDrop-in MCP server template with SQLite FTS5 search backend. ~300 lines, no vector DB, no embedding API, runs on a Pi.17 PyPIMIT
- AlicenseNot gradedqualityAmaintenanceMCP server for local RAG over personal notes, PDFs, and documents, enabling plain-English querying and hybrid search with multi-hop context expansion.MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for a self-hosted RAG system that enables AI tools to search and retrieve grounded answers from locally ingested documents via MCP tools, with local embeddings and no API key required.MIT