Files
gbrain/docs/what-schemas-unlock.md
3c1cc8a4d6 v0.40.7.0 Schema Cathedral v3 — agent-on-ramp + production rebuild of PR #1321 (#1327)
* 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>
2026-05-23 16:46:01 -07:00

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 by expert_routing signal (attendees, recency, salience) instead of raw text.
  • gbrain extract-facts runs on every meeting page automatically (because extractable: true), pulling typed facts like attended_by=alice-example, date=2026-05-23.
  • The downstream think skill 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.

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 as company (generic). They share a structural pattern (founder names, raise amounts, batch tag). Should I add a yc-w24-company type with extractable: true and the existing aliases pointing back to company? I'd backfill the 47 pages and add cohort=W24 as 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:

  • withMutation skeleton 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_EXCL atomic lock (not the TOCTOU existsSync+writeFileSync pattern from page-lock.ts — codex caught that during plan review). TTL refresh every 10s while a mutation runs; --force means "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 like personal/oncology/ or legal/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, with client_id captured as actor: mcp:<clientId8>).
  • T1.5 wiring finally completes for whoknows and find_experts: a custom researcher type marked --expert now 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 runs gbrain schema add-type from 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.md has 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 admin to mint an OAuth client your remote agent can use to call schema_apply_mutations over 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.