Open-Sourcing the Brain: the Brain-Vault Model
In part 3 I described the code-navigation side of this thing: a Rust indexer that walks a repo, builds a symbol database, and lets an agent query the structure of the code for roughly the cost of a single grep instead of reading whole files. That, plus the memory engine from part 2, was the private tool I had been running on my homelab for a couple of months. It worked. I used it every day.
But it had a limitation built into its foundation, and that limitation is the reason this post exists.
The problem: it only worked for me
The private version, the one still called obsidian-mcp at the time, was shaped entirely around my setup. It read my personal Obsidian vault, the one I keep synced across my machines and treat as the source of truth for everything I do. Its conventions, its paths, the way it discovered and indexed notes, all of it assumed my environment, my layout, my habits. Day to day that was invisible. It was a genuinely good tool, and it kept getting better the more I leaned on it.
The trouble was that it was good for me in a way that made it impossible to hand to anyone else. You could not just point it at your own notes and have it work. It expected my vault, mounted the way I mount it, synced the way I sync it. It read from a space tuned to exactly one person, and that person was me. As a personal tool that was completely fine. As something to open-source it was a dead end, because the first thing any other user would hit is that the whole design quietly assumed they were me.
So the question that drove the redesign was not how to fix a bug. It was simpler and more demanding: what would it take for someone who is not me to run this over their own notes, safely, without inheriting my setup? Answering that honestly meant separating two things the private version had tangled together, the notes I read and the data the tool writes.
The redesign: the brain-vault model
The fix that made cortexmd shareable is almost embarrassingly simple once you have been burned. cortexmd owns its own separate brain vault, and that brain vault is the only thing it is ever allowed to write to. Memories, the journal, agent diaries, tasks, the knowledge-graph notes, the list of indexed code repos: all of it lives in the brain vault, and cortexmd is the sole writer.
Your own vaults, the ones you edit by hand in Obsidian, are attached as read-only source vaults. cortexmd indexes them for search and code-navigation, and it never modifies them. Not a heat update, not a tag, not a single byte. Attaching a source vault is opt-in, with a default-deny allowlist, so you can keep private subtrees out of the index entirely and only expose the parts you want the agent to see.
Data flows one way. Source vaults in, brain vault out, and the two never overlap. You attach whatever vault is yours, the tool reads it and writes nothing back to it, and the brain it builds lives somewhere else entirely. That is what makes it general: there is no longer any assumption that the vault is mine, or mounted my way, or synced my way. It is also what makes it safe, because a tool that never writes to your notes cannot clobber them, and there is no shared file for a sync agent to fork. The coupling that kept the private version stuck to my machine is simply gone.
SOURCE_VAULTS[] (read-only, opt-in, allowlisted)
┌───────────┐ ┌───────────┐ ┌───────────┐
│ notes/ │ │ code/ │ │ docs/ │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ index (one-way, read) │
└──────────────┼──────────────┘
▼
┌──────────────────┐
│ cortexmd │ <- sole writer
│ (MCP server) │
└────────┬─────────┘
│ writes
▼
┌──────────────────┐
│ BRAIN_VAULT │ memories · journal · diaries
│ (own dir, not │ tasks · KG notes · code-repos.json
│ your vault) │
└──────────────────┘
The default brain vault is a dedicated data directory, something like ~/.local/share/cortexmd/brain, never your real Obsidian vault. You can point it somewhere else, but the default keeps the tool’s writes and your notes in two clearly separate places from the first run.
Two ways to run it
Once the write story was sound, the deployment story needed to match. cortexmd ships with two modes, and they are co-equal rather than a real one and a toy one.
The recommended default for a single person is local-stdio. It runs on your own machine, talks MCP over stdio to whatever client you use, and reads your vaults straight from disk. No sync. No Docker. No auth. No network at all. For one person on one machine this is everything you need, and it is the mode I would steer almost anyone to first. The whole point of the redesign was that a single user should be able to get the full brain with none of the operational weight the private version had wrapped around itself.
The second mode is self-hosted HTTP, and it is explicitly the advanced path. Here cortexmd runs as an Express server with proper auth (API key or OAuth2), and source vaults are pulled in read-only over a transport. That transport is an interface I called the IVault seam, with implementations for local disk, git-pull, WebDAV, and S3. This is the mode for multi-client or genuinely remote setups, where several MCP clients share one brain or the source data lives somewhere other than the server’s own disk. It is more moving parts, and you only reach for it when you actually need it.
The important thing is that both modes share the same read-only-source, sole-writer-brain model. The HTTP mode keeps the same guarantee, your sources stay read-only and the brain is the only write target. It just changes how the read-only sources reach the indexer.
A polyglot monorepo held together by a contract
The other thing open-sourcing forced me to clean up was the seam between the two languages this project is made of, because it really is two projects wearing one coat.
packages/server is the TypeScript MCP server: Node 22, Express, the memory engine, the recall logic, the tool definitions that show up to clients under the mcp__cortexmd__ namespace. crates/cli is a single Rust binary, cortexmd-cli, that is the tree-sitter indexer plus the CLI client, the session hooks, and the status-line HUD. Two toolchains, glued together by CI.
The hard part of a split like this is the place where they have to agree exactly. The symbol IDs that the Rust indexer produces have to be byte-identical to the ones the TypeScript side expects, or the whole code-navigation layer quietly points at nothing. So there is a contract/ directory that holds the shared wire format, the symbol-ID specification, and a set of golden fixtures. A CI parity check runs the same inputs through both sides and fails the build if the Rust producer and the TypeScript consumer ever disagree about what an ID should be. The contract is the referee, and it keeps both languages honest without either one having to trust the other.
The rename, and what it is now
When I pulled all of this together to share it, the old name no longer fit. obsidian-mcp described what it started as: a bridge to one app’s vault. What it had become was a memory and code-navigation brain that happened to use Obsidian-style markdown as one storage format among others. So it became cortexmd, and that is the name it ships under.
A note on honesty: this is pre-alpha. It is public and MIT licensed at github.com/Leicas/cortexmd, and the config names and some of the APIs are still in flux. I built it for myself first, ran it on my own homelab over my own private vault of personal and work notes, realised it was wired too tightly to my own setup to share, generalised it, and then cleaned it up enough to put it where other people can use it. It is not a finished product and I am not pretending it is one.
What I do feel good about is the shape of it. Your notes stay yours, on your disk, read-only, with the private parts excluded by default. The brain the agent builds lives in its own place and never reaches back into your files. In the default mode nothing leaves your machine: no cloud, no account, no network. That is the local-first, own-your-data version of the idea I actually wanted all along, and it took pulling it loose from my own setup to get there.
If any of this is useful to you, the project page has the overview and the links: cortexmd. And if you want to read it from the start, part 1 is where the series begins.
Series
This is part 4 of a four-part series on cortexmd.
- Part 1: Giving an AI Agent a Second Brain
- Part 2: The Memory Engine: Heat, Decay, and Dreams
- Part 3: The Token Killer: Navigating Code Without Reading It
- Part 4: Open-Sourcing the Brain: the Brain-Vault Model (you are here)