The problem
My notes live in a markdown vault in git. That part works. What didn’t work was everything around it once agents joined in. An agent’s findings landed wherever that session happened to write them. A comment on a passage meant nothing once the passage was edited. And every new tool wanted to keep its own copy of the truth.
Commenting on markdown is a crowded category, and “markdown with comments” is a worse Notion. The part nobody handled was a review surface where half the collaborators are agents.
What I built
Collab is the system of record for my whole agentic setup. It indexes the vault and serves it to people and agents: documents, tasks, roadmaps, bugs, features, goals, memory, annotations, and a daily note. You can highlight a passage, comment on it, address the thread to an agent, and get a threaded reply that carries the model, the sources it read, and the cost.

It ships as one TypeScript bundle in three shells — an Android app, a macOS app and the web — talking to one SvelteKit server on Tower, my home server. Agents reach the same server through an MCP endpoint with 223 tools.
How it works
- The vault is a directory of markdown files. Postgres holds the index, annotations, grants and threads — never canonical prose. Git already gives versioning, blame and time travel.
- The operations registry is the entire API. Every client, MCP session and script goes through one route per operation with one envelope shape. Each operation declares whether it reads or writes, what role it needs, and whether agents may call it. Expensive ones are hidden from agents, which could otherwise call them in a loop at a cost per turn.
- Writers to the vault are narrow on purpose. Daily notes are owned by a template engine; everyone else appends through embeds.
- Annotations anchor to text, not line numbers. A document keeps its identity through a
git mv, and anchors resolve against a normalised view, so whitespace churn doesn’t break them.
Decisions worth noting
Never silently re-anchor. An annotation either resolves to the right text or reports itself shifted or orphaned. A confidently wrong anchor is a defect; a missing one is a state. I measured this before building anything on top: 2,000 randomised edit scripts produced zero confident mis-attributions, and roughly 2,900 resolutions replayed through real git history produced zero more. Survival ranged from 84% on an append-mostly backlog to 30% on a file rewritten across 31 commits — and in that file, orphaning was the correct answer.
No live co-editing in v1. An agent proposes a diff and a person accepts or rejects it. That’s smaller and auditable, and you never want an agent quietly rewriting prose.
Document text is data, never instructions. An instruction found inside a document is surfaced, not obeyed. A hostile fixture document runs in CI to keep it that way.
Honest about offline. On the phone, Collab is offline-tolerant, not local-first. Reads come from a bounded cache; voice notes queue and retry; typed captures fail with a visible error. I wrote that asymmetry down as a finding instead of calling the app local-first.
Where it fits
Rule one of the whole system is that the vault owns the data — Collab indexes it, and nothing else becomes a second store of truth. Loop reads goals and starred roadmaps from Collab and writes status back. Collab’s own events go out to Headlines. Surface reads host vitals that the vault records. Loop and Mac the Reaper each appear inside Collab as plugins, but both run standalone first; the plugin mirrors them.

Outcome
Every agent in my setup is told to search Collab before answering from memory, and to write plans, decisions and bugs into it rather than into loose files. It has taken about 1,300 commits since August 2026. The anchoring model came out of that first measurement intact and everything else is built on it.
It also taught me where health checks lie. A process can answer “I’m up” while its database is hung. Collab now has a second health route that does a real read under a three-second deadline and returns 503 when it can’t. After one outage where the alert fired on every run and never reached me, “Collab unreachable” now posts straight to Discord as well.