Short answer
Point Claude Code at a folder and you have a second brain for one person. For a team you need three more things: the notes reachable from every machine, concurrent writes that do not duplicate text, and per-folder permissions the agent inherits. Baalda supplies those over one MCP endpoint.
Nearly every guide to building a second brain with Claude Code is written for one person, and nearly every one of them is correct. The vault is a folder of markdown on your disk, Claude Code already has file tools pointed at that disk, and there is no integration to install. That setup is covered properly in Claude Code's second brain is a folder, not an integration, and this post does not restage it. What those guides do not cover is the second person.
Why does the solo setup need no setup at all?
Because there is no gap to bridge. Claude Code reads and edits files in the directory you launched it in, and --add-dir widens the session to a vault folder somewhere else. The agent greps across the notes, opens one, rewrites a section. No server, no token, nothing to keep awake.
It stops working for a team not because it is a bad setup but because the three things it quietly relies on are all single-user assumptions:
- The files are on this disk.
- Nobody else is writing them right now.
- Everything under the path is yours to read.
A second person invalidates all three at once.
What actually breaks when a second person needs the same notes?
The notes are on one laptop. Your teammate's Claude Code cannot open a path on your machine. The usual patches each fail in their own way. A consumer file-sync service resolves two simultaneous edits to one file by keeping both and renaming one, which turns an agent's write into a second copy of the note nobody reads. Git needs a human to resolve a conflict, and an agent that commits on every change generates them faster than anyone will merge them.
Two agents write the same note at the same time. This is the failure nobody writing a solo guide has to think about, and it is worse than a lost edit. More on it below, because it is the heart of the problem.
The permission boundary is a directory. --add-dir draws one line, at a path, and Claude Code's docs are explicit that additional directories follow the same permission rules as the original working directory, which means readable without prompts. A team vault has folders that are not everyone's to read, and a directory boundary has no way to express that.
Baalda is a team second brain built on plain markdown files on your own disk. Several people edit the same note in real time over a CRDT, permissions are set per folder and per note, and it is open source under Apache-2.0 and self-hostable. It exposes the vault over MCP so an assistant works with the same files a person does, limited by the same permissions. It is free to run locally, with an optional managed Team plan for hosted sync. If the category is new, what a team second brain is covers the idea before the plumbing. The rest of this post is about the two problems above that a shared folder cannot solve on its own.
What happens when two Claude Code sessions edit the same note?
The intuitive worry is that one write overwrites the other. The real failure is stranger: the note ends up holding the text twice.
The mechanism is specific. A server that writes into a note has to read the note's stored state, apply the change, and append the result. If it awaits anywhere between the read and the append, two writes arriving close together both hydrate the same starting state, and both apply a whole-body delete and insert. A CRDT does what a CRDT is supposed to do and merges both inserts rather than discarding either, so neither write is lost and the document now contains both copies.
Baalda's write path carries a per-note lock for exactly this, and the comment on it in apps/server/src/sync/doc-batch.ts names the outcome it exists to prevent: two concurrent writes "each hydrate the SAME state and each apply a whole-body delete+insert", Yjs merges both inserts "and the note holds the text twice". Chaining writes per note id makes the second one see the first one's result.
The same comment makes the second point, and it is the one that matters more. Serialising writes per note is, in its words, "also what makes a precondition ... mean anything at all: check and apply are one atomic step only because of this." Without the lock, a check that the note has not changed is a check against a state the write is no longer applying to.
That precondition is the part an agent actually uses. read_note returns the note's content and a revision, which is a sha256 of the note's current text. Pass it back as expectedRevision on update_note, append_note or edit_note and a write against a note that someone changed in between is refused rather than merged over the top:
{
"name": "edit_note",
"arguments": {
"docId": "...",
"expectedRevision": "9f2b8c1e...",
"edits": [{ "replace": "Owner: unassigned", "with": "Owner: Priya" }]
}
}A content hash rather than a version counter is a deliberate choice, and the code says why: a CRDT has no single version number, so the hash of the text is the honest equivalent. It also means the check is about what the note says, not about how many times it has been touched.
Two smaller guards sit alongside it. edit_note works from anchors, and an anchor that matches zero times or more than once refuses the whole call with nothing written, so an agent cannot half-apply a batch of edits against a note that moved underneath it. append_note takes an idempotencyKey, so an unattended run that reconnects and retries gets the first result back instead of appending the same block a second time.
And where the write lands is the same place a keystroke lands. If a teammate has the note open, the MCP write mutates the live document and broadcasts to every connected editor, so they watch the text appear. If nobody has it open, the change is persisted and the next person to open the note loads it.
How do you stop the agent reading folders it should not?
A Baalda MCP token authenticates as one user inside one vault, and every call it makes is re-checked against the same per-folder and per-note permissions that govern that person. list_notes returns only the notes you can access, with your permission on each one, so an agent carrying your token sees the vault you see and not the vault your admin sees.
Setting that up is manage_access, which replaces access on selected folders or files, or on the whole vault, in three modes: open (Can edit), readonly (Can view) and private (No access). The audience is either everyone in the org or a named list of users, up to 1000 resources in one call, and it is owner or admin only.
This is the thing --add-dir has no equivalent for, and it is also where Obsidian Sync stops. Obsidian's own help page for collaborating on a vault says that "All collaborators receive the same permissions as the vault owner, with one exception: only the vault owner can invite collaborators", that "Fine-grained permissions are not supported yet", and that "All collaborators must have an active Sync subscription to access a shared vault". That is their published limitation rather than our characterisation of it, and why per-file permissions need a server goes through what it takes to add them.
The practical consequence for a team is small and easy to get wrong: each person mints their own token, in Vault settings under MCP. A token shared around the team gives every agent using it the reach of whoever created it, which undoes the whole arrangement.
What does each person actually have to set up?
One command each, pointed at the vault's endpoint with their own token:
claude mcp add --transport http --scope user baalda \
https://api.baalda.com/api/mcp \
--header "Authorization: Bearer mcp_..."Scope matters here. Claude Code's local scope, the default, writes to ~/.claude.json keyed by project path, so the server is only active in the project you ran the command from. A vault is relevant everywhere, which makes --scope user the usual choice. --scope project writes a .mcp.json in the repo root that everyone who clones it picks up, which is the one case where you must not paste a token: Claude Code expands ${VAR} and ${VAR:-default} inside url and headers, so write Bearer ${BAALDA_MCP_TOKEN} and have each person export their own. Note that Claude Code deliberately reads a short list of known credential variable names as empty in a remote server's url and headers, so confirm yours expands rather than assuming it does.
Self-hosting changes only the URL, to your own server plus /api/mcp.
Where is this the wrong answer?
If you are one person, it is overhead. The folder on your disk is the correct setup and nothing in this post applies to you.
If your team's written work already lives in Notion or Linear, use their hosted MCP servers. They authenticate over OAuth, there is nothing for you to run, and they are up whether or not your laptop is. Baalda needs a process running somewhere, which is your own machine for a local vault and a hosted or self-hosted instance for anything else, and a laptop that sleeps is not a server. The honest version of that trade is in Baalda compared with Obsidian.
And the guarantees above are about the text of a note, not about judgement. A lock and a revision check stop two agents producing a garbled file. They do not stop two people pointing their agents at the same document with opposite intentions and getting a coherent note that is wrong. That part is still a conversation.
