Architecture
Last updated
KuraDB is a single Go binary whose layers form a one-way pipeline: files enter through a watched folder, land in a per-database SQLite file, and leave only through read-only query interfaces.
System Overview
flowchart TD
inbox["~/Kura_name inbox folder"] --> watcher["Watcher: 10 s poll"]
watcher --> parsers["Parsers: text, PDF, DOCX, PPTX, CSV/TSV, XLSX"]
parsers --> handler["databaseHandler: Upsert / Dismiss"]
handler --> sqlite[("data.db: file_data table")]
sqlite --> search["search.Search"]
search --> http["HTTP API: /api/search"]
search --> mcp["MCP tools: list_rag / search_rag"]
mcp --> stdio["kura mcp over stdio"]
mcp --> remote["/mcp over HTTP, opt-in"]- flowchart TD
- inbox["~/Kura_name inbox folder"] --> watcher["Watcher: 10 s poll"]
- watcher --> parsers["Parsers: text, PDF, DOCX, PPTX, CSV/TSV, XLSX"]
- parsers --> handler["databaseHandler: Upsert / Dismiss"]
- handler --> sqlite[("data.db: file_data table")]
- sqlite --> search["search.Search"]
- search --> http["HTTP API: /api/search"]
- search --> mcp["MCP tools: list_rag / search_rag"]
- mcp --> stdio["kura mcp over stdio"]
- mcp --> remote["/mcp over HTTP, opt-in"]
Layers
| Layer | Package | Responsibility |
|---|---|---|
| CLI and daemon | cmd/app | Subcommand dispatch, daemon fork, per-database watcher loop, HTTP listener |
| Registry | internal/database (registry.go) | db.json list of registered databases, guarded by a mutex |
| Storage | internal/database (database.go, schema/file_data.sql) | Opens one SQLite file per database with separate read and write pools and applies the schema |
| Writes | internal/database/handler (upsert.go, dismiss.go) | The only code that writes file_data rows |
| Ingestion | internal/filesystem | Directory walk, change detection, file-type routing, paragraph and table chunking |
| Query | internal/search | Query parsing, keyword matching, grouping by source file |
| HTTP | internal/api | Gin router for /api/* and the optional /mcp mount |
| MCP | internal/mcp | MCP server, tool schemas, and the store that calls search.Search |
| Runtime | internal/runtime | runtime.uid PID file, liveness checks, graceful stop |
| Settings | internal/config | config.json with port and remote |
Cross-Cutting Rules
| Rule | Effect |
|---|---|
| Read-only interfaces | HTTP and MCP expose queries only; there is no endpoint that writes data |
| Single write path | Only the watcher calls databaseHandler.Upsert and databaseHandler.Dismiss; no other layer touches file_data |
| Soft delete | Removed or replaced content is flagged dismiss = TRUE; every query filters it out |
| One search implementation | MCP tools call search.Search directly instead of calling the HTTP API, so both interfaces return the same results |
| Per-database isolation | Each database has its own folder, SQLite file, and snapshot; one failing database is skipped without stopping the others |
These rules place KuraDB apart from other RAG tools. RAGFlow is a self-hosted RAG engine that pairs retrieval with agent capabilities, WeKnora is a knowledge platform built on embeddings, vector search, and reranking, AnythingLLM is a local-first agent app with a built-in vector database, and haiku.rag runs hybrid retrieval and reranking on LanceDB behind an MCP server. KuraDB runs no embedding model and keeps no vector index: it is a single Go binary that stores text chunks in one SQLite file per database, matches keywords, and leaves reasoning to the agent that calls it. mnemos is closer in form, a single Go binary on SQLite that serves MCP, but it is a memory server for agents; KuraDB indexes only the files placed in its watched folders and stores no conversation history.