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     23 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 install doc says eight phases. src/core/cycle.ts declares twenty-three, 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)
17conversation_facts_backfillllmBulk fact extraction over long-form conversation pages (off)
18enrich_thinllmTrickle-develops a few stub pages per source per tick (off)
19skilloptllmTreats SKILL.md files as trainable parameters (off)
20embedindexEmbed stale chunks
21orphansindexOrphan detection
22schema-suggestllmPassive schema-evolution proposals
23purgeindexHard-delete soft-deleted pages past the 72h recovery window

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 --once. Six are off by default.

The same twenty-three as a flow

A dependency-ordered table hides what is actually happening. The phases group into six movements, and the ordering is load-bearing — each movement consumes the previous one's output.

① HYGIENE      lint · backlinks
                make the markdown well-formed and the link table symmetric
                before anything reads it
       
② INGEST       sync
                git diff → DB. Everything downstream reads DB state, so this
                is the barrier between what's on disk and what the brain knows
       
③ EXTRACT      synthesize · extract · extract_facts · extract_atoms
  structure     · resolve_symbol_edges
                prose → structure: links, timeline entries, the ## Facts fence
                into the facts index, atoms out of transcripts, code symbols
                resolved to chunks. Mostly cheap; extract_atoms is a Haiku pass
       
④ SYNTHESIZE   patterns · synthesize_concepts
  meaning       · recompute_emotional_weight · consolidate
                cross-session themes, atoms clustered into concept pages,
                salience scoring, ephemeral → durable. Sonnet lives here
       
⑤ JUDGE        propose_takes → grade_takes → calibration_profile → drift
  opinion       scan prose for gradeable claims → retrieve evidence → judge
                model verdicts them → aggregate into a profile of your
                standing biases. Three of the four default OFF
       
⑥ MAINTAIN     conversation_facts_backfill · enrich_thin · skillopt
                · embed · orphans · schema-suggest · purge
                backfills, embedding refresh, orphan detection, schema
                proposals, and finally the purge — last, deliberately, so the
                rest of the cycle still sees soft-deleted pages

That gating is the real cost control. gbrain dream with movements ⑤ and ⑥ off is a cheap structural cycle. With them on it is a nightly LLM job over your entire corpus.

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 --->

The cron flows

Scattered across four files and never assembled. The reference schedule runs 20+ jobs. The docs' own advice: don't. Here is what each one actually does, and which three you need.

gbrain does not own scheduling

Start here, because it explains the shape of everything else. gbrain has no scheduler. A native scheduler loop inside gbrain jobs work "has been on the roadmap since v0.11.1 but has not shipped" — that is the convention doc's own wording. Something else owns when: crontab, launchd, Railway cron, the gateway. gbrain supplies only what the trigger does.

WHEN                          WHAT
────                          ────
crontab / launchd    ──────►  gbrain jobs submit <handler>
(host scheduler)               (Minions queue → durable worker)

The one exception is gbrain autopilot, a long-running daemon with its own internal timer. It replaces the host scheduler for maintenance work, and it is the path worth taking.

Three different cycles, and everyone confuses them

CommandPhasesNatureCadence
gbrain sync 1 One-shot. Git diff → DB. No LLM. every 15 min
gbrain autopilot 6 Daemon, adaptive interval. lint · backlinks · sync · extract · embed · orphans continuous, ~300s tick
gbrain dream 23 One-shot, LLM-heavy. The full ALL_PHASES. nightly
Autopilot is not the dream cycle

The 6-vs-23 split is stated exactly once in the entire codebase, in autopilot's own --help: "Runs the full maintenance cycle (lint + backlinks + sync + extract + embed + orphans) on an interval. For a one-shot cron-triggered cycle, see gbrain dream."

Autopilot keeps the index correct. It is plumbing — effectively free, no LLM calls in its six phases. Dream is where the thinking, and the bill, lives. Installing autopilot and assuming you have the compounding brain is the obvious mistake, and nothing warns you off it.

The seven reference flows, and which are actually gbrain

docs/guides/cron-schedule.md presents a seven-job schedule as one system. It is not. Three are gbrain builtins; four are external Node scripts you write, wire, credential and maintain yourself.

BuiltinTriggerThe flowCost
live sync*/15 walk git diff → parse frontmatter → chunk → upsert pages → extract links and timeline → embed only stale chunks free
dream cycle0 2 * * * the twenty-three phases, six movements the whole bill
brain health0 6 * * 1 gbrain doctor --json → warn checks → embed --stale sweeps whatever the incremental path missed free
Recipe (not gbrain)TriggerThe flowNeeds
email → brain*/30 poll inbox → per sender gbrain search "<sender>" → create or update people/ page → append timeline → write digest Gmail/IMAP creds
x → brain*/30 pull timeline and bookmarks → a media/ page each → entity extraction → link into people/ X API access
meeting sync0 10,16,21 * * 1-5 pull transcripts → ingest as meeting pages → attendee propagation: every attendee's page gets a timeline entry pointing back Granola/Zoom
calendar sync0 10 * * 0 last 7 days of events → daily files → enrich attendees Google Calendar
morning briefingdaily AM search calendar attendees, deal status, open threads → compose → deliver, and drain the quiet-hours held queue a delivery channel
Read the second table honestly — it is a VC's day

Attendee propagation, deal status, sender enrichment across thousands of people. That machinery exists because the brain behind it holds 24,585 people and 5,339 companies. A corpus of essays, saved articles, project notes and podcast transcripts has almost no person-entities in it.

Four of the seven reference flows have close to nothing to operate on, and each is a credential plus a script plus a failure mode.

Execution discipline — four rules, one of which bites

Rule 01

Minions, never agentTurn

agentTurn has a 300s timeout, no durability, no transcript. Minion jobs survive a gateway restart, expose duration and token accounting via gbrain jobs get, and accept mid-run steering.

Rule 02

Idempotency key on the slot

The convention doc does the math: a 5-minute cron running 8-minute jobs stacks four overlapping copies at steady state. A key that is stable per slot makes an overlapping fire a noop at the queue layer.

Rule 03

Stagger, never :00

Max one job per five-minute slot, :05 through :50. Everything firing at :00 is an explicit listed anti-pattern.

Rule 04

Quiet hours, and drain the queue

Default 11 PM–8 AM with a user-awake override. Held output lands in /tmp/cron-held/ and must be folded into the next briefing or it is silently lost. Timezone is travel-aware — the agent reads your calendar for flights and shifts quiet hours to follow you.

One 3 AM ping and you'll disable the whole system.

# Postgres — fire-and-forget, dedup at the DB
gbrain jobs submit <handler> \
  --idempotency-key <handler>:$(date -u +%Y-%m-%dT%H:%M)

# PGLite — run inline instead. The exclusive file lock blocks a
# separate worker daemon, so there is nobody to hand the job to.
gbrain jobs submit <handler> --params '{}' --follow

One more thing about handlers: gbrain only auto-rewrites cron entries whose handler is a builtinsync, embed, lint, import, extract, backlinks, autopilot-cycle. Anything else is host code you register yourself via MinionWorker.register(). The shell job type is CLI-only and explicitly rejected over MCP, so a remote agent cannot schedule arbitrary shell.

Budget metering, and the hole in it

Before each subagent submit the meter estimates max cost from model + max_output_tokens, accumulates across the cycle, and refuses the next submit once cumulative exceeds the cap. Every submit is appended to ~/.gbrain/audit/dream-budget-YYYY-Www.jsonl with the estimate and the actual usage when reported back. A cap of zero or negative disables the gate.

Non-Anthropic models bypass the cap entirely

The meter prices against ANTHROPIC_PRICING. Point the dream cycle's subagent at an OpenRouter or OpenAI model and the gate is skipped with a single BUDGET_METER_NO_PRICING warning per process — one line, in a log nobody reads at 2 AM.

If you cap the dream cycle, keep its subagent on an Anthropic model. Otherwise the cap is decorative.

Autopilot — the daemon worth using

gbrain autopilot --install --max-rss 2048   # launchd on macOS
gbrain autopilot --status
Supervision

Child worker, capped

Spawns gbrain jobs work, respawns on crash with a five-crash cap, holds child RSS to 2048 MB. Single-instance lockfile at ~/.gbrain/autopilot.lock, with stale-lock takeover rather than a permanent wedge.

Adaptive

It backs off on its own

Base 300s. After each tick it reads brain_score: ≥ 90 → interval × 2, < 70 → interval ÷ 2 (floor 60s), else unchanged. A healthy brain is left alone; a degraded one is worked harder.

PGLite

Forced inline

Minions dispatch needs minion_mode != off and engine == postgres. On PGLite the cycle runs in the daemon process itself. A hard exit mid-write kills WASM Postgres with a dirty WAL and can corrupt the database, so SIGTERM is handled deliberately.

Upgrades

Opt-in self-upgrade

During idle and quiet hours (self_upgrade.mode=auto), with a boot-time breadcrumb reconciliation so a crash-on-launch after an upgrade is recorded known-bad rather than looping.

For a single laptop this beats hand-rolled crontab: one install buys supervision, locking and a memory ceiling. Given the 31 GB leak that froze this Mac in August, the RSS cap is not a small detail — set it explicitly rather than trusting the default. And note what autopilot never does: it does not run the dream cycle. That stays a nightly line of its own.

Two sync patterns for 2+ sources

With a noto mirror and an agent source, per-source cron lines are the legacy pattern. One consolidated line replaces them and auto-picks-up future sources without a crontab edit:

*/5 * * * * gbrain sync --all --parallel 4 --workers 4 --skip-failed

Watch the connection budget: parallel × workers × 2 ≈ 32 connections during the wave, since every per-file worker opens its own two-connection pool. Homebrew Postgres defaults to max_connections = 100, so this is comfortable. gbrain doctor surfaces the recommended line as a sync_consolidation check once it sees two active sources.

And the anti-wedge pattern, for when a sync starts timing out:

gbrain sync --break-lock --all --max-age 1800
for src in $(gbrain sources list --json | jq -r '.[].id'); do
  timeout 600 gbrain sync --source "$src" --timeout 540 || true
done

--timeout firing mid-import exits 0 with status partial and leaves last_commit unchanged, so the next run re-walks the same diff and content_hash short-circuits whatever already landed. The outer timeout(1) does the OS-level kill 60s after gbrain's own graceful stop.

What I would actually schedule

Not the reference schedule. Three lines and a daemon.

# Vault → git mirror. One-way; rsync never writes back into iCloud.
*/15 * * * *  rsync -a --delete \
                "$HOME/Library/Mobile Documents/com~apple~CloudDocs/Noto/" \
                "$HOME/brain/sources/noto/" \
              && git -C "$HOME/brain" add -A \
              && git -C "$HOME/brain" commit -q -m "vault sync $(date -u +%FT%TZ)" || true

# Nightly dream — structure only to start. Movements ①–④ on, ⑤–⑥ off.
0 2 * * *     gbrain dream >> ~/.gbrain/logs/dream.log 2>&1

# Weekly health.
0 6 * * 1     gbrain doctor --json >> ~/.gbrain/logs/doctor.log 2>&1

Plus gbrain autopilot --install --max-rss 2048 handling sync, extract, embed and orphans continuously — which is why the */15 line above is only rsync-and-commit. gbrain notices the new commits on its own tick.

What to deliberately not run, and why:

The honest summary

Of the twenty-odd jobs a "production brain" runs, three plus a daemon is the right starting shape — and roughly what the reference doc would say if it were not written for a 146,000-page brain.

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

Seven 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

G — You ask the brain to write a page it doesn't have yet

on demand · you, or nobody

The generative direction. Not "find me the page" but "make me a page" — out of pages that already exist, out of something new, or out of both. There is no single verb for this. There are five paths, and they differ on two axes: who does the synthesising, and where the new information is allowed to come from.

  • 1

    Pick the path by those two axes. This is the whole decision:

    PathSynthesised byNew info fromLands at
    put_pagethe agent anywhere — you, the web, a sessionany slug you choose
    gbrain enrichgbrain, one grounded call per page nowhere — brain-internal onlythe thin page, developed
    enrich skillthe agent web searchpeople/ · companies/
    brainstorm · lsdgbrain, bisociation + judge your own forgotten pagesideas/<date>-…md
    book-mirrorfan-out to Minions one source document + youmedia/books/<slug>-personalized.md
  • 2

    The agent writes it. Claude Code composes the markdown and put_page stores it. One call chunks the body, embeds it, reconciles tags, and — when auto_link and auto_timeline are on — extracts the wikilinks into graph edges and the dated lines into timeline entries. The page is queryable on the next breath, not the next sync.

    Provenance is server-stamped for anything remote. A write-scope OAuth token cannot claim source_kind: capture-cli — only a trusted local caller (the capture CLI, autopilot, the dream cycle) may set its own provenance. Audit-trail spoofing is closed structurally rather than by validation.

  • 3

    gbrain writes it out of itself. gbrain enrich takes a thin stub and develops it into a real cited page by consolidating what the brain already knows about that entity — scattered mentions, inbound-link context, facts, the existing stub — in one grounded LLM call per page. Explicitly no web lookup; that is the agent-driven skill's job, not this one.

    gbrain enrich --types note,project --order inbound-links \
                  --limit 20 --model anthropic:claude-haiku-4-5 \
                  --max-usd 2 --dry-run

    Enriched pages carry enriched_at / enriched_by frontmatter that survives write-through, and the recency guard reads it so a re-run skips anything touched inside --reenrich-after.

  • 4

    gbrain writes it out of a collision. brainstorm pulls a close-set for your question via hybrid search and a far-set via a prefix-stratified domain bank, crosses them, and judges the results on a five-axis rubric. Every idea cites its close and far slugs with a 0–1 distance score, so you can see how far the collision actually travelled. Saves to a page by default.

    gbrain lsd is the same engine with the distance dial maxed: bigger far-bank, smaller close-set, forgotten pages preferred via a stale-bias signal, and an inverted judge that rejects ideas scoring too high on coherence — "too obvious, you'd have thought of this without LSD." Every idea must invert at least one implicit axiom. Ephemeral unless you --save.

    gbrain brainstorm "what's the real bottleneck on X?"   # ~$0.05–0.15
    gbrain lsd        "the unspoken assumption in X" --save # ~$0.20–0.40
  • 5

    Nobody asks — it happens at 2 AM. The dream cycle produces pages you never requested: synthesize_concepts clusters atoms and tier-promotes them into concept pages, and consolidate promotes hot facts into durable takes. This is the same flow with the trigger removed, which is the entire argument for running the nightly cycle at all.

  • 6

    Whichever path wrote it, four rules govern where it lands and whether it should exist. These are stated as mandatory in skills/_brain-filing-rules.md, and they are the difference between a brain and a folder of generated text.

Rule 01

File by primary subject

Not by format, not by source, not by the skill that ran. An article about a person goes to people/, not sources/. A reusable thesis goes to concepts/. The test: what would you search for to find this again?

Rule 02

The notability gate

Not everything deserves a page. The instruction is blunt: when in doubt, DON'T create. A missing page can be created later. A junk page wastes attention and degrades search quality.

Rule 03

Iron Law of back-linking

Every mention of an entity that has a page must produce a link both ways — new page to entity, entity back to new page. An unlinked mention is a broken brain. The graph is the intelligence.

Rule 04

Cite, and rank the sources

Every fact carries an inline [Source: …]. Precedence runs: your direct statements → compiled truth → timeline evidence → external lookup, lowest. When sources conflict you record both citations. Never silently pick one.

pagelinkstimelinechunkstagsprovenance
The guard that makes this trustworthy

gbrain enrich takes a --min-context threshold: below that many characters of retrieved context, the page is skipped, never fabricated. The system would rather leave a stub thin than invent a plausible one.

That single default is what separates "the brain wrote me a page" from "the brain hallucinated me a page," and it is worth checking is still set before you point any of this at a corpus you intend to trust later.

Where this lands hardest on 816 unread captures

gbrain lsd is the one built for exactly that pile. It prefers pages you have forgotten, and it throws away any idea coherent enough that you would have reached it unaided. A capture folder nobody revisits is not dead weight to it — it is the raw material it specifically wants.

Two caveats before running it. gbrain enrich defaults to --types person,company, and a corpus of essays and saved articles has neither — pass the types your own schema pack actually declares. And the default save path comes from the bundled pack's taxonomy, not yours, so check where a --save actually lands before generating in bulk.

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.