AxiomCode
AI 소프트웨어 엔지니어링을 위한 검증 가능한 인텔리전스, 형식화된 코드 그래프 기반
Commonwealth: a multiplayer, git-backed, agent-readable second brain for teams
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Commonwealth — a multiplayer second brain for teams
The shared, agent-readable context every teammate's AI reads before it acts.
Instant onboarding. Anti-bus-factor. Plain markdown. Git-backed. Open source.
Published on npm as @cmnwlth/*.
Most teams have a personal-notes story (Obsidian, CLAUDE.md) and an enterprise-search story
(Glean, Notion AI). Nothing in between owns the reasoning layer of a small team — the why
behind decisions, the current work-state, the memory that would otherwise walk out the door with
whoever wrote it.README 전문 보기 ↗The shared, agent-readable context every teammate's AI reads before it acts. Instant onboarding. Anti-bus-factor. Plain markdown. Git-backed. Open source.
Published on npm as @cmnwlth/*.
Most teams have a personal-notes story (Obsidian, CLAUDE.md) and an enterprise-search story
(Glean, Notion AI). Nothing in between owns the reasoning layer of a small team — the why
behind decisions, the current work-state, the memory that would otherwise walk out the door with
whoever wrote it.
Commonwealth is that layer, made multiplayer:
.env-style secrets are detected and blocked at
capture and scrubbed before commit.Claude Code / Codex (every teammate)
│ reads before acting · writes back what it learns (MCP)
▼
your brain = plain markdown in a git repo
│ background sync: pull · commit · push · conflict-free merge
▼
git remote (GitHub / GitLab / your own) — the team shares it
Requirements: Node ≥ 22 and git. Claude Code and/or Codex for the agent experience.
See it in 60 seconds, no setup:
npx @cmnwlth/cli demo
Scaffolds a throwaway brain for a fictional payments team and answers a few questions whose
answers live only in that team's notes. It cleans up after itself (--keep to poke around).
Set up a brain for your project — one command:
npm i -g @cmnwlth/cli # or run any command with: npx @cmnwlth/cli <command>
cd your-project
commonwealth init
init is an interactive wizard (press Enter to accept each default). It:
CLAUDE.md / .cursorrules / AGENTS.md).AGENTS.md brain snapshot.After install, restart the selected agent and open a new session/thread so it loads the plugin. In Claude Code,
/mcpshould list thecommonwealthserver. Beyond its tools (search,ask,read,remember, …), the MCP server exposes the command set as prompts (/mcp__commonwealth__ask,remember,decide,meeting,recall,status,promote) and the brain as read-only resources (commonwealth://<brain>/…— the map, per-kind indexes, and individual notes you can @-mention to pin into context), so Cursor/Windsurf/Zed/Claude Desktop users get Commonwealth's verbs and browsing natively, not just Claude Code. On those hosts the MCP server also owns sync itself — it pulls at startup and commits + pushes a note as it is written, telling you whether it actually reached the remote (ADR-0040). What it does not do without our hooks is capture automatically or inject context proactively; see agent parity. In Codex, run/hooks, review Commonwealth, and trust the current hook definitions; unreviewed plugin hooks are skipped.
The default remains Claude Code for backward compatibility. Select Codex or both explicitly:
commonwealth init --agent codex
commonwealth init --agent both
You can also install either plugin directly — the repo is its own compatible marketplace:
claude plugin marketplace add kristoffeys/commonwealth
claude plugin install commonwealth@commonwealth
codex plugin marketplace add kristoffeys/commonwealth
codex plugin add commonwealth@commonwealth
Prefer to run non-interactively (CI, scripting)? Pass --yes to use defaults + flags:
commonwealth init --yes --agent both --sync ~/work/app --seed-repo ~/work/app --remote [email protected]:you/brain.git
When you give the brain a --remote, init (and add) also drop a .github/workflows/commonwealth-ci.yml
into it: on every push/PR the brain's own repo clones itself and runs verify-restore --from-remote, so a
corrupted note or broken supersede chain is caught at push time, naming the offending file. Pass --no-ci to
skip it; a re-run never overwrites a workflow you've edited.
Then open a Claude Code session or Codex thread in the project and ask it something your team
already knows. Both hosts inject relevant brain context and capture before compaction. Claude Code
captures at SessionEnd; Codex has no session-end event, so it performs throttled capture when an
agent turn reaches Stop. In Codex, Stop is a turn boundary, not the end of the thread.
Once set up, talk to the brain through your AI in any session. The commonwealth CLI covers the
rest — every command resolves the right brain from the current directory automatically:
commonwealth add <folder> [--brain <dir>] # wire another folder to the brain, in one go
commonwealth registry <show|route|allow|deny|remove|default|pull> # brain-resolution rules (see below)
commonwealth status # last capture outcome + dropped candidates + review queue + sync state
commonwealth recall <query> [--verbose] # search the brain (--verbose shows per-hit retrieval provenance)
commonwealth ask <question> [--answer] # cited retrieval; --answer synthesizes a cited answer via a headless model
commonwealth reseed [<repo>] [--all] # mine repo(s) into the brain again
commonwealth pending # notes awaiting review
commonwealth promote <id...> | --all # approve staged notes into canon
commonwealth promote --all --pr # open a brain-repo PR to review the promotion instead
commonwealth reject <id...> # discard staged notes
commonwealth sync once # sync now (lifecycle hooks do this automatically)
commonwealth sync start|stop # opt into/out of the continuous daemon profile
commonwealth redact [--dry-run] [--yes] # PURGE leaked secrets from ALL git history + force-push (destructive)
commonwealth service <install|uninstall|status|restart> # run sync as an OS background service
commonwealth health # freshness/trust score + capture coverage (what fraction of sessions land a note)
commonwealth health --fail-under-capture 0.3 # exit non-zero when 7-day capture coverage is below 30% (CI/cron gate)
commonwealth map # brain-at-a-glance: per-kind counts + top contributors
commonwealth project list # engagement links: which sources are one project
commonwealth project link <id> <src...> # link a dev repo + business folder into one engagement
commonwealth project unlink <id> [<src>] # undo a link (derived views only; no notes change)
commonwealth project adopt <id> [--dry-run] # promote a proven link into note frontmatter (one commit), then retire the entry
commonwealth project relayout [<id>] [--dry-run] # move canon files so folders key off the resolved project (<project>/<kind>/)
commonwealth project rename <old> <new> [--dry-run] # rename a project everywhere it is the identity (alias key + frontmatter) and move the folders, one commit
commonwealth statusline [install] # ambient status line for Claude Code (see below)
commonwealth graduate [--suggest] # propose facts recurring across ≥2 brains to the org-brain
commonwealth consolidate [--dry-run] # supersede near-duplicate canon notes onto one survivor
commonwealth consolidate|graduate --force # run the full pass even when nothing has changed since the last one
commonwealth doctor [--fix] # diagnose the setup, the last capture, why candidates were dropped, and vault hygiene
commonwealth lint [--fix] # vault hygiene: dead links, metadata gaps, stale derived views (--fix rebuilds them)
commonwealth update --agent both # update the CLI + refresh both host integrations
commonwealth --version # print the installed CLI version
The CLI checks npm at most once a day and prints a note on stderr when a newer version is
published (TTY only, never in CI; set COMMONWEALTH_NO_UPDATE_CHECK=1 to silence it).
commonwealth redactrewrites shared history. The capture and pre-commit secret gates stop a credential entering a new commit; they can't remove one already sitting in an old blob (a working-tree "redaction" leaves the raw value recoverable viagit log -pand in every clone).commonwealth redactscans all history, rewrites every leaked value out of it, and force-pushes the result to scrub the remote — so afterwards every teammate must rungit fetch origin && git reset --hard origin/<branch>(unpushed local work needs a manual rebase). It requires typing the brain name to confirm, supports--dry-run, and is never run by the sync daemon. Rewriting history is damage-limitation — rotate the exposed credential too (ADR-0037).
Decisions are first-class. Commonwealth records decisions it detects in a session automatically; to be sure a business or team decision is on the record — or to log one that never touched a coding session — use the deliberate path inside Claude Code:
/commonwealth:decide we're standardizing on Postgres for the ledger, not DynamoDB
It writes a decision note capturing what was decided, when, who decided it, and
why — so a later reversal supersedes it rather than erasing the reasoning.
Paste a meeting into the brain and it is summarized and filed for you. Give
/commonwealth:meeting the raw material — a Plaud export, a recording transcript, or pasted
notes — inside Claude Code:
/commonwealth:meeting <paste the transcript / notes here>
It stores the meeting hybrid (ADR-0036): one immutable meeting note keeps a clean structured
summary with the raw transcript folded in at the bottom, and every decision, action item (with an
owner), and durable fact inside it is extracted as its own atomic note, cross-linked back to the
meeting. So the meeting shows up as a record you can re-mine and its decisions/actions land in the
decision log and the work-state list like any other note. The host agent does the summarizing;
Commonwealth stores. Large transcripts are piped in, so length is not a problem, and the transcript
passes the same secret + dedup gates as every write.
By default, captured notes go straight into canon after the dedup + secret gates. To hold them in a review queue for approval instead, flip the per-brain flag (it syncs with the brain):
commonwealth config set autoPromote false # require manual review
commonwealth pending # see what's waiting
commonwealth promote <id...> | --all # approve into canon
A gate declining a candidate is normal; a gate declining it silently is a bug. Every drop leaves
a capture receipt (ADR-0039) recording what class it was —
duplicate, secret-blocked, too thin, autoAdr-vetoed, trivia — whether you can do anything about
it, and what. commonwealth status shows the rollup; commonwealth doctor names the fix:
⚠ Decisions 3 decision candidate(s) were VETOED because this brain has `autoAdr` off (2h ago).
fix: Set `"features": { "autoAdr": true }` in the brain's `.commonwealth/config.json` …
✓ Drops 9 candidate(s) dropped by curation (12m ago): 7 duplicate (lexical), 2 trivia.
Receipts live in the brain's gitignored index/ — derived, disposable, never committed or synced.
A fresh clone starts with none.
A brain can be perfectly wired and still rot: a superseded_by pointing at a note somebody moved, a
[[wikilink]] to a note nobody wrote, a COMMONWEALTH.md that no longer describes canon.
commonwealth lint walks the link graph and the derived views and names each one, per file:
commonwealth lint # read-only: dead links, metadata gaps, stale views
commonwealth lint --orphans # also list notes nothing links to
commonwealth lint --fix # regenerate the drifted derived views (deletes nothing)
commonwealth doctor carries the same four checks as one line each. Exit code 1 is reserved for the
defects that put a note out of reach — it doesn't parse, its id doesn't match its filename, or a
supersede chain dead-ends — so it is a CI gate, not a nag; dead prose links and misfiled notes warn.
--fix only ever writes derived files, never deletes one, and never touches a note — safe
because derived files are a pure function of the notes
(ADR-0003). Fixing a broken supersede id is a canon edit and
stays yours.
Non-terminal teammates (designers, PMs) and teams that want an auditable trail can review promotions as a normal pull request on the brain repo instead of approving locally:
commonwealth promote <id...> | --all --pr # branch + commit the canon adds, push, open a PR
This needs a git remote (origin) and the GitHub CLI (gh); local-only brains keep the plain
promote. Merging the PR is the promotion — the adds are union-merge-safe (one fact per file,
ADR-0003). Closing it is the rejection — nothing enters canon. Because the staging queue is
per-user and gitignored (ADR-0008), the PR branch carries the canon adds only; your local staged
copies are cleared automatically the next time you run promote/status after the PR merges, and
no teammate's queue is ever touched. Scaffolded brains ship a commented-out .github/CODEOWNERS
sample so a team can gate decisions/ behind a lead's review with a one-line uncomment.
Show the brain at a glance in Claude Code's status line — name, freshness score, and pending-review count — so "is it working?" and "is anything waiting for me?" are answered without running a command:
commonwealth statusline install # add it to ~/.claude/settings.json (then restart Claude Code)
Renders e.g. 🧠 antenna · 87/100 · 3 pending · ⇅ (the ⇅ shows only when the optional sync
daemon profile is live; with the default daemonless lifecycle sync it's simply omitted. pending
shows only when the queue is non-empty). It reads a cached status the SessionEnd hook
refreshes, so it stays well under the status line's per-turn latency budget — no git or index work
happens on render. commonwealth statusline uninstall removes it; a hand-written statusLine is
never clobbered. (Claude Code doesn't let a plugin register a main status line, so this one-time
install writes the entry into your own settings.)
When the same fact recurs across several project brains — a convention, a shared-infra rule — it can graduate to an org-brain everyone reads. Graduation is opt-in and safe by default:
commonwealth org-brain set ~/brains/org # designate the org-brain (once, per machine)
commonwealth graduate --suggest # scan wired brains; stage recurring facts for review
A note is only ever considered when it carries graduate: true, and even then it must recur
across ≥2 distinct brains to be proposed. Candidates are staged for manual review in the
org-brain (with sources: back-links to where they came from) — never auto-promoted across the
trust boundary, regardless of any brain's autoPromote. Rejecting a candidate records a
reject-tombstone in the org-brain, so the same cluster is not re-proposed on the next run (it is
skipped with a (previously rejected — N suppressed) note); commonwealth graduate --include-rejected
resurfaces them. See ADR-0023.
A quiet run is cheap. consolidate and graduate are safe to put on a schedule: before doing
any similarity or embeddings work, each cheaply fingerprints the notes it would read and skips the
whole pass when nothing has changed since its last successful run, reporting nothing to do — canon unchanged since <time>. The marker advances only on success, so an interrupted pass
re-processes the same window rather than skipping it, and it lives in the disposable index/
directory — deleting it just costs one full pass. --force runs the full pass regardless, and
--dry-run always does the work.
Which brain a directory reads and writes is decided by an ordered ruleset (ADR-0024). A rule matches by git identity or path, and routes to a brain, denies capture, or falls through to a default brain:
commonwealth registry default ~/brains/antenna # the brain bare "allow" rules route to
commonwealth registry allow 'org:weareantenna/*' # all repos of an org → the default brain
commonwealth registry route repo:weareantenna/erp ~/brains/erp # one repo → a different brain
commonwealth registry deny repo:weareantenna/secrets # never capture this repo
commonwealth registry route 'path:~/scratch' ~/brains/scratch # a path (non-repo dirs, monorepos)
commonwealth registry show # list rules and the default brain
commonwealth registry remove repo:weareantenna/erp # drop a rule
Share rules with your team (ADR-0024 §5). Add --shared and the rule lives in the brain's committed config instead of your machine-local one, so it syncs to every teammate — the repo → brain intent is portable even though each person's brain path differs:
commonwealth registry route repo:weareantenna/erp ~/brains/erp --shared # the team routes erp here
commonwealth registry deny repo:weareantenna/secrets --shared # a team-wide deny
commonwealth registry pull # materialize teammates' shared rules
Shared rules are materialized into your local config automatically on sync; pull does it on demand. Your local rules always override a shared rule for the same matcher, so a personal deny or reroute is never clobbered by the team's — and personal (local, the default) rules never sync.
A matcher is one of:
| Matcher | Matches | Example |
|---|---|---|
repo:<owner/repo> | an exact repo (by its git origin) | repo:weareantenna/erp |
org:<owner> | every repo of an owner | org:weareantenna (or …/*) |
path:<dir> | a path prefix — for non-repo dirs & monorepo subtrees | path:~/scratch |
* | everything (the catch-all) | commonwealth registry allow '*' |
Precedence (most specific wins): repo > org > path (longest) > *. A deny wins on a tie. A bare allow (no brain) routes to the default brain; an unmatched directory captures nothing.
Because repo/org match on git identity, a rule follows a repo across every worktree, clone, and machine — one org:weareantenna/* line covers all of Antenna's repos and all their branch worktrees, which path prefixes never could. Quote matchers containing * so your shell doesn't expand them.
commonwealth add <folder>writes a rule for you: arepo:rule when the folder is a git repo with anorigin(so it follows that repo everywhere), otherwise apath:rule.
A per-user, local allow/deny list decides which folders are ever captured or injected — personal
projects stay out. It lives in ~/.commonwealth/config.json and is never synced.
commonwealth scope allow ~/work # only capture work under here…
commonwealth scope deny ~/work/secret # …except this (deny wins)
commonwealth scope check # → in-scope | out-of-scope (for the cwd)
Rule: in scope if (allow is empty OR under an allow entry) AND under no deny entry. With no
config, everything is in scope; add a deny (or a narrow allow) to exclude.
Scope only decides whether capture may happen in a folder — which brain the folder writes to
is a separate mapping. To bring a new project folder in, don't scope allow it by hand; run
commonwealth add ~/work/new-project # allowlist + brain mapping + symlink, in one go
which wires it to the brain your current directory resolves to (or pass --brain <dir>).
A note records where it was captured in its source (the git origin slug for a repo, the
folder name otherwise) — honest provenance that is never rewritten. But one real engagement often
spans several sources: a customer's dev repo and their business folder. Link them into one
project so every grouped view — COMMONWEALTH.md, health — reads as a single engagement:
commonwealth project link acme "weareantenna/acme-website" "Acme Website"
commonwealth project list # see the engagement and its member sources
commonwealth project unlink acme # undo — derived views only, no note changes
commonwealth project adopt acme # once the link is proven, bake it into the notes
Linking is always explicit (never a fuzzy name-match), it touches no note files, and it is
retroactive: existing notes regroup the moment you link. A working folder can also declare its
identity up front with a .commonwealth/project.json manifest ({ "project": "acme", "customer": "Acme Corp" }) — capture then stamps the project onto new notes and the customer as a
customer:<slug> tag. The alias map is the retroactive/corrective layer; the manifest is the
save-time path. (See ADR-0031.)
Once a link has proven correct, adopt it: commonwealth project adopt acme stamps the resolved
project (and customer:<slug> tag) onto every linked historical note's frontmatter in one
reviewable commit, then retires the now-redundant alias entry — the identity now lives on the notes
themselves (--dry-run previews the counts first). Adoption refuses on a dirty worktree, never
touches a note that already declares a different project (reported as a conflict), and leaves the
derived views byte-identical (the read-time and save-time tiers resolve the same way).
Need to rename an engagement? commonwealth project rename <old> <new> changes the id
everywhere it is the identity — the alias-map key (carrying its sources and customer) and any note
that declares project: <old> in its own frontmatter — then moves the folders to follow so every
note lands under <new>/<kind>/…, all in one reviewable commit (--dry-run previews the key
rename, the re-stamp count and the move plan). It refuses to run if <new> already names a project
(never a silent merge — pick a free id or unlink the existing one first) and, like adopt, refuses on
a dirty worktree.
You usually don't need this. By default sync runs in the session lifecycle (ADR-0032) — the plugin hooks commit/pull/push at session start and after each capture, so a fresh install converges with no resident process. The daemon profile below is opt-in for cases that want continuous background propagation regardless of sessions: headless/server installs, shared machines, or high-frequency teams. When the daemon is live, the lifecycle hooks stand down (it owns sync).
On a host with no lifecycle hooks at all (Claude Desktop's Chat tab, a bare MCP client) the MCP
server syncs: a bounded pull when it starts, and a commit + push when a note lands in canon, with
the remember answer stating whether it was published (ADR-0040). Our own plugin turns that off
(COMMONWEALTH_MCP_SYNC=off in its MCP declaration) because there the hooks already do it — set
that variable yourself only if you wire the server up by hand and run sync some other way.
commonwealth sync start runs the daemon in the foreground (it holds the terminal). To keep a
brain syncing across logout and reboot, install it as a user-level service that auto-restarts
on crash:
cd <a wired folder> # or pass --dir <brain>
commonwealth service install # generate + load the service, syncing that brain
commonwealth service status # is it loaded / active?
commonwealth service restart # reload (e.g. after picking up a new binary)
commonwealth service uninstall # unload + remove it
Per OS, install generates and loads a user-level unit — no root, nothing system-wide:
| OS | Mechanism | Auto-restart |
|---|---|---|
| macOS | a LaunchAgent plist in ~/Library/LaunchAgents/be.commonwealth.sync.plist | KeepAlive (on crash) |
| Linux | a systemd --user unit ~/.config/systemd/user/commonwealth-sync.service (with enable-linger so it runs while logged out) | Restart=always |
| Windows | a Scheduled Task CommonwealthSync, at logon | restart-on-failure |
commonwealth update restarts an installed service automatically so the freshly updated binary
is loaded — you don't have to remember to. Logs go to ~/Library/Logs/commonwealth-sync.log
(macOS) or the systemd journal (journalctl --user -u commonwealth-sync).
Commonwealth keeps a few small files, deliberately separate:
| File | Scope | Synced? | Holds |
|---|---|---|---|
~/.commonwealth/config.json | per-user | no | your brain-resolution rules + default brain, and the scope allow/deny |
<brain>/.commonwealth/config.json | in the brain | yes | brain name, remotes, and feature flags (team-shared) |
Two files, disambiguated by location: the per-user one under ~/.commonwealth/ is machine-local and never synced (your rules and personal denies stay yours); the one inside a brain syncs to the whole team.
Team-wide feature flags live in the brain config and are toggled with the CLI:
commonwealth config list # name, remotes, and all flags
commonwealth config set autoAdr false # opt a brain OUT of decision tracking
commonwealth config set semanticDedup true # smarter dedup (see below)
autoAdr (default on) — records decision notes (auto-detected and via
/commonwealth:decide). Set false to stop tracking decisions in a brain entirely.autoPromote (default on) — captured notes land in canon directly; set false to
require manual review.semanticDedup (default off) — also catch near-duplicate notes phrased differently
("auth uses JWT" vs "we authenticate with bearer tokens"), using embeddings. Runs on-machine by
default (no note text leaves the box) and needs an optional model package installed on enable.semanticSearch (default on) — hybrid retrieval: when an embeddings provider is
configured, recall/ask/search fuse a semantic (embedding) ranking with the lexical one, so
paraphrases and stopword-heavy questions ("did we use Shopware before?") still find the note.
Inert for brains with no provider (behaves exactly like lexical-only), and set it false to force
lexical-only even with a provider. Reuses the same vectors as semanticDedup, so existing brains
need one index rebuild to backfill vectors for notes captured before either was enabled. Per-prompt
context injection runs a strict variant that rejects vector-only noise (an embedding-near note
with no lexical/title/tag overlap); commonwealth recall --verbose shows the per-hit provenance
(lexical/semantic rank, fused score, evidence tier) behind each result.llmCurator (default on) — an LLM curation pass in the capture pipeline
(ADR-0030): a durability judge filters trivia the length
check can't, and a consolidation classifier catches paraphrased updates (supersedes the older
note) and contradictions of canon (flags them — never auto-rejected). Keeps autoPromote canon
clean without human review. Runs in the plugin hook layer over the same host runtime as capture,
so it is inert without a runtime (behaves exactly like today); any classifier failure fails open
to the deterministic gate. Set false to skip the pass.contradictionGuard (default off) — an action-time contradiction guard
(ADR-0033): a PreToolUse hook that, before a
Write/Edit/Bash runs, checks whether the pending change looks like it contradicts a recorded
note (reusing the / vectors) and surfaces it. Default
because it fires on the tool hot path; inert without an embeddings provider. — it injects a one-line warning into the agent's context and the tool still runs; set
to (from ) in the brain config to escalate to a permission
prompt instead. Conservative by design: decision-notes-only, a hard 300ms fail-open time budget (a
slow/cold embedder simply means no warning), one nudge per decision per session, and a high
similarity floor (, default ) so it fires rarely.| Doc | What it covers |
|---|---|
docs/05-quickstart.md | Get a brain running for one project in minutes |
docs/06-self-host.md | Share a brain across a team over your own git remote |
docs/07-agent-parity.md | Claude Code/Codex parity, lifecycle mapping, and health |
docs/01-architecture.md | How it works: git substrate, concurrency, the auto-bridge |
docs/02-data-model.md | The markdown schema: memory / decisions / work-state / people / meetings |
docs/03-distribution.md | Distribution into Claude Code and Codex |
docs/04-roadmap.md | What's shipped and what's next |
docs/release-checklist.md | Fresh-marketplace release proof for both hosts |
Apache-2.0 © 2026 Kristof Feys
decisionsemanticDedupsemanticSearchcontradictionGuard.modeaskwarncontradictionGuard.threshold0.82