# Architecture

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

```mermaid
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.

## Further Reading

- [Indexing Pipeline](/indexing-pipeline)
- [Keyword Search](/keyword-search)
- [Daemon Lifecycle](/daemon)
