Agent-readable docs index: /llms.txt. Full docs in one file: /llms-full.txt. Download /docs.zip to grep all markdown files locally.

Spaces & Permissions

Every note lives in exactly one space, and the space determines who can see it. There are no per-note permissions — visibility is a property of where a note sits.

The master layout

master/ Company/ # visible to everyone Home.md # entry point / priority dashboard Memory.md # business overview, positioning, team structure Decisions/ # decision log with reasoning Playbook/ # SOPs, standards, workflows Templates/ # reusable formats Intel/ # knowledge distilled from outside sources, mapped in Intel/Home.md Destinations/ Providers/ Events/ Trends/ Teams/<team>/ # visible to members of that team People/<person>/ # visible to that person only Memory.md Notes/ Actions/ Sessions/ Inbox/ # Inbox: transcripts land here Clients/<client>/ # admin-only by default; grant per client _meta/ # server-only — never compiled into any personal vault org.yaml # people, roles, teams spaces.yaml # space path → read/write rules promotions/ # pending/ approved/ rejected/ clients/created.log # audit trail of self-service-created client spaces shares/ # pending/ approved/ rejected/ revoked/
The Clients/ name is configurable per vault (brain init --entities, or brain rename-entities later); these docs use the default. Permissions never depend on the name — spaces.yaml is the only authority on who reads what. The shared space's name is configurable the same way: Company/ is the default, set with brain init --shared and fixed for the life of the vault. These docs use the defaults throughout.
Every Memory.md — company and personal — follows the same convention: a lean overview that links out, never a running log. Company detail lives in atomic notes under Decisions/, Playbook/, and Intel/; when a personal topic outgrows a few lines in People/<person>/Memory.md, the detail moves to People/<person>/Notes/<Topic>.md with a one-line link left under the heading.
Company/Intel/ holds knowledge distilled from outside the company — articles, posts, PDFs, screenshots — one flat page per subject, each claim cited with its source and date: [source](URL), as of YYYY-MM, where the source is a URL or the publication/title when there's no link, and the date is the source's own or captured YYYY-MM (today's) when it shows none. It's an ordinary part of the Company space: everyone reads it, agents feed it through promotions, and no extra spaces.yaml rule is needed. What someone knows from working with a thing is not Intel — that is first-party knowledge, it cites the episode that established it rather than a URL, and it belongs in whichever space the company names for it. brain init scaffolds Intel/ flat and empty on purpose: a company's own subjects are its own to name. See Getting Things In for the ingest flow.

Who sees what: spaces.yaml

Each space maps to a read and a write list of grants. A grant is one of everyone, role:<name>, team:<name>, or person:<id>. The {name} placeholder binds the wildcard segment, so one Teams/* rule covers every team.
spaces: - {path: Company, read: [everyone], write: ["role:admin"]} - {path: "Teams/*", read: ["team:{name}"], write: ["team:{name}"]} - {path: "People/*", read: ["person:{name}"], write: ["person:{name}"]} - {path: "Clients/*", read: ["role:admin"], write: ["role:admin"]}
Read this as: everyone can read Company, but only admins write it; a team's space is readable and writable by that team; a person's space is theirs alone; and a client is admin-only until you assign it — a new client folder is invisible to advisors until an exact rule grants it.
Exact match beats wildcard. If both Teams/* and a specific Teams/sales rule exist, the exact rule wins for Teams/sales. This lets you carve a single exception without rewriting the general rule.

Protecting clients

Client confidentiality is the common reason to move off the defaults. The Clients/* wildcard is deny-by-default (admins only); grant each client to its advisor and any supporting team with an exact rule, which overrides the wildcard:
- {path: "Clients/*", read: ["role:admin"], write: ["role:admin"]} - {path: "Clients/Vandenberg", read: ["role:admin", "person:marco", "team:concierge"], write: ["role:admin", "person:marco"]} - {path: "Clients/Nakamura", read: ["role:admin", "person:yuki"], write: ["role:admin", "person:yuki"]}
Now Marco sees Vandenberg but not Nakamura; Yuki sees the reverse; an advisor with no rule sees neither. Because the wildcard denies by default, forgetting to add a rule fails closed — a new client is private until you say otherwise, never accidentally company-wide.
The same fail-closed posture applies to a typo: {name} binds the folder name exactly, case-sensitively, so a folder called Teams/Sales next to a team id of sales compiles into nobody's vault rather than the wrong person's. Nothing leaks — but the notes silently reach no one, which is why brain doctor flags any space that resolves to zero readers (unreadable-spaces).
Names leak through prose, not just files. The compiler guarantees a client's file never enters an unauthorized vault — but a client name typed into a shared note (Company/Memory.md: "the Vandenberg expedition proved…") travels to everyone who reads that space. The structure can't redact prose. Keep client names in client spaces; write lessons generically in Company. brain doctor flags every cross-space reference (see below) so these slips don't accumulate silently.
Clients can also arrive by self-service request instead of an admin hand-editing this file — see Self-service client spaces below — and once granted, a client's owner can extend read or write access to a colleague, a team, or everyone (company-wide, read-only) themselves via brain shares / ShareRequests/, without an admin touching spaces.yaml directly (a new grant still needs approval — from the recipient, a team lead, or an admin; a revoke doesn't) — see Sharing a space. Both paths keep the same fail-closed posture as a hand-edited rule: a name collision is refused without ever revealing who owns it, and a request whose frontmatter owner disagrees with the requester's own People/<id>/ path is treated as tampering and rejected outright.

Self-service client spaces

An agent with write access to only its own People/<id>/ space can request a brand-new client without an admin touching spaces.yaml directly. It writes the request into its own space:
People/marco/ClientRequests/Vandenberg.md
--- client-name: Vandenberg owner: marco entity: client source: chat created: 2026-07-22 ---
The folder name (ClientRequests/) and the frontmatter key (client-name:) follow the vault's configured entity noun — see _meta/config.yaml. A vault configured with --entities Vendors --entity vendor uses VendorRequests/ and vendor-name: instead.
The request reaches master with the person's next write-back. Server-side, materialize_clients — run as part of brain cycle, between write-back and the shares/promotions sweep — provisions Clients/Vandenberg/ and appends an owner-bound exact rule to spaces.yaml:
- {path: "Clients/Vandenberg", read: ["role:admin", "person:marco"], write: ["role:admin", "person:marco"]}
The requester's People/<id>/ path segment is the authoritative owner — never a frontmatter field. Three other outcomes are possible:
  • Same owner, existing client. If Marco already owns Clients/Vandenberg, the request merges into the existing note instead of creating a new grant.
  • Name taken by someone else. The request is refused fail-closed — the existing owner is never revealed — and an inbox note (People/marco/Inbox/client-taken-….md) asks Marco to add a distinguishing detail (a first name, company, or city) and try again.
  • Owner mismatch. A request whose frontmatter owner disagrees with its own People/<id>/ path is tampering, not an ordinary collision — it's rejected outright and counted separately (clients_tampering in brain cycle --json), which flips the cycle's ok to false.
Every self-service creation is appended to _meta/clients/created.log and surfaced to the admin as an info finding by brain doctor, so the client roster's growth stays visible even though no admin action created it. An admin can rename, merge, or revoke a self-service-created client the same way as any other — including with brain shares revoke, which doubles as the veto lever for this list.

Sharing a space

Once someone owns a space — most commonly a self-service-created client — they can grant a colleague, a team, or everyone (company-wide, read-only) access to it themselves, without an admin hand-editing spaces.yaml. They write a request into their own space:
People/marco/ShareRequests/share-vandenberg-yuki.md
--- space: Clients/Vandenberg share-with: person:yuki access: read action: share owner: marco created: 2026-07-22 ---
ShareRequests/ sits alongside the configured entity's request folder (ClientRequests/ by default) — see _meta/config.yaml if you've renamed the entity tree.
action is share (grant) or revoke (remove); access is read or write. brain cycle treats the two very differently, because they change risk in opposite directions:
  • share requests queue for human approval. Adding access is risk-increasing, so the request lands in _meta/shares/pending/ — the same human-gated posture as promotions. Like promotions, that approval isn't always an admin's call — see below for who decides, and Who approves for the promotions table.
  • revoke requests auto-apply, in the same cycle. Removing access is risk-decreasing, so no approval gate is needed — the grant is amended immediately and the request archived to _meta/shares/revoked/ for the audit trail.
Who approves depends on who would gain access:
RecipientApprover
person:<id>that person — the recipient consents from their own vault
team:<name>anyone with role: lead who is on that team
everyonean admin, with brain shares approve (read-only shares only)
An admin can always decide anything, and brain shares revoke remains the veto. Recipients and leads see pending items in an Awaiting your decision section of their Shares.md and decide by writing People/<you>/Approvals/<share-id>.md with decision: approve or decision: reject (rejections need a reason:). The decision is applied by the next brain cycle after re-checking eligibility server-side; every delegated decision is recorded with who decided it and surfaced by brain doctor for 30 days.
Ownership is re-verified server-side against the live spaces.yaml rule, never trusted from the request. A revoke request is honored only from a requester whose own person:<id> is a literal entry on the exact rule's write list — team- or role-derived write access isn't enough to auto-apply a revoke. That requester can then revoke any other subject on the rule, but two protections hold regardless of who's asking: the space's bound owner — the first person: entry on the write list, set when the space was created — can never be revoked by anyone through this path, and self-revocation is always refused (ask an admin to remove your own access). A requester with no literal write entry of their own is rejected ("not the bound owner"); one who targets the bound owner is rejected too ("cannot revoke the space owner"). role:admin can never be revoked from any rule either — it's structural oversight, not a grant to negotiate away. A request whose frontmatter owner disagrees with its own People/<id>/ path, or whose requester turns out not to have write access to the space at all when brain cycle runs, is tampering — rejected outright and counted in shares_tampering (brain cycle --json), which flips the cycle's ok to false. Routine rejections (an unknown recipient, a subject who already has the access, revoking access that isn't there) do not.
Every pending share, and every decision from the last 30 days, shows up in the requester's own People/<you>/Shares.md under a Space shares heading — see Promotions: where the person sees status.

What a revoke does not undo

A revoke takes effect on the next compile: the space is gone from that person's vault, and brain compile rebuilds their tree without it. What a revoke cannot do is un-deliver what they already had.
Each compiled vault is a git repo, and the compiler commits to it on every change. So a note someone could read while they were granted access stays in their vault's git history after the revoke — the removal is a commit on top, not an erasure — and git log -p recovers it. A fresh clone carries that history too, because a clone copies history by default.
This is a property of having delivered the file at all, not a hole in the compiler. While the grant was live the note was on their machine, readable, copyable. Revocation is therefore a statement about the future: from here on, not yours. It is not recall.
Two consequences worth planning for:
  • Rotate, don't just revoke. If what leaked was a credential, a key, or anything whose value survives being read, revoking the space does not make it safe again. Rotate it.
  • To purge server-side, rebuild the vault. Delete that person's compiled vault (<out>/<id>) and run brain compile. The next compile builds a fresh repo with a single commit and no prior history, and brain doctor stays clean. The person then re-clones. This reaches the copy the server hands out — it cannot reach a clone already on their laptop, and nothing can.

Who exists: org.yaml

people: admin: {name: Admin, roles: [admin]} # dedicated curation identity — no agent alice: {name: Alice Nguyen, teams: [sales]} bob: {name: Bob Rivera, teams: [ops]}
A person's roles and teams are what the grants resolve against. The admin identity carries the admin role, so it reads and writes Company. Alice has no roles: she reads Company (it's read: [everyone]) but can't write it, and she reads/writes Teams/sales and People/alice.
Keep the admin role on a dedicated identity — one with no personal agent — rather than on an employee's account. In a deployment where people chat with agents, an employee who also held admin would have an agent that could write Company directly, bypassing the promotion gate. Separating the two keeps shared knowledge behind the human approval step for everyone.

Adding a person or team

Editing org.yaml (and spaces.yaml if a new space needs a rule) and re-running brain compile is the entire operation. There is no schema migration, no per-note reclassification — capacity grows, architecture doesn't. See the configuration reference for the full schema and validation rules.

Two people, one file

A write scope says who may write a space, not who may write it right now. Where a space has one writer that distinction never comes up. Where it has several — Teams/* by default — it decides what happens when two of them edit the same note.
Last write wins, and nothing warns you.
Write-back works by diffing a vault against the manifest the compiler shipped to that vault: every file whose hash moved is a change. So if two members of sales both edit Teams/sales/Runbook.md between cycles, each vault honestly reports "this file changed", both changes are in scope, and both apply to master in sequence. The second overwrites the first. There is no merge, no conflict marker, and no rejection — the first edit is simply gone from the working tree.
It stays recoverable: master is a git repo and both writes are commits, so the overwritten version is one git log -p away. But nobody is told to go looking.
Two things bound how often this matters:
  • Personal spaces cannot collide. People/<id> has exactly one writer by construction, and that is where the vast majority of writing happens — captures, memory, notes, drafts.
  • Shared spaces mostly aren't written directly. Company/* is admin-write, and the intended path into it is a promotion, which is reviewed by a human who sees the target.
The exposure is real but narrow: several people writing the same file in the same team space within one cycle window. If a team works that way, either give each member a file of their own, or shorten the cycle interval so the window is smaller.
This is a deliberate simplicity, not an oversight. Detecting the conflict would mean write-back comparing against master's current state rather than the manifest baseline, and then deciding what to do — reject the batch, attempt a merge, or write a conflict file. Each of those is a worse failure for the overwhelmingly common case of one writer per file.

Cross-space links

Wikilinks between spaces are allowed. When the compiler builds a slice, a link that points at a note the person can't see is stubbed — rendered as plain text or a marker — never resolved to content they shouldn't have.
The stub protects the target's content, but the link text — usually the note's name — remains in the source. brain doctor reports this as a cross-refs warning: for every wikilink, it checks that everyone who can read the source space can also read the target space, and flags the readers who can't. It's a warning, not an error — nothing structural broke, but a human wrote a name where someone uncleared can see it. Personal spaces (People/<id>) are exempt: their sole reader is the owner, who can't leak a name to themselves.
A name doesn't need a wikilink to leak. brain doctor also runs a plain-ref check: it scans shared prose for the names of restricted spaces written as ordinary text (the Petrov in "the Petrov trip reset our vetting") and flags the same reader mismatch. To keep false positives low it only matches proper-noun space names — capitalized client and deal folders like Vandenberg, not lowercase team or person identifiers like sales or marco, which collide with everyday words. It's structural name-matching, not language understanding, so it catches names that are also folders; a client referred to by a nickname that isn't a folder name won't be caught. See the CLI reference for the full check list.