keiken · research

2026-07-04 · essay

Local-first is a constraint, not a feature: the Verdant decisions

Verdant is a desktop workspace that turns conversations with local language models into structured, navigable knowledge — extracted entities, a knowledge graph, a persistent memory bank, all in a single SQLite file on your machine. This essay is about the decisions, not the features, because the features follow from the decisions.

1. Local-first as a hard constraint

The most consequential decision was refusing a cloud path entirely. Not "offline mode," not "sync later" — no network egress, period.

Constraints are more productive than features because they make whole categories of decisions for you. Once no data leaves the machine, the architecture picks itself: Tauri over Electron (a Rust core that can do real work, not just shell a browser), SQLite over anything served, Ollama and self-hosted endpoints as the only providers. Every downstream question — where do embeddings live, what happens to transcripts, who can read the memory bank — answers itself.

The cost is real: no cross-device sync, no collaboration. I took the trade knowingly. The users Verdant serves — people working with material they cannot upload — don't have the option of taking the other side of it.

2. Structured memory over raw transcripts

Chat clients store transcripts. Transcripts are write-only memory: you can re-read them, but nothing about a 4,000-line scrollback is navigable.

Verdant treats the conversation as raw material. Sessions are parsed, key entities and concepts extracted, and the results stored as typed memories — facts, instructions, project scopes — that are individually editable and deletable. The extraction is a starting point, not an oracle: the human curates what the machine proposes.

This is the difference between a log and a knowledge base, and it's the entire reason the app exists.

3. The graph is navigation, not decoration

Most tools that ship a "knowledge graph" ship a screenshot generator — a pretty force-directed blob you look at once. The decision in Verdant was to make the graph a primary navigation surface: nodes are clickable, typed, and categorized, and a live extraction panel sits inside the chat window itself, so structure accumulates while you work rather than in a batch job you never run.

The test I used: if the graph view disappeared, would the app lose a core workflow or a marketing asset? It has to be the former.

4. Export as the escape hatch

Structured memory creates a lock-in risk: the more the app understands your data, the more it holds hostage. So everything — sessions, memories, graph state — exports to Markdown and JSON. The SQLite file is documented, local, and yours.

Local-first without exit rights is just a smaller cloud.

5. Boring storage, fast core

SQLite via Rusqlite, Tokio for the async core, multi-threaded Rust command handlers between frontend and storage. Nothing exotic. The frontend (React, Zustand, React Flow) stays a thin projection of state the Rust side owns.

The lesson generalizes: when the product idea is unusual — conversations as knowledge infrastructure — the substrate should be maximally boring. Novelty budgets are real, and I spent mine on the extraction and memory model, not on the database.


Verdant is open source at github.com/keiken-shin/verdant.

← writing · index