gbrain — Operator's Field Manual
Operator's field manual gbrain v0.42.74.0 read from source, 2026-08-08

Markdown is truth.
Postgres is a cache.

Everything gbrain does — the graph, the search, the nightly cycle, the calibration of your own predictions — falls out of one contract, enforced by a CI gate.

people/bob-smith.md — the characteristic artifact of the system
---
type: person
tags: [yc, ai-infra]
---

# Bob Smith

Runs engineering at [[companies/acme]]. Met through [[people/alice]].

## Facts

<!--- gbrain:facts:begin --->
| # | claim        | kind | confidence | visibility | valid_from |
|---|--------------|------|------------|------------|------------|
| 1 | Founded Acme | fact | 1.0        | world      | 2017-01-01 |
<!--- gbrain:facts:end --->

## Takes

<!-- gbrain:takes:begin -->
| # | claim                    | kind | who    | weight | since   |
|---|--------------------------|------|--------|--------|---------|
| 1 | They'll raise a B by Q3  | bet  | eugene | 0.7    | 2026-01 |
<!-- gbrain:takes:end -->

<!-- timeline -->
## Timeline
- 2026-04-22 — pricing chat [Source: notes/2026-04-22]

Four structured surfaces inside one file a human can still read.
Brass = authored by you, canonical, lives in git  ·  Teal = machine-read markers that become database rows.

<!--- gbrain:section:01 --- the contract --->

The one idea everything hangs off

Read this and the rest of the system becomes predictable.

The git repo of markdown files is the system of record. The database is a derived cache. We do not back up the database — we rebuild it from the repo.

docs/architecture/system-of-record.md

This isn't aspirational. scripts/check-system-of-record.sh runs in CI and bans direct calls to insertFact, addLink, addTimelineEntry, upsertTake anywhere outside a designated reconciler. Code that writes a derived table without going through markdown first fails the build.

Two consequences you feel immediately:

# Disaster recovery is boring — there is no "restore backup" step
psql -c 'DELETE FROM facts; DELETE FROM links; DELETE FROM takes;'
gbrain sync          # re-read markdown from the repo
gbrain extract all   # rebuild every derived table, byte-identically

# Multi-machine sync is git. That is the entire mechanism.
git push        # laptop
git pull        # desktop — its DB rebuilds on next sync

Every table sits in exactly one of three buckets:

BucketTablesRebuildable
FS-canonical takes · facts · links · timeline_entries · tags Yes — byte-identically
Derived pages · content_chunks · page_versions Yes — re-chunk + re-embed
Runtime only oauth_tokens · minion_jobs · mcp_request_log · raw_data No — but it isn't knowledge
<!--- gbrain:section:02 --- architecture --->

Architecture

Five moving parts. Everything else is a reconciler between the repo and the index.

┌──────────────────────────────────────────────────────────────────┐
│  BRAIN REPO   git · markdown · the system of record                │
│  ~/brain/{people, companies, concepts, ideas, projects, media}   │
└───────────────────────────┬──────────────────────────────────────┘
                            │  gbrain sync — walks the git diff,
                            │  parses frontmatter + fences
                            ▼
┌──────────────────────────────────────────────────────────────────┐
│  POSTGRES / PGLITE   derived index · ~45 tables               │
│  pages · content_chunks (pgvector HNSW) · links · facts · takes  │
│  timeline_entries · tags · sources · minion_jobs                 │
└───────┬───────────────┬───────────────┬──────────────┬───────────┘
        ▼               ▼               ▼              ▼
    CLI             MCP           MINIONS       DREAM CYCLE
  gbrain …        gbrain serve      job queue      gbrain dream
  ~90 verbs       ~120 ops as       crash-safe     19 phases
                  MCP tools         subagents      nightly cron
Storage

Two engines, one contract

BrainEngine declares ~47 operations, implemented twice: PGLite (Postgres 17 in WASM, zero-config, single-writer, good to ~50K pages) and real Postgres + pgvector.

API

The operations registry

One 6,246-line file declares ~120 named ops with params, OAuth scope, and a localOnly flag. CLI and MCP are both generated from it, so they cannot drift apart.

Privacy

remote is a required field

Every op context carries remote: boolean, enforced by the type system. Private fact rows are stripped by the chunker before embedding, so they never reach search at all.

Jobs

Minions

A Postgres-native, BullMQ-shaped queue. The point is crash-safe subagents: LLM tool loops persist pending → done, so a crash resumes instead of losing work.

Behaviour

63 skills

Plain markdown, tool-agnostic, routed by a RESOLVER file. Signal detection, ingest, citation repair, briefings, schema authoring. Recipes an agent reads — not code.

Shape

Schema packs

Your folder names aren't hardcoded — they come from the active pack. It threads through every read and write path, and its name+version is folded into the search cache key.

The retrieval pipeline

query
  → intent-aware rewrite
  → ┌ pgvector HNSW  — max-pool: best chunk per page, so a page
    │                   surfaces on its strongest evidence
    └ BM25          — websearch_to_tsquery, GBRAIN_FTS_LANGUAGE
  → reciprocal rank fusion
  → source-tier boost        ← weight your own writing above saved articles
  → graph signals            ← adjacency · cross-source · session demote
  → title / alias boost
  → ZeroEntropy reranker
  → results tagged evidence (why it matched)
              and create_safety (exists / probable / unknown)

gbrain search "…" --explain prints per-stage attribution: base score, every boost that fired, what it multiplied by. gbrain search diagnose traces which layer surfaced — or missed — a specific page.

gbrain search returns pages. gbrain think runs the same retrieval, then composes a cited answer plus gap analysis — what's stale, what's uncited, where two pages contradict each other, what hole you should go fill. That second verb is the whole reason to run this.

<!--- gbrain:section:03 --- primitives --->

The primitives

gbrain invents about sixteen nouns. Most confusion with the tool comes from collapsing two of them that look alike. Each below says what it is, where it physically lives, and what it is not.

Storage and addressing

page

One markdown file. The atom of storage.

Everything is a page: a person, a company, an essay, a saved article, a day. A page carries a body (compiled_truth), frontmatter, a type, a content hash, and a salience score. Deletes are soft — a page sits in a 72-hour recovery window before purge actually removes it.

markdown  one file on disk
db  pages — one row, plus content_chunks holding its embedded pieces
not  a database record you edit through the tool — you edit the file

slug

A page's address, shaped like a path.

people/bob-smith, writing/no-way-back, inbox/2026-08-08-a91f2c04. The leading segment is what the schema pack reads to decide a page's type.

Slugs are unique per source, not globally. The same topics/ai can exist in two sources and be two different pages.

full address  brain : source : slug

source

A named content repo inside one brain.

Your notes vault is one source. A codebase is another. An essay collection a third. Every page row carries a source_id. A .gbrain-source dotfile in a directory pins every command run there to that source, so you never pass a flag.

db  sources — id, local_path, and its sync state
cli  gbrain sources add noto --path ~/brain/sources/noto

brain

A whole database. You can have several.

Your personal brain is one. A team's published brain that you mount is another. Separate pages tables, separate access control, separate lifecycle.

The rule that separates the two axes: if the data owner changes, it's a brain boundary. If the owner stays the same and only the topic changes, it's a source boundary.

routing  --brain picks the database  ·  --source picks the repo inside it
solo use  one brain, several sources — you will rarely type --brain

sync state

How far a source has been read.

Three fields on the source row: the last git commit imported, when that happened, and which chunker version did it. gbrain sync walks only the diff since last_commit — that's what makes re-syncing a thousand-page vault take seconds instead of minutes.

Bump the chunker version in a release and the mismatch forces a full re-walk automatically. If a sync is interrupted it exits cleanly with last_commit unchanged, so the next run re-walks the same diff and content hashes skip whatever already landed.

db  sources.last_commit · last_sync_at · chunker_version

federation

Whether a source joins general search.

A per-source boolean. federated: true and its pages show up in every unqualified query. false and the source is invisible unless you name it — the right setting for draft writing, or anything you don't want bleeding into unrelated answers.

Across brains there is deliberately no federation at all. The agent sees the list of brains and decides when to query each one. Keeping that out of SQL is what keeps access control and debugging sane.

scope  within a brain, automatic  ·  across brains, the agent's job

schema pack

The declaration of your brain's shape.

A YAML manifest naming the page types that exist, which folder prefixes map to each, which types get facts mined out of them, which participate in expertise routing, what edge types are legal — and which dream-cycle phases run at all.

Swap the pack and the brain re-interprets itself; swap back and nothing is lost. The pack's name and version are folded into the search cache key, so results from one pack can never leak into another. gbrain schema detect clusters your actual filesystem into proposed types when none of the bundled packs fit.

bundled  gbrain-base-v2 (default) · creator (atoms) · investor · engineer · everything
resolution  flag → env → per-source key → brain key → gbrain.yml → config → default

Structure carried by a page

links

Typed edges between pages. The graph.

Written by the auto-linker on every page save — pure pattern matching on [[wikilinks]], zero LLM calls. An edge carries a type (works_at, founded, discusses, derived_from, supersedes) and the surrounding context.

Two grades exist and it matters: a real wikilink, versus a mentions edge inferred from body text. The weak kind is excluded from backlink-count ranking and only counts toward graph traversal, so a name appearing everywhere doesn't inflate its own importance.

Point at a page that doesn't exist yet and a stub is created. That's how the graph grows without anyone curating it.

markdown  [[people/alice]] in the body
db  links — from_page, to_page, link_type, context
not  a folder, a tag, or a similarity score — a stated relationship

tags

Flat labels from frontmatter.

The simplest primitive: a YAML array, reconciled into a table on import. No hierarchy, no types, no relationships. They filter and they feed the salience score — that's it.

One sharp edge: since v0.41.37 tag reconciliation is add-only. Removing a tag from frontmatter no longer removes it from the database, because enrichment writes tags of its own that a re-index must not wipe.

markdown  frontmatter tags: [yc, ai-infra]
db  tags — page_id, tag

The two knowledge layers — do not conflate these

This is the distinction the codebase calls out by name as the category error. Both are claims. They differ in who said it, when it was captured, and how long it lives.

facts — hot memorytakes — cold epistemology
whoseOnly yours. What you said.Anyone's. Attributed by holder.
whenReal time, per conversation turnRetrospective, extracted from pages
kindsevent · preference · commitment · belief · facttake · fact · bet · hunch
carriesThe claim, its kind, visibilityHolder, weight, since-date, source
read viagbrain recallgbrain takes list / search
lifecyclePromoted overnight, then marked consolidatedDurable; graded and scored over time

facts

What you told the brain, captured as you say it.

“I have a call with Arya Thursday.” “I don't drink coffee.” “We decided to cut the second podcast season.” A cheap model pulls these out per turn and files them on the relevant entity page.

Each row carries visibility: world | private. Private text is stripped by the chunker before embedding — it never becomes a vector, never appears in a search result, and never leaves the machine through the MCP surface.

markdown  a ## Facts fence table on the entity page
db  facts
not  other people's claims — those are takes

takes

Who believes what, how strongly, since when.

A take is a claim plus an owner. holder=self kind=bet “the AI hardware wave peaks in 2027” at weight 0.7 is a different object from the same sentence held by someone you interviewed. Four kinds: an opinion, a verifiable fact, a dated prediction, an intuition.

Weights use 0.05 increments on purpose. The extraction guidance is explicit that 0.74 is false precision, that amplifying someone else's claim caps out around 0.55, and that self-reported numbers never reach the confidence of verified ones.

Because takes carry a weight and a date, they are the only thing in the system that can later be graded against what actually happened.

markdown  a ## Takes fence table
db  takes
not  your conversation memory — that's facts, until the bridge runs

atoms

The reusable unit pulled out of long-form material.

A cheap model reads a transcript or article and extracts one to three atoms, each typed from a closed list: insight, anecdote, quote, framework, statistic, story angle, strategy angle, strategy, endorsement, critique, collection. Each becomes its own page under atoms/{date}/.

This is the creator's primitive. Twelve podcast transcripts sitting inert become a few dozen individually addressable, retrievable pieces — the anecdote you half remember telling, findable without re-listening.

written by  dream phase extract_atoms, capped at $0.30 per source per run
requires  the creator or everything schema pack — off in the default pack

concepts

Atoms that recur, promoted into a real page.

Nightly, atoms are grouped by the concept they reference and tiered by how often the theme appears: ten or more is tier one, five is tier two, two is tier three. The top two tiers get a written narrative; the bottom gets a plain stub.

The tier is the finding. A theme reaching tier one means you have circled it ten separate times without noticing — which is a different and more useful signal than any single note.

written by  dream phase synthesize_concepts, capped at $1.50 per run
lands at  concepts/{slug}

Landing zones and boundaries

inbox

Where unfiled things land, on purpose.

Two things share the name. gbrain capture writes to inbox/YYYY-MM-DD-<hash> by default, so anything captured without a destination clusters in one predictable place to triage later. And ~/.gbrain/inbox/ is a watched folder — anything dropped in from a Shortcut, AirDrop, or Finder gets ingested.

The hash makes capture idempotent: the same text captured twice is one page, not two.

cli  gbrain capture "the thought" · --file · --stdin

diary · event

The two temporal page types.

Added for the Life Chronicle feature. An event under life/events/ is something that happened on a date. A diary entry under life/diary/ is what you thought about it. Neither has facts mined out of it — they're read chronologically, not queried for claims.

These power the chronicle verbs: what happened in a window, what happened on this day in previous years, what has changed since a date.

read via  gbrain chronicle_day · chronicle_since · chronicle_on_this_day

remote

Two different things wearing one word.

The trust flag. Every operation runs with remote: true|false, required by the type system. You at your own terminal are local and see everything. Anything reaching the brain through MCP — including an agent on this same machine — is remote, and gets private fact rows and the entire takes fence stripped from its responses.

The install shape. A thin client is a gbrain with no local content at all, pointed at someone else's brain server over HTTP. Same commands, the data lives elsewhere. Local-only operations refuse with a specific hint rather than silently querying an empty database.

consequence  an agent asking your brain a question sees less than you do, by construction
<!--- gbrain:section:04 --- folder structure --->

Three folder structures

They are easy to confuse and they do completely different jobs.

1 — The brain repo (your knowledge)

Governed by gbrain.yml at the repo root. The split here is the useful lever:

storage:
  db_tracked:        # version-controlled, human-curated
    - people/
    - companies/
    - concepts/
    - ideas/
    - projects/

  db_only:           # on disk + in the DB, auto-gitignored by sync
    - media/articles/  # searchable, but never bloats the repo
    - media/x/         # restore with: gbrain export --restore-only
    - meetings/transcripts/
Why this matters for a captured-article pile

Mark a directory db_only and its contents stay fully searchable while never entering git. That is exactly the right home for hundreds of saved articles, clipped threads, and transcripts — the bulk that you want retrievable but never want to review in a diff.

The directory names come from the active schema pack. gbrain-base-v2 is the default: 15 types, each declaring path_prefixes, whether facts get extracted from it, and whether it participates in expertise routing.

TypePath prefixesExtractableExpert routing
personpeople/ · person/noyes
companycompanies/ · products/ · orgs/noyes
mediamedia/yesno
writingwriting/yesno
projectprojects/nono
conceptconcepts/yesno
atomatoms/nono
diarydiary/nono
notecatch-allyesno

Plus tweet, social-digest, analysis, source, deal, email, slack, event — and typed edges: works_at, founded, invested_in, mentions, discusses, derived_from, supersedes, redirects_to.

2 — ~/.gbrain/ (machine-local runtime)

Never contains your knowledge. Wipe it and rebuild from the repo.

~/.gbrain/
├── config.json              brain registry, embedding model, search mode
├── brain/                   PGLite data dir, if using PGLite
├── inbox/                   drop files here → ingested automatically
├── autopilot.lock
├── advisor-history.jsonl
└── audit/                   ~25 weekly-rotated JSONL streams
    ├── dream-budget-YYYY-Www.jsonl
    ├── batch-retry-YYYY-Www.jsonl
    ├── db-disconnect-YYYY-Www.jsonl
    ├── schema-mutations-YYYY-Www.jsonl
    ├── rerank-failures-YYYY-Www.jsonl
    └── … quality-probe, phantoms, shell-jobs, lock-renewal

gbrain doctor reads those audit streams to produce its health checks — which is why a failure three days ago is still diagnosable today.

3 — Brains ⊥ sources

Two independent axes. A brain is a database. A source is a repo inside it. One brain can hold your notes, a codebase, and an essay collection as separate sources, each with its own sync state and a federated flag controlling cross-source search. A .gbrain-source dotfile pins every command run inside a directory to that source.

<!--- gbrain:section:05 --- the dream cycle --->

The dream cycle

The docs say eight phases. src/core/cycle.ts declares nineteen, in strict dependency order. Each is individually gated and can be run alone.

#PhaseKindWhat it does
01lintmarkdownFrontmatter and structure hygiene
02backlinksindexReconcile incoming links
03syncmarkdownGit diff → database
04synthesizellmConsolidate yesterday's conversations
05extractindexMaterialise links and timeline
06extract_factsindexRebuild facts from every ## Facts fence
07extract_atomsllmHaiku pass: transcripts and articles → atom pages
08resolve_symbol_edgesindexTwo-pass code-symbol resolution
09patternsllmCross-session pattern detection
10synthesize_conceptsllmAtoms → tier-promoted concept pages
11recompute_emotional_weightindexSalience signal from takes and tags
12consolidatellmEphemeral memory → durable pages
13propose_takesllmScan your prose, propose gradeable claims to a review queue
14grade_takesllmRetrieve evidence, judge model verdicts them (auto-resolve off by default)
15calibration_profilellmAggregate resolved takes into narrative bias statements
16driftllmJudge soft-band takes against recent evidence (off, report-only)
17schema-suggestllmPassive schema-evolution proposals
18embedindexEmbed stale chunks
19orphans / purgeindexOrphan detection, soft-delete purge

Phases hold a database lock, are scoped global or per-source, meter their own budget to ~/.gbrain/audit/dream-budget-*.jsonl, and run singly: gbrain dream --phase extract_facts.

Phases 13–15 are the sleeper feature

Nothing in the marketing mentions them. The cycle reads your prose, extracts the claims you actually made, waits, grades them against what happened, and produces a profile of your standing biases. It turns a pile of opinions into a scored record of how your judgment performs.

Every essay, idea note, and diary entry you already have is input for this. Nothing else in a normal notes stack does it.

<!--- gbrain:section:06 --- recurring jobs --->

Cron

The reference schedule runs 20+ jobs. The docs' own advice: don't. Start with three.

# ── the three that matter ────────────────────────────────
*/15 * * * *       gbrain sync --repo ~/brain && gbrain embed --stale
0 2 * * *          gbrain dream                 # the 19-phase cycle
0 6 * * 1          gbrain doctor --json && gbrain embed --stale

# ── add only as you add the matching integration ─────────
*/30 * * * *       email collector      # → people pages
*/30 * * * *       x/twitter collector  # → media pages
0 10,16,21 * * 1-5 meeting sync         # → attendee propagation
0 10 * * 0         calendar sync

Two non-negotiable disciplines

Discipline 01

Quiet-hours gate

Every job that can notify you checks quiet-hours-gate.sh first. Held output goes to /tmp/cron-held/ and must be folded into the next morning briefing, or information is silently lost.

The docs put it bluntly: one 3 AM ping and you'll disable the whole system.

Discipline 02

Travel-aware timezones

The agent reads your calendar for flights and out-of-office blocks, infers the destination timezone, and shifts quiet hours to follow you. No reconfiguration when you land.

Or skip crontab entirely

gbrain autopilot --install

A launchd daemon that supervises a gbrain jobs work child, submits one cycle job per interval, respawns on crash with a five-crash cap, and caps child memory at 2048 MB. For a single laptop this is clearly the better path — the supervision, locking, and memory ceiling are handled rather than hand-rolled.

<!--- gbrain:section:07 --- flows --->

Six flows, end to end

The primitives only make sense in motion. Each flow below names what you actually type, what the system does with it, and which primitives it touches on the way through.

A — You capture a thought

five seconds · you

The lowest-ceremony path in. No destination, no decision, no filing.

  • 1

    You type one line.

    gbrain capture "the podcast's best episodes all start with
                    a disagreement, not a topic"
  • 2

    A page is written to disk at inbox/2026-08-08-3f1a9c02 — the hash is of the content, so capturing the same sentence twice produces one page, not two.

  • 3

    The next sync reads it, chunks it, embeds it. It is now retrievable — from a phrase you don't remember writing, months later.

  • 4

    Later, the overnight cycle may notice this sentence is a claim and queue it as a proposed take. You never had to decide that up front.

inboxpageslugsync statetakes

B — You ask the brain something you can't answer yourself

the daily loop · you

Two verbs, two different jobs. Reach for the wrong one and you'll misjudge the tool.

  • 1

    When you want raw material to skim — a quote, a citation, a page you know exists:

    gbrain search "consumer AI ideas I dropped"

    Returns ranked pages. No LLM cost. Each result carries an evidence tag saying why it matched.

  • 2

    When you want the answer:

    gbrain think "which consumer AI ideas did I abandon,
                 and what was the common reason?"

    Same retrieval, then a written answer with citations — and a note on what the brain doesn't know. That last part is the differentiator: it tells you when a page is stale, when two pages contradict, when there's a hole.

  • 3

    When a result surprises you, ask why it ranked where it did:

    gbrain search "…" --explain     # every boost that fired
    gbrain search diagnose "…" --target writing/no-way-back
pagelinksfederationsourceschema pack

C — Claude Code writes something back mid-session

continuous · the agent

This is where the graph actually grows, and it costs nothing. The trigger is a line in your CLAUDE.md telling the agent to search first and write decisions back.

  • 1

    You settle something out loud: “we're dropping the second podcast season, the transcripts are worth more as atoms.”

  • 2

    The agent calls put_page and writes a page containing a wikilink:

    # decisions/2026-08-08-podcast-s2.md
    Dropping season two of [[projects/podcast]]. The dozen existing
    transcripts are more valuable mined as atoms than extended.
  • 3

    The auto-linker fires on the save. It finds [[projects/podcast]] and writes a typed link row. Zero LLM calls — this is pattern matching.

    If that page didn't exist, a stub is created. Point at something absent and the graph grows a node for it.

  • 4

    From then on, anything asking about the podcast surfaces this decision through a backlink — not because the words matched, but because the two pages are factually connected.

pagelinksslugremote

D — An essay you wrote becomes a scored prediction

weeks to months · overnight, then you

The longest loop in the system and the one nothing else in a notes stack does. It only works because a take carries a weight and a date.

  • 1

    You wrote an essay months ago containing a real claim — “Hong Kong's tech scene won't recover without unlocking the tools, not the funding.” It is prose. Nothing is tracking it.

  • 2

    Overnight, propose_takes reads your prose and pulls out the gradeable claims. It does not write them into your brain — they land in a review queue.

  • 3

    You review, and the ones you accept get written into a ## Takes fence:

    gbrain takes propose      # accept / reject the queue

    Now it is a take: holder self, kind bet, a weight, a since-date.

  • 4

    Time passes and evidence accumulates in the brain. grade_takes retrieves what's relevant and asks a judge model to verdict the claim. Auto-resolve is off by default — it proposes a verdict, you keep the call.

  • 5

    Across enough resolved takes, calibration_profile writes the output that matters: two to four sentences describing your standing biases, plus a Brier score. Not what you believe — how your believing performs.

    gbrain takes scorecard
pagetakesfactsschema packlinks

E — Twelve podcast transcripts become findable pieces

one setup, then overnight

Transcripts are the worst-shaped content in any vault: enormous, low signal density, impossible to skim. Atoms are the answer, and they're off by default.

  • 1

    Switch to a schema pack that declares the atom phases. The default pack doesn't, so nothing happens until you do this.

    gbrain config set schema_pack gbrain-creator
  • 2

    Overnight, extract_atoms reads each transcript and pulls one to three typed atoms — an anecdote here, a framework there, a statistic worth reusing. Each becomes its own page. Capped at $0.30 per source per run.

  • 3

    Then synthesize_concepts groups atoms by theme and tiers them by recurrence. A theme you circled ten separate times becomes a tier-one concept page with a written narrative.

  • 4

    The payoff is asymmetric. You can now find the story you half-remember telling without re-listening to an hour of audio — and the tier count tells you which of your themes are actually load-bearing.

atomsconceptsschema packpagesource

F — You add a second source and keep it out of general search

once per repo · you

The moment the brain stops being one pile. Drafts, client work, and anything half-formed belong behind a boundary.

  • 1

    Register the repo as a source inside the same brain:

    gbrain sources add drafts --path ~/brain/sources/drafts
    gbrain sources add code   --path ~/dev/some-project
  • 2

    Turn federation off for the one that should stay quiet:

    gbrain sources drafts --federated false

    Its pages now answer only when you name the source. Unqualified queries behave as if it isn't there.

  • 3

    Drop a .gbrain-source dotfile in each checkout. Now every command you run inside that directory is scoped to it automatically — no flags, ever.

  • 4

    Each source keeps its own sync state, so they import independently and a slow one never blocks the rest.

sourcefederationsync statebrainslug
The one bridge between the two knowledge layers

Facts flow to takes, one way, once a night. The consolidate phase groups your hot facts by entity, deduplicates them against takes that already exist, promotes the durable ones with proper attribution and weight, and marks the originals consumed.

Nothing flows back. A take is never demoted to a fact — which is why gbrain recall (this week's conversation memory) and gbrain takes list (the durable belief record) return genuinely different things and both are worth asking.

<!--- gbrain:section:08 --- setup --->

Setting it up on this machine

macOS 26.5 Tahoe, Apple Silicon. Two things in the standard quickstart do not apply — both are handled below.

Skip every quickstart you'll read

They all begin gbrain init --pglite. PGLite's embedded WASM engine is incompatible with macOS 26.x on Apple Silicon — it crashes. PGLite is also single-writer, so gbrain serve and gbrain sync fight over the write lock. Two independent reasons to go straight to real Postgres.

01

Postgres with pgvector

~15 min

Only libpq (the client) is installed today. This adds the server.

brew install postgresql@17 pgvector
brew services start postgresql@17
createdb gbrain
psql gbrain -c 'CREATE EXTENSION IF NOT EXISTS vector;'
02

Install the CLI

~2 min

From GitHub only. The npm package called gbrain is an unrelated project that will shadow the real binary on your PATH.

bun install -g github:garrytan/gbrain
gbrain --version    # expect 0.42.74.0 or later
03

Set the search mode before anything else

~1 min

gbrain init silently applies tokenmax — the most expensive corner of a 25× spread. Choose deliberately.

ModeHaiku 4.5Sonnet 4.6Opus 4.7
conservative$40/mo$120/mo$200/mo
balanced$100/mo$300/mo$500/mo
tokenmax$200/mo$600/mo$1,000/mo

Figures are per 10,000 queries/month and scale linearly. A personal brain runs a few hundred — divide by 20 or more. conservative is the right default here.

gbrain init
gbrain config set search.mode conservative
gbrain doctor
04

Mirror the vault into a git source

~10 min

gbrain wants a git repo; iCloud Drive is not one, and git inside iCloud corrupts both. Mirror one way — the vault stays the only thing you ever write to, and you get free version history of your notes as a side effect.

mkdir -p ~/brain/sources/noto && cd ~/brain
git init

rsync -a --delete \
  "$HOME/Library/Mobile Documents/com~apple~CloudDocs/Noto/" \
  ~/brain/sources/noto/

git add -A && git commit -m "import vault"
05

Declare what belongs in git

~5 min

Bulk captured material stays searchable but out of the repo. Write ~/brain/gbrain.yml:

storage:
  db_tracked:
    - sources/noto/Writings/
    - sources/noto/Projects/
    - sources/noto/Ideas/
    - sources/noto/Daily Notes/
  db_only:
    - sources/noto/Captures/     # searchable, never in a diff
06

Import, embed, and run the honest test

~20 min

Ask three questions you genuinely cannot answer today. If think doesn't beat ten minutes of manual searching, stop here — don't build the rest on faith.

gbrain import ~/brain/ --no-embed
gbrain embed --stale

gbrain think "what have I written about consumer AI ideas,
             and which ones did I abandon and why?"
gbrain think "what recurring themes run through my essays?"
gbrain think "what did I save about note-taking systems,
             and what's the through-line?"
07

Wire it into Claude Code

~5 min

Then paste the brain-first protocol into your global CLAUDE.md: search the brain before answering or asking; write decisions back with put_page; cite the page you used.

claude mcp add gbrain -- gbrain serve

Note: stdio MCP exposes the unfiltered registry — roughly 120 tools, not the "30+" the README advertises.

08

Earn the graph

half a day

The auto-linker is pure pattern matching on wikilinks — zero LLM calls. A vault with almost no links produces almost no graph. Check the size of the prize before spending on it: doctor reports how many bare links would resolve.

gbrain doctor            # look for link_resolution_opportunity
gbrain config set link_resolution.global_basename true
gbrain extract links --source db --dry-run | head -20
gbrain extract links --source db
gbrain stats             # links should now be > 0
09

Let it run nightly

~5 min

Only after step 6 proved the value and step 8 measured the delta.

gbrain autopilot --install
gbrain autopilot --status
The division of labour worth preserving

Your existing note CLI stays the only writer to the vault — capture doesn't change at all. gbrain reads a mirror and writes only into its own source. Capture surface and query surface stay cleanly separated, and nothing an agent does can corrupt the notes you actually wrote.