12345678910111213141516171819master/ 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/
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.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.spaces.yamlread 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.12345spaces: - {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"]}
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.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.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:123- {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"]}
{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).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.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.People/<id>/ space can request a brand-new client without an admin touching spaces.yaml directly. It writes the request into its own space:1People/marco/ClientRequests/Vandenberg.md
1234567--- client-name: Vandenberg owner: marco entity: client source: chat created: 2026-07-22 ---
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.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:1- {path: "Clients/Vandenberg", read: ["role:admin", "person:marco"], write: ["role:admin", "person:marco"]}
People/<id>/ path segment is the authoritative owner — never a frontmatter field. Three other outcomes are possible:Clients/Vandenberg, the request merges into the existing note instead of creating a new grant.People/marco/Inbox/client-taken-….md) asks Marco to add a distinguishing detail (a first name, company, or city) and try again.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._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.spaces.yaml. They write a request into their own space:1People/marco/ShareRequests/share-vandenberg-yuki.md
12345678--- 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.| Recipient | Approver |
person:<id> | that person — the recipient consents from their own vault |
team:<name> | anyone with role: lead who is on that team |
everyone | an admin, with brain shares approve (read-only shares only) |
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.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.People/<you>/Shares.md under a Space shares heading — see Promotions: where the person sees status.brain compile rebuilds their tree without it. What a revoke cannot do is un-deliver what they already had.git log -p recovers it. A fresh clone carries that history too, because a clone copies history by default.<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.org.yaml1234people: admin: {name: Admin, roles: [admin]} # dedicated curation identity — no agent alice: {name: Alice Nguyen, teams: [sales]} bob: {name: Bob Rivera, teams: [ops]}
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.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.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.Teams/* by default — it decides what happens when two of them edit the same note.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.git log -p away. But nobody is told to go looking.People/<id> has exactly one writer by construction, and that is where the vast majority of writing happens — captures, memory, notes, drafts.Company/* is admin-write, and the intended path into it is a promotion, which is reviewed by a human who sees the target.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.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.