* v0.40.6.0 Phase 1 foundations — pack-lock + mutate-audit + cache invalidation + lint rules + best-effort
Six new primitives that Phase 2's withMutation skeleton (next commit) depends on.
No consumers yet; all callers wire up in Phase 4. Foundations ship first per
codex C1 phase-ordering finding from /plan-eng-review.
1.1 pack-lock.ts (18 cases)
Atomic acquire via openSync(path, 'wx') = O_CREAT|O_EXCL. Kernel-level
atomic, NO TOCTOU window. Codex C8 caught that page-lock.ts:79+96 has
existsSync+writeFileSync (TOCTOU) — we deliberately do NOT copy it.
Stale detection via TTL (60s default) + kill(pid, 0) liveness probe.
TTL refresh every 10s while withPackLock(fn) runs so long DB-aware
lint/stats on big brains don't go stale. --force = "steal stale lock"
(NOT "skip locking"). Lock path per-pack so two packs never block.
1.2 mutate-audit.ts (13 cases)
ISO-week JSONL at ~/.gbrain/audit/schema-mutations-YYYY-Www.jsonl.
Privacy redacted per D20: type names → sha8, prefixes → first slug
segment only. Matches candidate-audit.ts privacy posture. Both verbose
surfaces gate on GBRAIN_SCHEMA_AUDIT_VERBOSE=1 (same env). Logs BOTH
success AND failure events so Phase 9's schema_pack_writability doctor
check has signal to read (closes codex C11). summarizeMutations()
primitive shipped for cross-surface parity between doctor + future
audit CLI.
1.3 registry.ts cache invalidation + stat-mtime TTL (10 cases)
invalidatePackCache(name?) walks the extends-chain reverse-graph
(every cached entry whose chain contains name is evicted). This is the
codex C6 fix — pre-v0.40.6, editing a parent pack silently left
children stale because cache identity was child-bytes-only. New
per-name CacheEntry tracks the file-stat snapshot of every file in
the extends chain. tryCachedPack(name) is the TTL-gated fast path:
inside STAT_TTL_MS (1000ms default, env GBRAIN_PACK_STAT_TTL_MS)
returns cached without statting. Outside the window: stats every file
and cascade-invalidates on any mtime change (D11 cross-process
detection). resolvePack reference-equality preserved on byte-identical
re-build. ASCII state-machine diagram in file header (D9).
1.4 best-effort.ts (4 cases)
loadActivePackBestEffort(ctx) returns ResolvedPack | null. Single
source of truth for the 4 T1.5 wiring sites (Phase 8). null means
"EMPTY FILTER" semantics, NOT "fall back to hardcoded defaults" —
pack-load failure must be loud, per D4. Never throws.
1.5 lint-rules.ts (35 cases)
11 pure rule functions extracted from CLI handlers per codex C13/D16.
9 file-plane rules + 2 DB-aware rules (extractable_empty_corpus, mutation_count_anomaly).
Phase 2 withMutation pre-write gate composes file-plane subset.
runAllLintRules() returns {ok, errors, warnings} structured report
ready for CLI + MCP.
1.6 query-cache-invalidator.ts (4 cases)
invalidateQueryCache(engine, sourceId?) DELETEs query_cache rows so
cached search results bound to old page types don't survive a
schema mutation. Reuses SemanticQueryCache.clear() so we don't
reinvent the PGLite+Postgres parity. Codex C9 fix.
Tests: 84 new cases across 6 test files. All 153 schema-pack tests green.
Plan: ~/.claude/plans/system-instruction-you-are-working-recursive-thacker.md
Closes: half of T2-T7 from the plan's Implementation Tasks JSONL.
Successor to: closed PR #1321 (community PR; author garrytan-agents).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* v0.40.6.0 Phase 2 — mutate.ts withMutation skeleton + 11 primitives
Builds on Phase 1 foundations (pack-lock, mutate-audit, lint-rules,
cache invalidation, query-cache-invalidator).
withMutation(packName, opts, mutator, op, ctx): 8-step skeleton wrapping
every primitive. Atomic .tmp+fsync+rename. Per-pack file lock. Pre-write
file-plane lint validation gate. Audit log on success AND failure. Pack
cache + query cache invalidation hooks. ASCII state-machine diagram in
file header per D9.
11 primitives, each ~5-line wrapper around withMutation:
add_type, remove_type (with codex C14 reference check), update_type
add_alias, remove_alias, add_prefix, remove_prefix
add_link_type (rejects fm_links refs on remove)
remove_link_type, set_extractable, set_expert_routing
Inline minimal JSON→YAML emitter so mutating a YAML pack stays YAML.
The emitter's array-of-mappings nesting was tricky: the first key sits
inline with the `- ` (e.g. `- name: person`), subsequent keys live at
indent+1, and nested arrays inside the mapping keep their relative
depth (the v0.40.6 emitter bug I fixed pre-commit: trim+prefix lost
internal indent of nested arrays like path_prefixes).
YAML round-trip: emitted YAML reparses cleanly through parseYamlMini.
Comments and formatting NOT preserved (documented in plan; pin pack.json
if you care about layout).
Codex C14 reference check: removeType refuses if any other type's
aliases/enrichable_types/link_types/frontmatter_links references the
target. STILL_REFERENCED error names every reference for cleanup.
Validation gate composes runFilePlaneLintRules from Phase 1.5 — a
mutation that would create a dangling ref or prefix collision fails
BEFORE the .tmp write (the invariant: pack file on disk is NEVER
partial).
Tests: 34 cases pinning every primitive + skeleton invariant. Bundled
guard, codex C14, atomicity (crash-mid-write leaves original untouched,
lock auto-released after mutator throw), YAML round-trip, validation
gate firing on prefix collision.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* v0.40.6.0 Phase 3 — stats + sync pure core functions
Both ship as runStatsCore / runSyncCore pure functions so Phase 4 CLI
handlers (next commit) and Phase 7 MCP ops (later) both compose without
duplicating logic. Codex C13 / D16 prereq for the MCP exposure phase.
stats.ts (17 cases):
Multi-source aware: sourceIds[] (federated read) OR sourceId (single)
OR neither (whole-brain aggregate). NULLIF(type, '') normalizes
empty-string + NULL to one untyped bucket (pages.type is NOT NULL in
the schema so empty string is the legacy "untyped" representation).
Soft-delete exclusion. by_type sorted by count desc, ties by name asc.
Empty-brain coverage:1.0 (vacuous truth, matches getBrainScore).
Dead-prefix detection: pack-declared prefixes with zero matching
pages surface as DeadPrefixHint[] (agent's drilldown signal for
mis-declared paths). Best-effort: pack-load failure leaves
pack_identity:null + dead_prefixes:[].
sync.ts (13 cases):
D14 chunked UPDATE: 1000-row batches per prefix. Each batch:
WITH win AS (SELECT id FROM pages WHERE untyped+prefix LIMIT $batch),
upd AS (UPDATE ... WHERE id IN win RETURNING 1) SELECT COUNT(*). Loop
until zero rows. Concurrent writers never block on the row-set for
more than ~100ms per batch (vs the multi-second monolithic UPDATE
shape PR #1321 had).
Codex C5 write-side scoping: sourceId param directly, NOT
sourceScopeOpts which is read-side and inherits OAuth federation
reads. Phase 7 MCP op (schema_apply_mutations) enforces at dispatch.
Dry-run by default: per-prefix probe returns would_apply + 10-slug
sample (the drilldown signal). Apply path returns total_applied.
Idempotency contract pinned: second apply finds zero matching rows.
Soft-delete exclusion on both probe + update. Dead-prefix flag set
when probe returns count=0. JSON envelope schema_version:1.
Tests use canonical PGLite block per CLAUDE.md test-isolation rules.
seedPage helper auto-seeds sources(id) row before FK insert.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* v0.40.6.0 Phase 4 — wire 14 new schema CLI verbs
Thin handlers wrapping Phase 2's mutation primitives + Phase 3's
stats/sync cores. CLI is the human surface; Phase 7 wires the same
cores into MCP for agent use.
New verbs:
Authoring:
add-type <name> --primitive P --prefix dir/ [--extractable]
[--expert] [--alias A]* [--pack <name>]
remove-type <name> [--pack <name>]
update-type <name> [--extractable BOOL] [--expert BOOL]
[--primitive P] [--pack <name>]
add-alias <type> <alias> [--pack <name>]
remove-alias <type> <alias> [--pack <name>]
add-prefix <type> <prefix> [--pack <name>]
remove-prefix <type> <prefix> [--pack <name>]
add-link-type <name> [--inverse V] [--page-type T] [--target-type T]
[--pack <name>]
remove-link-type <name> [--pack <name>]
set-extractable <type> BOOL [--pack <name>]
set-expert-routing <type> BOOL [--pack <name>]
Activation:
reload [--pack <name>] Flush in-process cache; --pack scopes
Discovery + repair:
stats [--source <id>] Per-type counts + coverage + dead prefixes
sync [--apply] [--source <id>] Backfill page.type (chunked UPDATE)
cli.ts: schema added to CLI_ONLY_SELF_HELP so `gbrain schema --help`
routes to printHelp() instead of the generic one-line stub.
withConnectedEngine defensive fix retained from PR #1321:
EngineConfig built once and passed to BOTH createEngine and
engine.connect for future-proof against engine implementations that
read URL at connect time.
End-to-end agent journey verified:
fork gbrain-base mine → use mine →
add-type researcher --primitive entity --prefix people/researchers/
--extractable --expert →
active (shows 23 page types) →
stats (shows 100% coverage on empty brain, vacuous truth).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* v0.40.6.0 Phase 5+6+7 — schema lint with rich rules + 9 new MCP ops
This is the marquee commit: Wintermute and any other remote OAuth agent
can now author + introspect schema packs over normal HTTPS MCP. Phases
5+6 collapse into Phase 7 because the new MCP ops compose Phase 1.5's
lint rules and Phase 2/3's mutation/stats/sync cores directly — no
extra extraction needed (D6 from /plan-eng-review).
Phase 5: schema lint CLI wired to runAllLintRules from Phase 1.5
Replaces the prior 2-rule check (duplicate names + missing prefix)
with the full 11-rule suite. New --with-db flag opts into the 2
DB-aware rules (extractable_empty_corpus, mutation_count_anomaly).
JSON envelope shape stable. Exit code 1 on any error.
Phase 7: 9 new MCP operations
Read-scope (NOT localOnly — read scope is safe to expose remote):
get_active_schema_pack — identity packet (pack name, sha8, counts).
list_schema_packs — bundled + installed names.
schema_stats — composes runStatsCore from Phase 3.
schema_lint — composes runAllLintRules; --with-db is
CLI-only (DB-aware rules need engine).
schema_graph — JSON {nodes, edges} from link_types
inference + frontmatter_links.
schema_explain_type — settings for one declared type.
schema_review_orphans — untyped pages drilldown.
Admin-scope (NOT localOnly per D2 — Wintermute reaches via OAuth):
schema_apply_mutations — BATCHED per D10. Single MCP tool taking
a mutations[] array; composes all 11
mutate primitives. Atomic batch_id; outer
withPackLock wraps the whole batch so no
other writer can slip in mid-iteration.
Partial-results returned on mid-batch
failure for forensic agent debugging.
Audit log records actor=mcp:<clientId8>
(D20 privacy-redacted shape).
reload_schema_pack — flush in-process cache + extends-chain
cascade (codex C6 fix from Phase 1.3).
withConnectedEngine defensive fix applied to schema.ts:withConnectedEngine
(PR #1321 closed) — EngineConfig built once and passed to BOTH
createEngine AND engine.connect for defense in depth.
Test seams:
- operationsByName lookup pinned for every new op.
- All 9 ops have scope + localOnly declarations pinned to lock in
the trust posture.
- Batched mutation atomicity tested: partial-failure returns
{error: mutation_failed, partial_results: [...]} with one batch_id
across all results.
- Audit log actor=mcp:<clientId.slice(0,8)> capture verified
end-to-end (audit JSONL read back after the op handler runs).
- Empty mutations[] rejected with invalid_request.
- Unknown op surfaced via SchemaPackMutationError INVALID_RESULT.
Coverage: 23 new cases for the 9 ops (operations-schema-pack.test.ts).
All 255 schema-pack-related tests green.
Plan: ~/.claude/plans/system-instruction-you-are-working-recursive-thacker.md
Successor to: closed PR #1321.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* v0.40.6.0 Phase 8 + 10 + 12 — T1.5 wiring, schema-author skill, ship
Final wave commit. Brings the cathedral from "shipped but undiscoverable"
to "shipped + agents find it + agents use it."
Phase 8 (partial T1.5 wiring — agent-facing surfaces):
- whoknows CLI (src/commands/whoknows.ts:340) consults the active pack
via loadActivePackBestEffort + expertTypesFromPack. Pack-load failure
→ EMPTY filter (NOT hardcoded ['person', 'company'] defaults) per
D4. A researcher type declared --expert in a custom pack now
surfaces in `gbrain whoknows "ML"` results. Pre-v0.40.6 it silently
never matched.
- find_experts MCP op (src/core/operations.ts:2820) same wiring so
OAuth clients (Wintermute etc.) inherit pack-aware expert routing
over HTTP MCP, not just CLI.
- facts/eligibility.ts and enrichment-service.ts union widening
deferred to v0.40.7+ (filed in TODOS.md as 2 follow-up entries) —
larger blast radius than fit this wave's context budget.
Phase 10 (skill + RESOLVER + Convention — the discoverability layer):
- skills/schema-author/SKILL.md — agent dispatcher for "evolve the
schema pack." 36 trigger phrases route here. Explicit Non-goals
section names brain-taxonomist (filing one page) and eiirp
(schema-check during iteration) so agents pick the right surface.
7-phase workflow: brain → assess → propose → apply → sync → verify
→ commit. Lists every gbrain schema CLI verb + every MCP op the
skill uses. brain_first: exempt frontmatter (this skill IS the
brain-first path for schema authoring).
- skills/conventions/schema-evolution.md — decision tree for "when to
add a type vs alias vs prefix." <20 pages → don't pack-codify;
20-100 → alias or narrow prefix; 100+ → first-class type. Don'ts
section + "when to remove a type" + "when to commit the pack" all
answered from one place.
- skills/RESOLVER.md entry with full functional-area dispatcher line
(compressed routing pattern per v0.32.3 dispatcher convention).
- schema-evolution.md added to the cross-cutting Conventions list.
Phase 12 (ship bookkeeping):
- VERSION → 0.40.6.0
- package.json → 0.40.6.0
- CHANGELOG.md entry with ELI10 lead per CLAUDE.md voice rules
(250+ words explaining the wave in plain English before any
file/function name appears), full "To take advantage of v0.40.6.0"
paste-ready commands block, itemized changes by category, credit
to @garrytan-agents (PR #1321 author).
- TODOS.md gains 10 new follow-up entries grouped under
"v0.40.6.0 Schema Cathedral v3 follow-ups (v0.40.7+)" covering:
enrichment-service union widening, facts/eligibility wiring, 3
doctor checks, T16 + T16.1 evals, T19 federated closure, T20
extends merging, T21 YAML comments, T22 admin SPA, T23
schema:write scope, T24 multi-tenant federation.
- llms-full.txt regenerated via bun run build:llms (CLAUDE.md
edits trigger the test/build-llms.test.ts gate — required per
repo discipline).
Verification:
- bun run typecheck clean.
- Full agent journey smoke-tested end-to-end in Phase 4 commit
(fork → use → add-type → active → stats — all green).
- All 255+ schema-pack tests green from Phases 1-7.
Total wave: 6 commits, ~5000 net LOC, 84 new tests, 21 design
decisions captured. PR #1321 closed with successor pointer comment.
Plan: ~/.claude/plans/system-instruction-you-are-working-recursive-thacker.md
Co-Authored-By: garrytan-agents <garrytan-agents@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ci): rename Wintermute → 'your OpenClaw' + add schema-author skill conformance
CI failures from PR #1327 first run:
1. check:privacy script flagged 4 'Wintermute' name leaks (CLAUDE.md:550 rule —
never use the private OpenClaw fork name in public artifacts):
- src/core/operations.ts:3816 → 'your OpenClaw and similar remote agents'
- src/core/operations.ts:4015 → 'your OpenClaw, etc.' (in description)
- src/core/operations.ts:4225 → 'your OpenClaw, etc.' (in comment)
- test/operations-schema-pack.test.ts:325 → clientId 'remoteAgentClient12345678'
(matching audit-actor regex updated: 'mcp:remoteAg' instead of 'mcp:wintermu')
2. skills/manifest.json missing schema-author entry. Added between
brain-taxonomist and skillify per alphabetical-ish grouping.
3. skills/schema-author/SKILL.md missing 3 conformance sections per
test/skills-conformance.test.ts:
- ## Contract (inputs/outputs/side effects/idempotency/trust/atomicity)
- ## Anti-Patterns (don't mutate bundled packs, don't add types for one-off
directories, don't conflate filing vs. schema authoring, etc.)
- ## Output Format (per-mutation JSON, per-batch JSON, stats JSON, sync
dry-run JSON, human format, error envelope codes)
The 3 sections were inserted ABOVE the existing 'Failure modes' section so
the existing failure-mode bullets are still adjacent to the new error
envelope codes in Output Format.
Verified locally:
- bun run check:privacy → clean
- bun test test/skills-conformance.test.ts test/check-resolvable.test.ts test/check-resolvable-cli.test.ts test/regression-v0_22_4.test.ts → 286/286 pass
- bun test test/operations-schema-pack.test.ts → 23/23 pass
- bun run verify → clean (privacy + skill_brain_first + fuzz-purity + typecheck)
llms.txt + llms-full.txt regenerated.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: v0.40.7.0 — schema cathedral v3 README + CLAUDE.md annotations
Doc-debt cleanup from the v0.40.7.0 ship (Phase 12 had deferred these to
fit context budget; /document-release surfaced the gap):
- README.md: new "What's new in v0.40.7.0" lead paragraph above the
v0.36.4.0 entry. ELI10 lead: "Your agents can now author your brain's
schema pack themselves" + the agent journey + 14 CLI verbs + 9 MCP
ops + schema-author skill boundary callouts.
- CLAUDE.md: new "Schema Cathedral v3 (v0.40.7.0)" section between the
thin-client routing cluster and the Commands section. 14-bullet
Key Files cluster covering pack-lock / mutate-audit / registry /
best-effort / lint-rules / query-cache-invalidator / mutate / stats /
sync / schema.ts CLI / operations.ts MCP / whoknows T1.5 wiring /
schema-author skill / schema-evolution convention. Each bullet
references the design decisions (D2/D4/D6/D8/D9/D10/D11/D13/D14/D20)
and codex findings (C5/C6/C8/C9/C13/C14) captured during /plan-eng-review.
Closes the "CLAUDE.md has zero v0.40.7.0 mentions" doc debt.
- llms-full.txt + llms.txt regenerated.
Privacy check clean (no Wintermute leaks in the new prose — used "your
OpenClaw" per CLAUDE.md:550 rule). test/build-llms.test.ts 7/7 green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: tutorial — Build your first schema pack (closes v0.40.7+ doc-debt)
Closes the tutorial gap surfaced by /document-release's Diataxis coverage
map. The schema-pack cathedral shipped with reference (CLAUDE.md cluster),
how-to (SKILL.md 7-phase workflow), and explanation (conventions/
schema-evolution.md decision tree), but no tutorial — no concrete
"your first schema mutation" walkthrough.
docs/schema-author-tutorial.md ships exactly that:
- 8 numbered steps, time-to-first-result < 3 (active pack visible by step 2)
- Walks from `gbrain schema fork gbrain-base mine` through `add-type
researcher` + `sync --apply` + proving the T1.5 wiring via `gbrain
whoknows` surfacing the new type
- Every step shows the exact command and expected output
- Placeholder pages (alice-example, bob-example, charlie-example) so any
brain can run the tutorial without affecting real content
- "What you built" section recaps state on disk + active wiring
- "Next steps" cover add-link-type, add-alias, lint --with-db, commit to
source control, MCP path for agents
- "Related docs" cross-links to reference (CLAUDE.md cluster) + how-to
(SKILL.md workflow) + explanation (schema-evolution.md)
Cross-linked:
- README.md "What's new in v0.40.7.0" paragraph gets a "Walkthrough:"
pointer at the end
- skills/schema-author/SKILL.md gets a "## Tutorial" callout just above
the workflow phases — agents that hit the skill via RESOLVER routing
see the tutorial pointer first
Closes the Diataxis quadrant matrix to full coverage:
- Tutorial: ✅ docs/schema-author-tutorial.md (NEW)
- How-to: ✅ skills/schema-author/SKILL.md workflow
- Reference: ✅ CLAUDE.md cluster + gbrain schema --help
- Explanation: ✅ skills/conventions/schema-evolution.md
Privacy check clean. Typecheck clean. llms-full.txt regenerated (545KB).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: what-schemas-unlock — the WHY doc (7 use cases + structural argument)
The schema-author tutorial walks through HOW to mutate a pack. This new
doc explains WHY agents and users should care, with concrete killer use
cases on real corpus shapes:
1. The 4000 invisible meetings — untyped pages skip every structural
surface (whoknows, find_experts, recall, think). Adding a `meeting`
type + sync flips them from invisible to queryable. Same content,
completely different agent experience.
2. The founder ops brain — 4 type-adds + 4 link-types build a
CRM-shaped query surface. `gbrain whoknows "Series A SaaS"` routes
through investor + portco specifically; `graph-query` walks intro
chains. Downstream of notes, not parallel to them.
3. The research brain — researcher / paper / lab / grant / dataset
types + cites / authored / uses link verbs turn a reading-list-as-
markdown into a queryable research graph.
4. The legal brain (or anything where claims have numbers) — typed
`damages=5000000`, `filed_date=...` become comparable across pages
of the same type. Generic note systems can't do this because they
don't know which numbers belong to which type.
5. The team brain — each mounted brain has its own schema pack. Two
engineers searching the same brain get DIFFERENT routing because
their personal packs declare different expert types.
6. The agent-co-curates pattern — the NEW thing in v0.40.7.0. Agent
watches your ingestion stream, runs `gbrain schema detect`
periodically, proposes a new type when a pattern accumulates, applies
it via batched MCP `schema_apply_mutations` after one approval.
Brain learns. Audit log captures the agent's client_id as
`actor: mcp:<clientId8>`.
7. Before-vs-after on real content — pick a corpus, note top-3
whoknows results, add the type via sync, re-run. The numerical
delta IS the win.
Then the structural argument: types matter at query time. Untyped
content is invisible content. The schema is queryable AND mutable AND
auditable — that's the production-system difference from "vibes-based
knowledge management."
Closes with the v0.40.7.0-specific list of what changed (withMutation
skeleton, O_CREAT|O_EXCL atomic lock vs page-lock.ts TOCTOU pattern,
privacy-redacted audit log, 9 MCP ops, T1.5 wiring, cross-process
invalidation via stat-mtime TTL gate).
Cross-linked:
- README.md "What's new in v0.40.7.0" paragraph now has both the
"Why it matters:" pointer (this doc) AND the "Walkthrough:"
pointer (tutorial).
- docs/schema-author-tutorial.md opens with "Want the WHY before the
HOW?" link to this doc.
- skills/schema-author/SKILL.md now has a "Tutorial + vision" section
that points at both, with explicit guidance that agents should read
the WHY doc before pitching schema authoring to a user.
177 lines. Privacy check clean. Typecheck clean. llms-full.txt
regenerated (545KB).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: surface schema docs from README Capabilities + Docs index + llms.txt
The two new schema docs were ONLY linked from the v0.40.7.0 "What's new"
paragraph in README. That paragraph will get pushed down by every future
release and become a worse and worse entry point.
Real discovery paths added:
1. README.md `## Capabilities` section — new "Agent-authored schema
(v0.40.7.0)" bullet between "Brain consistency" and "## Integrations".
Permanent home alongside Hybrid search, Self-wiring graph, Minions,
43 skills, Eval framework. Includes the one-paragraph pitch + 3
pointer links (vision / tutorial / agent skill).
2. README.md `## Docs` index — two new lines added at the top of the
list (right after docs/INSTALL.md, before docs/architecture/):
- docs/what-schemas-unlock.md with one-line description
- docs/schema-author-tutorial.md with one-line description
3. scripts/llms-config.ts `Configuration` section — both docs added to
the curated llms.txt entry list so the LLM-readable map points at
them. Sits right after docs/GBRAIN_RECOMMENDED_SCHEMA.md (topical
grouping). includeInFull defaults to true so they ride in the
single-fetch llms-full.txt bundle.
Result: schema docs are now reachable from 5 entry points instead of 1:
- README "What's new" paragraph (release-pinned, will age out)
- README Capabilities bullet (permanent, top-of-funnel)
- README Docs index (permanent, end-of-page reference)
- llms.txt (LLM-readable curated map)
- llms-full.txt (single-fetch bundle for agents)
Also caught 3 leftover Wintermute leaks in docs/what-schemas-unlock.md
that the privacy check flagged: agent-co-curates pattern now uses "your
OpenClaw"; `register-client wintermute` example renamed to
`register-client my-agent` per CLAUDE.md:550 privacy rule. Privacy
check clean. test/build-llms.test.ts 7/7 green. llms.txt 4314 → 5000
bytes, llms-full.txt 545KB → 572KB.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: garrytan-agents <garrytan-agents@users.noreply.github.com>
15 KiB
What schemas unlock
Most note-taking apps treat every page the same. You write something, it goes in a pile, you search the pile with text matching. Tags help, but tags are flat. After a few thousand pages, the pile gets noisy and the search gets stupid.
Schemas are how gbrain stops being a pile of notes and becomes something with structure. A schema declares what KINDS of things live in your brain (person, company, meeting, researcher, case, lab-result), what they link to (attended, authored, prescribed-by), what facts the system should extract automatically (mrr=50000, damages=5000000), and which types route through expert search vs general search.
The default schema (gbrain-base) ships with 22 page types covering the universal shapes — people, companies, meetings, notes, daily, calendar events. That's enough to start. But your brain is yours, and your brain's shape is not the default shape. A research brain needs researcher and paper as first-class types. A founder brain needs lead, investor, portco, deal-stage. A lawyer brain needs case, motion, deposition, precedent. Same engine, totally different shape.
v0.40.7.0 made it possible for AGENTS to author that shape for you. Not just "the user manually edits YAML in ~/.gbrain/schema-packs/mine/pack.yaml" but "your agent sees the corpus, proposes a type, asks for approval, applies it atomically with a full audit trail, then backfills 4000 existing pages with one chunked SQL command." That's the new thing.
This doc is the WHY. The tutorial is the HOW.
Killer use cases
1. The 4000 invisible pages
You have 4000 markdown files under meetings/ going back two years. The default schema doesn't have a meeting type, so all 4000 are typed note (the catchall). When you run:
gbrain whoknows "Q3 roadmap discussion"
You get the top 10 text matches, ranked by raw relevance. The brain has no idea these are meetings. It can't route to attendees. It can't pull dates. It can't surface "this conversation came up again with the same people three weeks later."
Add a meeting type:
gbrain schema add-type meeting --primitive temporal --prefix meetings/ --extractable
gbrain schema sync --apply
The sync backfills page.type = 'meeting' on all 4000 pages in 1000-row batches. Now:
gbrain whoknows "Q3 roadmap discussion"routes through the meeting type, ranking byexpert_routingsignal (attendees, recency, salience) instead of raw text.gbrain extract-factsruns on every meeting page automatically (becauseextractable: true), pulling typed facts likeattended_by=alice-example,date=2026-05-23.- The downstream
thinkskill can now answer "what did we decide about pricing in the last three roadmap meetings" by querying the meeting graph instead of grep'ing 4000 files.
One command. 4000 pages went from invisible to queryable. The content didn't change. The structure did.
2. The founder ops brain
You're a founder or investor with ~500 markdown files mixing leads, portfolio companies, deal notes, intros, and follow-ups. You've been writing freely; you have no system. Your queries are all "wait, who introduced me to that fintech founder again?" and you scroll Notion for 20 minutes.
Add the founder shape:
gbrain schema fork gbrain-base mine
gbrain schema use mine
# Types
gbrain schema add-type lead --primitive entity --prefix people/leads/ --expert
gbrain schema add-type investor --primitive entity --prefix people/investors/ --expert --extractable
gbrain schema add-type portco --primitive entity --prefix companies/portco/ --expert --extractable
gbrain schema add-type deal --primitive entity --prefix companies/deals/ --extractable
# Link verbs
gbrain schema add-link-type invested-in --page-type investor --target-type portco
gbrain schema add-link-type intro-from --page-type lead --target-type lead
gbrain schema add-link-type passed-on --page-type investor --target-type deal
gbrain schema add-link-type led-by --page-type deal --target-type investor
gbrain schema sync --apply
Now gbrain whoknows "Series A SaaS" routes through investor and portco types specifically, not the noisy general type set. gbrain graph-query alice-example --type intro-from --depth 2 walks two hops of intros to surface "Alice introduced you to Bob who introduced you to Charlie." gbrain extract-facts starts producing typed claims from the fence in your deal pages: (deals/acme-seed, raise=2000000, valuation=15000000, lead=widget-vc, closed_at=2026-05-23).
The CRM you've been promising yourself you'll set up next quarter? You just shipped it in 4 commands. It's downstream of your notes, not parallel to them.
3. The research brain
Replace "founder" with "PhD student" and the same pattern applies with different types: researcher, paper, lab, grant, dataset + authored, cites, funded-by, uses-dataset.
gbrain schema add-type paper --primitive annotation --prefix research/papers/ --extractable
gbrain schema add-link-type authored --page-type researcher --target-type paper
gbrain schema add-link-type cites --page-type paper --target-type paper
gbrain schema add-link-type uses --page-type paper --target-type dataset
Suddenly "show me papers that cite this work AND use the same dataset" is a gbrain graph-query traversal, not 30 minutes in Google Scholar. The fact extraction picks up arxiv_id=2402.04253, cited_by_count=140, published_date=2026-02-15 automatically. Your reading-list-as-markdown turns into a queryable research graph that knows who works on what and what's connected to what.
4. The legal brain (or any domain where claims have numbers)
Lawyers, medical providers, accountants, anyone working in a domain where the meaning of a number depends on its type. A "judgment of $5M" against a "$2M case strategy threshold" is a comparison the brain can do — but only if both numbers are typed.
gbrain schema add-type case --primitive entity --prefix legal/cases/ --extractable --expert
gbrain schema add-type motion --primitive annotation --prefix legal/motions/ --extractable
gbrain schema add-type deposition --primitive annotation --prefix legal/depositions/ --extractable
gbrain schema add-link-type filed-in --page-type motion --target-type case
gbrain schema add-link-type cites --page-type motion --target-type precedent
Now ## Facts fences in your case notes can carry typed claims (damages=5000000, filed_date=2026-05-23, judge=jane-doe) that gbrain stores as first-class columns. gbrain eval trajectory legal/cases/acme-v-widget prints the case history with regressions flagged. gbrain founder scorecard (renamed for legal: roll up plaintiff success rate, average damages, settlement-vs-trial ratio) gives you a structured view of how your practice is performing.
This isn't possible without typed page kinds. You can write the same prose in any note-taking app. Only gbrain treats the numbers as comparable across pages of the same type.
5. The team brain
gbrain mounts add lets you stack additional brains alongside your personal one. Each mounted brain has its OWN schema pack. The eng team's brain has incident, runbook, service, oncall-rotation. The design team's brain has component, experiment, ab-test, figma-link. The legal team's brain has cases and depositions.
When you query, the schema pack governs how each source's content is routed. An eng query against the mounted eng brain knows that incidents/2026-05-23-db-outage.md is an incident page with severity=p0, mttr=47min, on_call=alice-example — extractable typed facts. Your personal query against the same brain still works, but the routing is sharper because the eng team has invested in their ontology.
The schema is the team's tribal knowledge made explicit. Two engineers on different teams searching the same brain get DIFFERENT routing because their personal packs declare different expert types.
6. The "agent co-curates your ontology" pattern (the new thing)
This is what v0.40.7.0 actually enabled, and what the closed PR #1321 was reaching for.
Your OpenClaw (or any agent connected to your brain over HTTPS MCP with admin scope) watches your ingestion stream. After a week of you dumping notes under garrytan/companies/yc-w24/, the agent runs gbrain schema detect periodically, sees that prefix accumulating, and proposes:
You have 47 pages under
companies/yc-w24/typed ascompany(generic). They share a structural pattern (founder names, raise amounts, batch tag). Should I add ayc-w24-companytype withextractable: trueand the existing aliases pointing back tocompany? I'd backfill the 47 pages and addcohort=W24as a typed fact extracted from each page.
You approve once. The agent calls schema_apply_mutations over MCP with a batch:
{
"pack": "mine",
"mutations": [
{"op": "add_type", "name": "yc-w24-company", "primitive": "entity", "prefix": "companies/yc-w24/", "extractable": true, "expert_routing": true},
{"op": "add_alias", "type": "yc-w24-company", "alias": "company"}
]
}
All inside ONE withPackLock scope, atomic, audited (the agent's client_id captured in the audit log as actor: mcp:<clientId8>). Cache invalidated cross-process. Sync backfills the 47 pages. The brain learned a new category of thing without you having to think about it.
The next time you query "YC W24 companies in fintech", the brain routes through the new type. Six months later when you forget the pattern entirely, the agent reminds you it's there and offers to consolidate it with the W25 batch.
The brain learns. The agent is the curator. You approve, the agent does the work.
7. The before-vs-after benchmark
If you want to FEEL the difference without buying the pitch:
Pick a real corpus you have. Run gbrain whoknows on a topic that should match. Note the top-3 results.
Then run gbrain schema review-orphans --limit 50 --json and look at the untyped pages. If 10+ of them share an obvious prefix that should be a real type, add the type + sync.
Re-run the same whoknows query. Top-3 should shift, because the new type is now routing through expert ranking instead of being lumped into the catchall. The numerical delta IS the win. You can run a tutorial in 5 minutes; this experiment proves it matters on your actual content.
Why this matters
Three things gbrain does that generic note systems can't:
1. The brain knows the difference between a person and an idea. Page-type matters at query time. gbrain whoknows only considers expert_routing: true types. gbrain extract-facts only runs on extractable: true types. gbrain graph-query walks declared link verbs. None of that works on a flat tag system because tags don't have semantics — they're labels. Types are first-class citizens with rules attached.
2. Untyped content is invisible content. If your meetings are typed as note, expert routing skips them, facts extraction ignores them, link inference doesn't fire. They exist on disk and they're indexed for text search, but the structural surfaces (whoknows, find_experts, recall, think) treat them as second-class. Adding a type isn't cosmetic; it's structural promotion.
3. The schema is queryable AND mutable AND auditable. You can ask the brain what its schema looks like (gbrain schema graph), evolve it through 14 atomic CLI verbs + 9 MCP ops with full lock + audit semantics, and recover from any mistake (every primitive has an inverse, plus gbrain schema downgrade restores the previous active pack). This isn't "vibes-based knowledge management." It's a production system with structural integrity guarantees.
What changed in v0.40.7.0 specifically
v0.39.1.0 shipped the schema-pack engine. You could ALREADY fork the bundled pack and edit pack.yaml by hand. What you couldn't do was let an agent author it safely — there were no atomic file locks, no audit log, no MCP exposure, no pack-aware wiring in the query path. The cathedral was built but unreachable from the outside.
v0.40.7.0 closed those gaps:
withMutationskeleton wraps every primitive in 8 ordered safety steps (bundled-guard → lock → read → mutate → validate → atomic write → audit → invalidate). The pack file on disk is never partial. Two concurrent agents can't race.- Per-pack
O_CREAT|O_EXCLatomic lock (not the TOCTOUexistsSync+writeFileSyncpattern from page-lock.ts — codex caught that during plan review). TTL refresh every 10s while a mutation runs;--forcemeans "steal stale lock" not "skip locking." - Privacy-redacted audit log at
~/.gbrain/audit/schema-mutations-YYYY-Www.jsonl. Type names sha8-hashed, prefixes truncated to first segment only. A leaked screenshot of the audit can't reveal sensitive taxonomy likepersonal/oncology/orlegal/depositions/. - 9 new MCP ops including the batched
schema_apply_mutations(admin scope, NOT localOnly — your OpenClaw and any remote agent author packs over normal HTTPS MCP, withclient_idcaptured asactor: mcp:<clientId8>). - T1.5 wiring finally completes for
whoknowsandfind_experts: a customresearchertype marked--expertnow actually surfaces in query results. Pre-v0.40.7 it silently never matched because the query path read hardcoded['person', 'company']. - Cross-process invalidation via stat-mtime TTL gate inside
loadActivePack. Operator runsgbrain schema add-typefrom a terminal; the autopilot daemon picks up the new type within 1 second without a restart.
The cumulative effect: an agent can safely co-curate your ontology with a complete forensic trail. That's the new thing.
Where to start
- Want to see it work in 5 minutes? Run the tutorial. Forks the bundled pack, adds a researcher type, proves the wiring end-to-end.
- Want the agent recipe? Read
skills/schema-author/SKILL.md. 7-phase workflow agents follow when they detect a schema-evolution opportunity. - Want the rules of thumb? Read
skills/conventions/schema-evolution.md. Decision tree for when to add a type vs alias vs prefix. <20 pages don't pack-codify. 100+ pages need first-class types. - Want the architecture? The "Schema Cathedral v3 (v0.40.7.0)" section in
CLAUDE.mdhas the 14-bullet module-by-module breakdown, each citing the design decision and codex finding that motivated it. - Want to set up an agent that co-curates your brain? Run
gbrain auth register-client my-agent --scopes adminto mint an OAuth client your remote agent can use to callschema_apply_mutationsover MCP. The agent then runs detect → suggest → apply on its own cadence and asks you to approve substantive changes.
The killer feature isn't "schemas." Personal knowledge systems have had schemas forever. The killer feature is that your AGENT can shape them safely on your behalf, with structural integrity guarantees that match what you'd expect from a database, not a notes app.
That's what we built. Try it on a corpus you actually have and the numbers go up.