Architecture¶
The whole system rests on three decisions, in order of how much they define the product:
- Git is the substrate — not a database with git export.
- Concurrency is designed out, not resolved — atomic files + derived indexes.
- The "auto" bridge is the product — capture → curate → commit → propagate.
1. Git is the substrate¶
The brain is a git repository of markdown. No proprietary store is the source of truth — that is the ownership and portability guarantee: your knowledge stays in files you own, not an opaque index or a block database you can't leave.
- One repo per project brain.
acme-brain,internal-brain, etc. A team may also have anorg-brainfor cross-project knowledge. (Monorepo-of-brains is a later option; per-project repos keep permissions and blast radius simple.) - Remote = any git host. GitHub by default (fits our OSS + Projects workflow), but the design must not assume GitHub-only. Self-host / BYO-remote is first-class.
- A local working copy lives on each member's machine (e.g.
~/.commonwealth/<brain>), kept in sync by the plugin's lifecycle hooks at session start and after each capture (ADR-0032) — a resident daemon is an optional profile, no longer the default. The agent reads/writes the local copy; sync moves commits to/from the remote. - A derived index (SQLite + embeddings) is built from the markdown for fast
search. It is disposable and
.gitignored — rebuildable from files at any time (basic-memory's model, and the right one).
acme-brain/ # a git repo = one project's brain
├── memory/ # atomic notes (append-heavy, rarely collide)
│ ├── 2026-07-01-auth-choice-a1b2.md
│ └── 2026-06-30-client-billing-quirk-9f3d.md
├── decisions/ # ADR-style, one file per decision
├── work-state/ # current status per workstream
├── people/ # people-threads: one file per person/relationship
├── index/ # DERIVED, gitignored (SQLite + vectors)
├── .commonwealth/ # config: schema version, curation rules, remotes
├── COMMONWEALTH.md # human+agent entry point (the router / TOC)
└── README.md # USER-OWNED: scaffolded once, never regenerated
2. Concurrency: design it out¶
Concurrency is where most shared-memory tools are weakest — mtime-wins overwrites, whole-file rewrites that conflict, or simply being single-player. We don't want to win merge conflicts — we want to not have them.
Three mechanisms, in priority order:
a) Atomic, append-only notes — one fact per file¶
Following the pattern that already works in personal setups (Claude's own
one-fact-per-file memory): each note is a small, self-contained markdown file with a
collision-proof name (<date>-<slug>-<shortid>, shortid = content/uuid hash). Two
teammates writing "at the same time" create two different files. Git merges them as a
union — no conflict, ever. This is the single most important concurrency decision.
b) Derived, never-hand-merged indexes¶
COMMONWEALTH.md, per-folder tables of contents, backlink graphs, roll-ups — all
regenerated from the note files, not hand-edited. So the high-contention "index"
file is never the subject of a manual merge. Two strategies, combined:
- Regenerate on the daemon after every pull (idempotent from the file set).
- Register a git merge driver (
merge=unionvia.gitattributes) for the append- only index files as a backstop, so even a raw merge unions cleanly.
c) A serialization queue for the rare true edit¶
Editing an existing note (a correction, a decision superseded) can still collide. For those:
- Section-scoped edits, not whole-file rewrites. Prefer
append/insert-sectionops over rewriting the file (Letta'smemory_insertis safe;rethinkis lossy). - A lightweight write queue in the daemon serializes commits to the same file: acquire → pull/rebase → apply → push, with retry. This is the "queueing mechanism" from the brief, scoped down to only where it's actually needed (same-file edits), not every write.
- On genuine conflict, never silently overwrite. Write both versions as sibling notes
and file a
conflict:curation task for review.
Net: ~all writes are new atomic files (conflict-free unions); indexes are derived (no manual merges); only same-file edits touch the queue, and even those degrade to a reviewable task rather than data loss.
3. The "auto" bridge — capture → curate → commit → propagate¶
Storage is solved; the unsolved problem (per the research) is the auto pipeline: turning session learnings into shared, curated, propagated knowledge. This is the product. It runs in four stages, wired into host-specific Claude Code/Codex lifecycle hooks + MCP.
session ──▶ CAPTURE ──▶ CURATE ──▶ COMMIT ──▶ PROPAGATE ──▶ next session
(learnings) (draft (dedupe, (atomic (push + (pull +
notes) verify, file + open PR / inject relevant
gate) queue) review) context)
Capture (host lifecycle hook + MCP write tools)¶
- The agent proposes candidate memories from the session (decisions made, gotchas
learned, work-state changes). Two paths: explicit MCP
remembercalls during the session, and a lifecycle sweep that drafts notes. Claude Code sweeps atSessionEnd; Codex has no session-end event, so it reviews the accumulated thread transcript at throttledStopturn boundaries. Both hosts also capture beforePreCompact. - Candidates land in a staging area (
staging/), not straight into canon.
Curate (curation gate, runs on staging + nightly)¶
- Dedupe against existing notes — lexical, plus optional embeddings (
semanticDedup). - Verify where possible — check memory against reality (e.g. a claim about code vs. the
actual code). Mark
verified:/stale:. - Contradiction check — flag notes that conflict with canon; open a review task.
- Relevance gate — score whether a candidate is worth committing/sharing at all (avoid junk accumulation). Low-value → drop; high-value → promote.
Commit (atomic file + queue, per §2)¶
- Promoted notes become atomic files, committed with a structured message.
- Curation-as-review: promotion opens a PR (or a review queue) so a human — or a higher-trust agent — approves before it becomes canon. Junk never auto-lands.
Propagate (SessionStart hook + relevance-gated fetch)¶
- Commit + push after each capture, in the (already-detached) SessionEnd worker (ADR-0032).
- Fetch/merge into every teammate's local copy on session start (the SessionStart hook runs a time-capped sync-once, then flushes any debt from a prior offline session). The optional daemon profile does the same continuously on a poll interval.
- Relevance-gated injection — the genuinely novel bit: don't dump the whole brain
into context; surface the notes relevant to what this teammate is doing right now
(current project/files/task). This is the "auto push/fetch where it sees fit" from
the brief, made concrete. Relevance runs through core
search(), which is hybrid when an embeddings provider is configured (ADR-0025): a lexical BM25 list fused with a semantic (cosine) list over the per-note vectors, so paraphrases and stopword-heavy questions still surface. Degrades to lexical-only with no provider — same forask,recall, and the MCPsearchtool, which all inherit it.
Components¶
| Component | Role |
|---|---|
| Brain repo(s) | Git repo(s) of markdown — the substrate & source of truth |
| Lifecycle sync | Default (daemonless, ADR-0032): the plugin hooks commit+push after capture and pull+flush-debt at session start, reusing the sync engine as a library. Nothing resident to run. |
| Sync daemon | Optional profile (ADR-0032): a long-lived per-machine process that additionally polls for continuous background propagation. When live, the lifecycle hooks stand down. |
| MCP server | Exposes search / read / remember / list-workstate / whoami-style tools to Claude Code, Codex, and other MCP clients. Reads local copy + index. |
| Curation agent | Runs dedupe/verify/contradiction/relevance on staging + nightly (cron), opens review PRs. Can reuse Claude via the Agent SDK. |
| Agent plugin | One payload with Claude Code and Codex manifests, shared MCP/runtime assets, and host-specific lifecycle declarations. The provisioning unit. |
| Brain registry | Maps a working directory / project → its brain repo(s), so the plugin mounts the right brain automatically. |
Decisions of record¶
The concrete choices behind the above — embeddings (local-first, opt-in), the review-gate default, secret scanning, clone-on-demand access, and more — live as Architecture Decision Records. Cross-brain graduation (project → org brain) is the main open thread; see the roadmap.
See docs/02-data-model.md for the note schema and
docs/03-distribution.md for how the plugin auto-provisions.