Every project I’ve written about this year produced the same kind of leftover: decisions. Why Tsundoku identifies series the way it does. Why Codex plugins talk over stdio. Why the third attempt at a library server used SQLite. Each took an evening of thinking, and each lived in exactly one place: whatever chat window I had open at the time.
That’s the problem Mnemo solves. The line at the top of its PRD is: context is the most valuable thing you produce, and it currently lives nowhere. It’s spread across chat projects that don’t talk to each other, markdown files I forget I wrote, and notes apps that no agent can reach.
Mnemo is a self-hosted memory and knowledge layer: one place for decisions, notes, snippets, links and files, that any tool I use can read from and write to, including the agents I work with every day.

The Mnemo feed, filterable by kind, tag, source and date. Screenshots use a fictional demo workspace.
What goes in it
Everything is an entry, and each entry has a kind: a note, a decision (context, decision, why, consequences), a memory (a durable fact), a code snippet, or a link. Entries have tags, can be linked to each other, and keep their history, so editing a decision doesn’t erase what it used to say. Files sit alongside them, and their text is extracted so it’s searchable.

A decision entry. The structure is a convention, written in markdown.
Saving has to be fast. If it takes more than a few seconds, I won’t do it, and an empty memory is worth nothing.
Built for agents first
The interface I use most isn’t the web UI, it’s MCP. Mnemo is an MCP server with tools to search, read, create, update and link entries, and to upload and fetch files.
It’s mainly used remotely, over HTTP with OAuth, so any MCP client that supports remote connectors can use it: Claude.ai, ChatGPT, Claude Code and others. Claude can check “have I already decided how auth works in my Rust projects?” before proposing something, or save a decision at the end of a design discussion. A small Claude Code plugin adds a few capture commands for the terminal.
OAuth wasn’t in the original plan. I started with simple API keys, which are great for scripts but not accepted by the chat apps I most wanted to connect. So Mnemo became its own OAuth server, with a consent screen and a page to see and revoke connected apps. It took a day, which says more about how well-specified OAuth is these days than about me.
Search
Search combines two approaches: classic full-text search (built into SQLite), and optional semantic search that finds entries by meaning rather than exact words. The two result lists are merged, and each result shows which one found it.

Search results, each tagged with how it was found.
Semantic search is strictly optional. Embeddings can come from a small model running inside Mnemo, from an external API, or not at all, and everything still works with full-text alone. While a model is still downloading, search just serves full-text results.
Links that fill themselves in
The latest feature is small but changed how I use it: paste a bare URL, and Mnemo fetches the page in the background and fills in a title and summary. It only fills empty fields, so it never overwrites anything I typed, and it deliberately keeps things simple: no headless browser, just the page’s own metadata.

A link saved as a bare URL, after Mnemo filled in the details.
The shape of it
It’s the same shape as my other Rust projects: a single binary with the React web UI embedded, one SQLite file for everything (so backup is copying a file), and a CLI for adding, searching, exporting and importing.
It runs in single-user mode with API keys, or multi-user mode with login through an identity provider, each user’s data kept separate.

The admin view: users, encryption status and the semantic search backend.
There’s also optional encryption at rest, for the database and the files. Mnemo refuses to start if the encryption keys look wrong in any way. A memory store is exactly the kind of thing that should fail loudly rather than guess.
A few things that fought back
Not every dependency fits a tiny container. All my Rust projects ship as small static binaries. Mnemo couldn’t, because the local embedding model needed a more standard system library, and then a newer version of it than my base image had. A good reminder that adding “just one more feature” can change how a project is packaged.
Screenshots need a fake life. I wanted screenshots that look like real use without exposing my real notes, so Mnemo has a screenshot setup with a fictional startup, complete with its own decisions, postmortems and onboarding docs. Every screenshot in this post comes from it.
Where it’s at
The most useful thing about it isn’t a feature. It’s that the agents I work with now have somewhere to put things that outlives the conversation. The best capture flow turned out to be the laziest one: finish a design discussion with Claude, say “save that as a decision”, and move on.
The repository isn’t public yet. When it is, I’ll add a link here.
