| name | localdb |
| description | Search and index local document collections with the localdb CLI or MCP server — hybrid search with citations over markdown, text, and PDF files. |
When to use
Use localdb when you need to retrieve passages from a local corpus (Markdown, plain text,
PDF, or indexed URLs) with verifiable citations. It returns structured Citation objects
with the source URI, exact text snippet, byte span, relevance scores (BM25, dense, fused),
and document metadata extracted from frontmatter. Hybrid search (BM25 + binary-quantized
dense) runs entirely in-process — no daemon or GPU needed.
CLI crib sheet
localdb init
localdb store add notes
localdb source add ~/notes --store notes
localdb source add https://example.com/doc --store notes
localdb index --store notes
localdb search "reciprocal rank fusion" --store notes --json
localdb search "your query" --store notes --json \
| jq -r '.citations[] | "\(.uri)\n \(.snippet)"'
Reading citations
localdb search --json returns an object with a citations array. Each citation:
| Field | Type | Meaning |
|---|
uri | string | file:// URI of the source document |
snippet | string | Extracted text passage matching the query |
span | {start, end} | Byte offsets of the snippet within the document |
score.fused | float | Reciprocal-rank-fusion score (higher = more relevant) |
score.bm25 | float | BM25 component |
score.dense | float | Dense vector component — normalized Hamming similarity (1 − dist/bits) from the binary-quantized local ONNX embedder |
document_id | string | Blake3 content hash — pass to get_document MCP tool |
heading_path | array | Markdown heading breadcrumbs (may be empty) |
metadata | object | Dublin Core document metadata extracted from frontmatter: title, creator, date, description, etc. Fields are null when not present. |
MCP tool shapes
When localdb is registered as an MCP server (localdb mcp, or over HTTP at /mcp
on a running localdb serve daemon), four tools are available:
search(query: string, stores?: string[], limit?: int, content_length?: int)
→ citations array (same shape as CLI --json)
get_document(id: string)
→ { document_id, uri, text, title, chunk_count, provenance, store, metadata }
Note: uri-based lookup is NOT supported in v1; use document_id from a search result.
get_chunks(document_id: string, offset?: int, limit?: int)
→ { document_id, uri, title, store, total_chunks, offset, limit, returned, chunks }
Paginated; an out-of-range offset returns an empty chunks array, not an error.
list_stores()
→ { stores: [{ id, name, visibility, document_count, chunk_count }] }
Tool results are returned as a text content item whose text field contains
pretty-printed JSON. If localdb serve is already running, localdb mcp proxies to
its /mcp route automatically rather than conflicting with it.
Config snippet
Minimal config with custom data directory (version: 1 is required):
version: 1
paths:
data: /path/to/your/localdb-data
Pass it to any command with --config /path/to/config.yaml.
Troubleshooting
| Symptom | Cause | Fix |
|---|
error: store not found: handbook on localdb index | Store was declared in YAML config — YAML-declared stores cannot be indexed | Use localdb store add handbook to create a runtime store, then localdb source add |
Database already open. Cannot acquire lock. | Another embedded-mode process opened the DB while the daemon also holds it | Prefer letting the daemon serve reads/MCP (localdb mcp proxies to it automatically); stop the daemon only if you need direct embedded access |
error: daemon is unreachable (exit 5) | Stale daemon.sock left after daemon crash or SIGKILL | rm <data_dir>/daemon.sock |
| Empty search results | Store has not been indexed yet | Run localdb index --store <name> |
error: invalid request: store 'X' already exists (exit 2) | store add called for a store that already exists | Use the existing store; list stores with localdb store list |
source add on a non-existent path succeeds | Path existence is not validated at add time | The error will surface at index time |