Bun, SQLite, local GGUF models via node-llama-cpp, and one retrieval core shared by CLI, Web UI, SDK, REST, and MCP.
GNO is a TypeScript CLI package executed by Bun, with a SQLite-backed index, local model inference via node-llama-cpp, and a shared retrieval core that every surface (CLI, Web UI, SDK, REST API, MCP) plugs into.
~/.config/gno/ — config files (index.yml, presets)~/.local/share/gno/ — SQLite database, model cache, asset cache~/.cache/gno/ — temporary artifacts, rerank scratchpadEvery GNO surface speaks to the same shared retrieval core:
src/cli/*, exposed as the gno executable by the installed Bun packagegno serve launches a Bun HTTP server with the browser workspace and the REST APIgno serve, 35+ endpointsask sends the selected evidence to the generation model with a citation-preserving prompt, and --verify adds a claim-classification pass against the closed Capsule.Three hashes exist for every piece of evidence, and the distinction runs through the whole system:
Keeping them separate is what lets verification say “the file changed but your cited paragraph did not”. Document IDs are derived from the source hash, so identity is content-addressed rather than path-addressed.
gno serve and gno daemon are two front ends for one resident runtime: a single exclusive owner per data directory, holding the store, the watcher, the job queue, the model lifecycle, and a Streamable HTTP MCP gateway at 127.0.0.1:3000/mcp.
Because it is one runtime, several MCP clients share one warm store and one set of loaded models while keeping isolated sessions, cancellation, and configuration snapshots. The second agent to connect does not pay the first agent’s model load. Exclusivity is enforced: a second process against the same data directory is rejected rather than racing.
Shutdown is ordered rather than abrupt. New work is rejected, admitted requests are cancelled and awaited, background embedding and model downloads drain, MCP sessions close, then models, SQLite, and the ownership lock are disposed.
Three checks sit between a request and an effect, and they are independent by construction:
any default or opt-in local). Distinct from egress. Local mode is evidence-qualified for tested macOS File Provider layouts only (Google Drive, iCloud Drive, and OneDrive only for the tested configuration and both validated immediate SharePoint library roots), uses hierarchical directory classification plus a guarded content recheck, and fails closed outside proven support.The core defines ports — converter, store, embedding, rerank, generation — and adapters implement them. That is why an OpenAI-compatible HTTP endpoint can substitute for a local GGUF per model role without the retrieval core knowing, and why a per-collection embedding override is a configuration change rather than a code path.
┌─────────────────────────────────────────────────┐
│ CLI / MCP / Web UI / REST / SDK / Desktop │
├─────────────────────────────────────────────────┤
│ Ports: Converter, Store, Embedding, Rerank, Gen │
├─────────────────────────────────────────────────┤
│ Adapters: SQLite, FTS5, sqlite-vec, llama.cpp, │
│ OpenAI-compatible HTTP │
├─────────────────────────────────────────────────┤
│ Core: Identity, Mirrors, Chunking, Retrieval, │
│ Capsules, Journal, Egress │
└─────────────────────────────────────────────────┘