IndexSIG-00

WRK-01Record

Cairn: local-first cited search and grounded Q&A over a Markdown vault

TypeScript engine + Electron alpha that indexes Markdown into SQLite, runs hybrid search, and answers only from your notes with citations.

Status
Alpha: engine CLI and desktop shell work; multi-format ingestion and PDF annotation are planned, not built
Updated
Stack
TypeScriptNode.jsbetter-sqlite3sqlite-vecSQLite FTS5OllamaElectronReactCodeMirror 6

What it is

Cairn is a knowledge-management tool that runs entirely on your machine. The repository holds two npm workspaces: @cairn/engine, a headless indexing and retrieval library with a cairn CLI (index / search / ask), and @cairn/desktop, an Electron + React shell around it with a file tree, a CodeMirror Markdown editor, search, Ask, and a gated agent edit flow. It also carries the planning corpus: two PRDs, two spike-backed feasibility reports, and ten ADRs that override the PRDs where they disagree.

How it works

indexer.ts walks a folder for .md files, splits each with a recursive character splitter (~512 tokens, 15% overlap), and records the nearest heading and 1-based start line per chunk so results can cite file:line › heading. Chunks are stored under <vault>/.cairn/index.db via better-sqlite3 with an FTS5 table and, when an embedder is available, a sqlite-vec table plus a content-hash embedding cache. retrieve.ts runs a dense KNN arm and a keyword arm and fuses them with reciprocal rank fusion; in auto mode it falls back to keyword-only if no vectors or no Ollama. ask.ts passes only the top hits to a local chat model under a strict grounding prompt and returns “Your notes don’t cover this.” when the pool’s best cosine falls under a coverage threshold. agent-run.ts lets a model call read_note and propose_edit, but the engine holds no filesystem handle — proposals become diffs the desktop’s main process approves per hunk, with git checkpoints for revert.

Notable decisions

  • sqlite-vec is a brute-force scan, not ANN; accepted as adequate at v1 scale.
  • Embeddings never go to the cloud. cloud-provider.ts supports OpenAI-compatible, Anthropic, Azure, and Bedrock chat as BYOK escalation, and its embed() throws by design.
  • The engine test suite uses a fake ModelProvider and in-memory index, so it runs without Ollama.
  • Dependencies are limited to MIT/Apache/BSD/MPL; AGPL/GPL is a hard blocker.

Current state

The engine gate suite and desktop tests exist and are wired into npm test. The desktop alpha covers the MVP scope (choose vault, index, cited search, optional Ask). Docling-based multi-format ingestion (ADR-0009), PDF annotation, and the full agent-mode set remain design documents.