Mnemosyne
Local-first semantic history for source code: symbols and structural changes via Tree-sitter, not line diffs — queryable by AI agents over MCP.
Git only remembers what you commit. Between commits work gets lost, and line diffs cannot say which function changed or how. I wanted a local history that understands code structure — and that AI tools can query.
The local-history tool I wanted as a daily driver. A daemon watches saves, a TUI and CLI search and restore, and nothing leaves the machine. Still the project that taught me what it takes for a Rust tool to stay running all day, every day.
- 01Tracks symbols and structural changes instead of line-based diffs
- 02Daemon, CLI and TUI over a content-addressed storage workspace
- 03Exposed to AI tools through MCP
- 01
Identity from the code, not from the name
A line diff sees a renamed function as one deletion and one insertion, so its history stops at the rename.
Engineering choiceTree-sitter parses each save, and every function, struct or class gets a structural hash of its body. Same name with a new hash is an edit; a new name with the same hash is a rename, so the history follows the function. The price: a rename and an edit in the same save look like a delete and an add, and only languages with a bundled grammar, fourteen today, get symbol history. Other files are still saved and restorable as plain content. - 02
Store each chunk once, rebuild files on demand
A local history saves far more often than anyone commits. A full snapshot of every save would fill the disk with copies of the same code.
Engineering choiceEach save is split into chunks along the code structure, and each chunk is stored once under its BLAKE3 hash, compressed with zstd. redb keeps the index of snapshots and symbols in one file, with no server. An old version is reassembled from its chunks when you ask for it. The cost is on the way out: reading an old file does more work than opening a snapshot, and because chunks are shared, deleting history needs a garbage collector, not a file delete. If history ever had to be shared across machines, I would keep the content-addressed objects, which travel as they are, and redesign the single-file index. - 03
Never lose a save, never slow one down
File watchers miss events, and editors and formatters can write the same file several times in a second.
Engineering choiceSaves are debounced per file, and the delay grows from one to ten seconds while a file keeps changing, so a burst becomes one snapshot. A poll every 30 seconds catches what the watcher missed, and a scan every minute finds new files. History can lag a save by a few seconds; in exchange, the daemon stays out of the way while you type.
Shipping a daemon I run every day. Content-addressed storage, a TUI, and the discipline of keeping every byte on-device.

