An all-Rust engine that indexes a plain-markdown vault into SQLite and serves it three ways: an MCP server for Claude, a CLI, and a native desktop app for humans. Open source, shipped, signed and notarized. It is indexing this site’s repository right now.
The studio runs on a markdown vault: hundreds of notes, specs, plans, and memory files linked with [[wikilinks]] and YAML frontmatter. When an agent needs to find something in it, the only tools it has are find and grep. Both return noise, and both burn context on a repository whose structure the model can’t see.
Obsidian solves the human side with a graph and backlinks, but that is built for a person clicking, and it is a third-party app with no machine API. I wanted one engine serving both audiences: a query API for agents, and a native reader and editor for me, over the exact same plain-markdown files.
Lattice is a single Rust core crate with no I/O of its own. It walks a vault, parses every markdown file, and builds a graph: each file is a node (a README is an index, everything else a note), and three kinds of edge connect them. Wikilinks, frontmatter references, and the contains tree from a directory’s README down to the files beneath it.
The graph lives in SQLite with an FTS5 full-text index, but that database is only a derived cache. The .md files are the source of truth. Delete the index and Lattice rebuilds it from disk.
Agents don’t browse a vault, they query it. Lattice exposes the same core engine as an MCP server (over stdio, drops straight into Claude Code) and a matching CLI, both returning one JSON shape. An agent asks for backlinks, outbound links, a frontmatter filter, full-text search, orphans, or broken links, and gets structure back instead of a wall of grep output.
The headline tool is vault_context_bundle: give it a note and a token budget, and it returns that note plus its most relevant neighbors, deduped and ranked, packed to fit. Budgets are soft, and a manifest lists exactly what was included and what was dropped. No silent truncation.
Humans read and edit the same vault through Lattice’s own native window: a Rust backend (the core crate, exposed as Tauri commands) with a SvelteKit webview. No Electron, no bundled runtime, one binary.
It browses notes with backlinks and outbound-link panels, turns the graph queries (orphans, broken links, frontmatter filters, search) into first-class views, and edits markdown in a CodeMirror editor that writes straight back to the .md file. Markdown is rendered once, by the Rust comrak path, so the app and the agents see the same content.
A tool whose whole value is freshness can never serve a silently-stale answer, and a tool that writes to your notes can never corrupt them. Two decisions carry that weight.
The first index design rebuilt on every call (about 9 seconds) or watched the filesystem with notify. The watcher proved unreliable inside a piped MCP server: the spawned thread never received filesystem events, and a silently-stale index is the worst possible failure. Lattice holds the index in memory and does a cheap incremental re-sync on each call instead: walk, compare mtimes, reparse only what changed. Six calls plus startup dropped from about 9 seconds to about 1.3, and the answer is always current.
The second: the frontmatter patcher refuses to touch what it can’t safely round-trip. Hand it a block-style YAML list or CRLF it can’t parse cleanly, and it returns the file unchanged with a warning rather than risk corrupting it.
Lattice is a public repository, not a private experiment. GitHub Actions runs cargo test, cargo clippy, cargo fmt, and the Svelte build on every push, and the green checks are part of the point.
v0.2.0 ships as a real macOS app: Developer ID signed, Apple-notarized, and stapled, so it opens with a clean double-click and no quarantine warning. And it earns its keep by dogfooding. The vault it indexes is this studio, the same repository that holds the page you are reading.
The harness operates the studio; Lattice is how it remembers and navigates. One is the hands, the other is the memory. Both are tools I built because the ones I needed didn’t exist yet.