Files
gbrain/docs/UPGRADING_DOWNSTREAM_AGENTS.md
T
891c28b582 v0.22.4 feat: frontmatter-guard — 0 resolver warnings + validate/audit/install-hook CLI (#448)
* fix: resolve check-resolvable warnings on master

- skills/maintain/SKILL.md: drop "citation audit" trigger; the focused
  citation-fixer skill is the single owner. Silences the MECE overlap
  warning surfaced by src/core/check-resolvable.ts.
- skills/RESOLVER.md: add citation-audit disambiguation row pointing
  citation-fixer (focused fix) and chain-into maintain for broader audit.
  Broaden query triggers ("who is", "background on", "notes on") so
  the failing routing-eval fixtures resolve.
- skills/enrich/SKILL.md: replace inlined Citation Requirements block with
  backtick-wrapped `skills/conventions/quality.md` reference (the format
  extractDelegationTargets recognizes). Silences the dry_violation warning.
- skills/citation-fixer/routing-eval.jsonl: rewrite the two failing fixtures
  to embed "fix citations" verbatim so the substring matcher passes.
- skills/query/SKILL.md frontmatter: mirror the broadened RESOLVER.md
  triggers so the trigger round-trip test passes.

Result: gbrain check-resolvable reports 0 warnings, 0 errors against
the actual checked-in skills/ tree.

* feat: extend parseMarkdown + lint with frontmatter validation surface

Add an opt-in validation surface to parseMarkdown(): when called with
{ validate: true }, returns errors[] populated with seven canonical
ParseValidationError codes:

  MISSING_OPEN, MISSING_CLOSE, YAML_PARSE, SLUG_MISMATCH,
  NULL_BYTES, NESTED_QUOTES, EMPTY_FRONTMATTER

Existing callers are unaffected — validation is opt-in via the new
opts argument. The validation logic lives here as the single source of
truth for what counts as malformed brain-page frontmatter.

src/commands/lint.ts now consumes parseMarkdown(..., { validate: true })
and emits stable lint rule names (frontmatter-missing-close,
frontmatter-yaml-parse, frontmatter-null-bytes, frontmatter-nested-quotes,
frontmatter-slug-mismatch, frontmatter-empty). MISSING_OPEN is suppressed
to avoid double-reporting with the legacy no-frontmatter rule.

Tests: test/markdown-validation.test.ts (NEW, all 7 codes) +
test/lint-frontmatter.test.ts (NEW, lint integration + suppression).

* feat: add brain-writer.ts orchestrator (scan / autoFix / writeBrainPage)

Thin orchestrator (~280 lines) on top of parseMarkdown(..., {validate:true})
and isSyncable() (the canonical brain-page filter from src/core/sync.ts).
Three consumers call into this module: the gbrain frontmatter CLI, the
frontmatter_integrity doctor subcheck, and the v0.22.4 migration audit
phase. Single source of truth — no parallel validation stack.

Public API:
  - autoFixFrontmatter(content, opts?): { content, fixes }
    Mechanical auto-repair for the fixable subset (NULL_BYTES,
    MISSING_CLOSE, NESTED_QUOTES, SLUG_MISMATCH). Idempotent.
  - writeBrainPage(filePath, content, opts): path-guarded, .bak backup
    before any in-place mutation. Path guard refuses writes outside
    sourcePath. .bak is the safety contract for non-git brain repos.
  - scanBrainSources(engine, opts?): walks every registered source via
    direct SQL on sources.local_path, uses isSyncable() to filter,
    blocks symlinks (matches sync's no-symlink policy), respects
    AbortSignal.

The dirty-tree guard from src/core/dry-fix.ts:getWorkingTreeStatus() is
NOT used here — it rejects non-git repos as unsafe, but brain repos
aren't always git repos. .bak backups are the contract that works
universally.

Tests: test/brain-writer.test.ts (NEW, 16 cases) — autoFix idempotency,
path-guard reject, .bak backup, per-source rollup, AbortSignal mid-scan,
single-source filter, missing-source-path graceful skip, symlink no-loop.

* feat: gbrain frontmatter CLI (validate / audit / install-hook)

New top-level command surface for the frontmatter-guard feature:

  gbrain frontmatter validate <path> [--json] [--fix] [--dry-run]
    Validate one .md file or recursively scan a directory. --fix writes
    .bak then rewrites in place. No git-tree-clean guard — .bak is the
    safety contract (works for both git and non-git brain repos).

  gbrain frontmatter audit [--source <id>] [--json]
    Read-only scan via scanBrainSources(). Per-source rollup grouped by
    error code. --fix is intentionally NOT available here; use validate
    --fix on the source path to repair.

  gbrain frontmatter install-hook [--source <id>] [--force] [--uninstall]
    Drops a pre-commit hook in each source that's a git repo (skips
    non-git sources with a one-line note). Hook script gracefully
    degrades when gbrain is missing on PATH (prints a warning, exits 0).
    Refuses to clobber existing hooks without --force; writes <hook>.bak.
    --uninstall reverses cleanly.

src/cli.ts wires frontmatter through handleCliOnly so --help works
without a DB connection. The audit subcommand instantiates an engine
internally only when needed.

Tests: test/frontmatter-cli.test.ts (NEW, 9 cases) +
test/frontmatter-install-hook.test.ts (NEW, 6 cases) — --help no-DB,
clean/broken validate, --fix dry-run, --fix non-git, --json envelope,
recursive directory scan with isSyncable filter parity, hook install
+ overwrite-protection + --force + --uninstall + silent-refresh.

* feat: doctor frontmatter_integrity subcheck

Adds a frontmatter_integrity subcheck under gbrain doctor that calls
scanBrainSources() (the same shared scanner the CLI and migration use).
Reports per-source counts grouped by error code, with a fix hint
pointing at `gbrain frontmatter validate <path> --fix`. Wrapped in
a doctor progress phase with heartbeat so 50K-page brain scans stay
visible.

Tests: test/doctor.test.ts (UPDATE) — assertion that the subcheck
calls scanBrainSources and the fix hint references the correct CLI.

* feat: frontmatter-guard skill (registered in manifest + RESOLVER)

New skill at skills/frontmatter-guard/SKILL.md that wraps the gbrain
frontmatter CLI for agent-driven workflows. Agent-agnostic — no
references to private host libraries. Registered in skills/manifest.json
and skills/RESOLVER.md (the trigger row was added in the Part A commit).

Triggers: "validate frontmatter", "check frontmatter", "fix frontmatter",
"frontmatter audit", "brain lint".

Includes routing-eval fixtures that pass the substring matcher. The
SKILL.md has the conformance-required Output Format and Anti-Patterns
sections. Anti-patterns explicitly call out: don't auto-fix MISSING_OPEN
or EMPTY_FRONTMATTER without user input, don't skip .bak backups, don't
install the pre-commit hook on non-git brain dirs.

* feat: v0.22.4 migration orchestrator (audit-only, source-aware)

Adds the v0.22.4 migration that surveys every registered source for
frontmatter issues and queues per-source repair commands without ever
mutating brain content. Three idempotent phases:

  - schema: no-op (no DB changes in v0.22.4)
  - audit: scanBrainSources() across ALL registered sources; writes
    JSON report to ~/.gbrain/migrations/v0.22.4-audit.json
  - emit-todo: appends one entry per source-with-issues to
    ~/.gbrain/migrations/pending-host-work.jsonl, each with the exact
    `gbrain frontmatter validate <source-path> --fix` command

The agent reads skills/migrations/v0.22.4.md after upgrade, surfaces
the report counts to the user, and runs the fix command only with
explicit consent. `apply-migrations --yes` never silently rewrites
brain pages.

Filename convention: TS orchestrator at v0_22_4.ts (underscores, since
TS module paths can't have dots); user-facing migration doc at
skills/migrations/v0.22.4.md (dotted, matches existing convention).
The pending-host-work.jsonl skill field references the dotted-path doc.

Skips cleanly when no sources are registered (fresh install).

Tests: test/migrations-v0_22_4.test.ts (NEW, 9 cases) + updated
test/migration-orchestrator-v0_21_0.test.ts to allow v0.22.4 after,
test/apply-migrations.test.ts skippedFuture arrays extended to include
v0.22.4, test/check-resolvable.test.ts regression guard asserting the
actual checked-in skills/ tree has 0 warnings + 0 errors.

* docs: pre-commit recipe + downstream agent upgrade notes for v0.22.4

- docs/integrations/pre-commit.md (NEW): recipe doc covering install,
  bypass (`git commit --no-verify`), uninstall, and downstream-fork
  integration notes. Includes the full pipeline diagram showing how
  the hook (write-time gate), doctor (audit gate), and CLI (fix tool)
  share parseMarkdown(..., {validate:true}) as the single source of
  truth.
- docs/UPGRADING_DOWNSTREAM_AGENTS.md: append v0.22.4 section with the
  diff pattern for forks that had inline frontmatter validators. Covers
  the five upgrade actions: replace ad-hoc validators, drop
  lib/brain-writer.mjs references (it never shipped), wire the doctor
  subcheck into custom health pipelines, optionally install the
  pre-commit hook on git-backed brain repos, and walk
  pending-host-work.jsonl after apply-migrations.
- llms.txt + llms-full.txt: regenerated from build:llms script after
  the new docs landed.

* chore: bump version and changelog (v0.22.4)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: handle null loadConfig() return in frontmatter + migration paths

CI typecheck caught three call sites that passed loadConfig()'s
GBrainConfig | null result straight into toEngineConfig() (which
expects GBrainConfig, not null):

  - src/commands/frontmatter.ts:64 (audit subcommand connect)
  - src/commands/frontmatter-install-hook.ts:86 (install-hook connect)
  - src/commands/migrations/v0_22_4.ts:59 (audit phase connect)

The frontmatter CLI and install-hook paths follow the existing
src/commands/repair-jsonb.ts pattern: throw 'No brain configured. Run:
gbrain init' so users get an actionable message instead of a TS-shaped
runtime crash.

The v0.22.4 migration audit phase takes a different shape: a fresh
install or test environment running apply-migrations shouldn't fail
hard just because there's no brain to scan yet. Return a clean
'skipped: no_brain_configured' phase result so the orchestrator
continues normally and the ledger records a complete (skipped) run.

* test: add v0.22.4 migration E2E + injection point for testability

Closes plan item B14 (the E2E that was promised but not delivered before
the original ship). Runs the v0_22_4 orchestrator end-to-end on PGLite
against a fixture brain with two registered sources and synthetic
malformed pages on disk. Asserts:

  - audit phase writes ~/.gbrain/migrations/v0.22.4-audit.json with
    per-source counts (NESTED_QUOTES + NULL_BYTES on alpha,
    NESTED_QUOTES on beta)
  - emit-todo phase appends one entry per source-with-issues to
    pending-host-work.jsonl, each pointing at skills/migrations/v0.22.4.md
    with the exact `gbrain frontmatter validate <source> --fix` command
  - the migration is audit-only — no fixture page is mutated
    during apply-migrations (no .bak created, contents byte-identical)
  - re-running the orchestrator is idempotent — JSONL stays at 2 lines

Adds a small test-injection point to v0_22_4.ts:
  __setTestEngineOverride(engine: BrainEngine | null): void

Mirrors src/commands/repair-jsonb.ts pattern. When set, phaseBAudit
uses the injected engine instead of loadConfig + createEngine. Production
path is unchanged: the override is null by default and the existing
loadConfig logic runs end-to-end. Required because Bun's os.homedir()
does not observe mid-process process.env.HOME mutations, so we can't
redirect loadConfig's config-file lookup via env-var overrides; the
injection point is the only hermetic way to E2E-test the orchestrator
without writing to the user's real ~/.gbrain/config.json.

Test runs unconditionally in CI's Tier 1 (no DATABASE_URL needed,
PGLite in-memory).

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-26 20:45:05 -07:00

22 KiB

Upgrading Downstream Agents

GBrain ships skills in skills/. Downstream agents (custom OpenClaw deployments, agent forks of any kind) often copy these skill files into their own workspace and diverge over time — adding agent-specific phases, removing irrelevant ones, tightening language. Once that happens, gbrain can't push updates to those forks. The agent has to apply the diffs by hand.

This doc lists the exact diffs each downstream agent needs to apply when upgrading. Cross-reference against your fork's local skill files.

Why this exists

gbrain upgrade ships the new binary. gbrain post-upgrade [--execute --yes] runs the schema migrations and backfills the data. But the skill files themselves that tell the agent how to behave — those are user-owned. If your ~/git/<your-agent>/workspace/skills/brain-ops/SKILL.md says # Based on gbrain v0.10.0 at the top, it doesn't know about v0.12.0 features.

The agent will keep manually calling gbrain link after every put_page (now redundant — auto-link does it), miss out on gbrain graph-query for relationship questions, and not know to backfill the structured timeline.

How to apply

  1. Identify your forked skill files. Typically at ~/git/<your-agent>/workspace/skills/ or wherever your agent's skill directory lives.
  2. For each skill listed below, find the matching phase/section in your fork.
  3. Apply the diff (paste the new block in the indicated location).
  4. Update the version banner at the top of your fork (# Based on gbrain v0.12.0).
  5. Verify: ask the agent to write a test page and confirm the response includes auto_links: { created, removed, errors }.

Total time: ~10 minutes for all four skills.


1. brain-ops/SKILL.md

Where: Insert a new ### Phase 2.5 section immediately after ### Phase 2: On Every Inbound Signal.

Why: Phase 2.5 declares that auto-link runs automatically. Without this, the agent's mental model says it must call gbrain link after every put_page, which is now redundant and can cause double-add warnings.

### Phase 2.5: Structured Graph Updates (automatic)

Every `put_page` call automatically extracts entity references and writes them
to the graph (`links` table) with inferred relationship types. Stale links
(refs no longer in the page text) are removed in the same call. This is
"auto-link" reconciliation.

- No manual `add_link` calls needed for ordinary page writes.
- Inferred link types: `attended` (meeting -> person), `works_at`, `invested_in`,
  `founded`, `advises`, `source` (frontmatter), `mentions` (default).
- The `put_page` MCP response includes `auto_links: { created, removed, errors }`
  so the agent can verify outcomes.
- To disable: `gbrain config set auto_link false`. Default is on.
- Timeline entries with specific dates still need explicit `gbrain timeline-add`
  (or batch via `gbrain extract timeline --source db`).

Also update the Iron Law section. If your fork still says "Back-links maintained on every brain write (Iron Law)" without qualification, append:

**v0.12.0 update:** Auto-link satisfies the Iron Law for entity-reference links
on every `put_page`. The agent's Iron Law obligation is now: include the
entity reference in the page content (e.g., `[Alice](people/alice)`); auto-link
handles the structured row. Manual `add_link` calls are reserved for
relationships you can't express in markdown content.

2. meeting-ingestion/SKILL.md

Where: Append to the end of ### Phase 3: Attendee enrichment.

Why: Eliminates redundant gbrain link calls per attendee (auto-link handles them when the meeting page references attendees as [Name](people/slug)).

**Note (v0.12.0):** Once the meeting page is written via `gbrain put`, the
auto-link post-hook automatically creates `attended` links from the meeting
to each attendee whose page is referenced as `[Name](people/slug)`. You don't
need to call `gbrain link` for attendees. You DO still need `gbrain timeline-add`
for dated events (auto-link only handles links, not timeline entries).

Where: In ### Phase 4: Entity propagation, the line "Back-link from entity page to meeting page" can be replaced with:

4. Entity references in the meeting page body auto-create the link via auto-link.
   For incoming references on the entity page (entity page → meeting page), edit
   the entity page to mention the meeting and `put_page` it — auto-link handles
   the rest.

3. signal-detector/SKILL.md

Where: Append to the end of ### Phase 2: Entity Detection.

Why: Same logic as brain-ops — eliminates manual gbrain link after writing originals/ideas pages that reference people or companies.

**Auto-link (v0.12.0):** When you write/update an originals or ideas page that
references a person or company, the auto-link post-hook on `put_page`
automatically creates the link from the new page to that entity. You don't
need to call `gbrain link` manually. Timeline entries still need explicit calls.

4. enrich/SKILL.md

Where: Replace ### Step 7: Cross-reference with the v0.12.0 version.

Why: Step 7 used to be primarily about creating links between related entity pages. With auto-link, that's automatic. Step 7 is now about content updates, not link creation.

Old (delete):

### Step 7: Cross-reference

- Update company pages from person enrichment (and vice versa)
- Update related project/deal pages if relevant context surfaced
- Check index files if the brain uses them
- Add back-links manually via `gbrain link` for any new entity references

New (paste):

### Step 7: Cross-reference

- Update company pages from person enrichment (and vice versa)
- Update related project/deal pages if relevant context surfaced
- Check index files if the brain uses them

**Note (v0.12.0):** Links between brain pages are auto-created on every
`put_page` call (auto-link post-hook). Step 7 focuses on content
cross-references (updating related pages' compiled truth with new signal
from this enrichment), not on creating links. Verify via the `auto_links`
field in the put_page response (`{ created, removed, errors }`).
Timeline entries still need explicit `gbrain timeline-add` calls.

After all four diffs are applied

  1. Bump the version banner at the top of each forked file:

    # Based on gbrain v0.12.0 skills/<skill-name>, extended with <your-agent>-specific config
    
  2. Run the v0.12.0 backfill (this populates the graph for your existing brain):

    gbrain post-upgrade
    

    The v0.12.0 release wires post-upgrade to call apply-migrations --yes automatically, which runs the v0_12_0 orchestrator (schema → config check → extract links --source dbextract timeline --source db → verify). Idempotent; cheap when nothing is pending.

  3. Verify auto-link works: ask the agent to write a test page that references [Some Person](people/some-person). Confirm the put_page response includes auto_links: { created: 1, removed: 0, errors: 0 }.

  4. Verify graph traversal works:

    gbrain graph-query people/some-well-connected-person --depth 2
    

    Should return an indented tree of typed edges.


v0.12.2 hotfix (data-correctness, no skill edits)

v0.12.2 is a Postgres data-correctness hotfix. No forked skill files need to change — the skill contracts are unchanged. But you DO need to run the migration, and you should know about one behavior change in markdown parsing.

1. Run the migration (Postgres-backed brains)

gbrain upgrade

The v0_12_2 orchestrator runs gbrain repair-jsonb automatically. It rewrites rows where jsonb_typeof = 'string' across pages.frontmatter, raw_data.data, ingest_log.pages_updated, files.metadata, and page_versions.frontmatter. Idempotent, safe to re-run. PGLite brains no-op cleanly.

Verify after upgrade:

gbrain repair-jsonb --dry-run --json    # expect totalRepaired: 0

2. Recover any truncated wiki articles

If your brain imported wiki-style markdown before v0.12.2, some pages were silently truncated (any standalone --- in body content was treated as a timeline separator). Re-import from source:

gbrain sync --full

The new splitBody rebuilds compiled_truth correctly.

3. Know the splitBody contract going forward

splitBody now requires an explicit timeline sentinel. Recognized markers (priority order):

  1. <!-- timeline --> (preferred — what serializeMarkdown emits)
  2. --- timeline --- (decorated separator)
  3. --- directly before ## Timeline or ## History heading (backward-compat)

A bare --- in body text is now a markdown horizontal rule, not a timeline separator. If your agent writes pages with a bare --- delimiter, migrate to <!-- timeline --> — the serializeMarkdown helper already does this.

4. Wiki subtypes now auto-typed

inferType now auto-detects five additional directory patterns as their own page types (previously they all defaulted to concept):

Path pattern New type
/wiki/analysis/ analysis
/wiki/guides/ guide
/wiki/hardware/ hardware
/wiki/architecture/ architecture
/writing/ writing

If your skills or queries filter by type=concept and expect wiki content in that bucket, update them to include the new types.


v0.13.0 — Frontmatter Relationship Indexing

Verdict: no action required for most skills. v0.13 projects YAML frontmatter fields into the graph as typed edges. The ingestion API is unchanged — keep calling put_page with frontmatter the way you do today; the graph auto-populates behind the scenes.

Three skills get an optional new phase if you want to consume the new auto_links.unresolved response field. Without this, unresolvable frontmatter names silently skip (same as v0.12 behavior).

1. meeting-ingestion/SKILL.md (optional)

Where: Add a new section after "Phase 3: Write Meeting Page".

### Phase 3.5: Check for unresolved attendees (v0.13+)

After `put_page`, inspect `response.auto_links.unresolved` — an array of frontmatter
references that did not resolve to existing pages. For meetings, this usually means
attendees you haven't created a person page for yet.

If `unresolved.length > 0`:
- Option 1 (create pages now): trigger an enrichment pass to build the missing people pages.
- Option 2 (defer): log the unresolved names to the enrichment queue for later.
- Option 3 (accept the gap): the attendee edge will not be created until a page exists.
  Re-running `gbrain extract links --source db --include-frontmatter` after creating
  the page fills in the missing edges.

2. enrich/SKILL.md (optional)

Where: Add to the enrichment trigger list.

### Drain unresolved frontmatter names (v0.13+)

If any `put_page` response includes `auto_links.unresolved` entries, the enrichment
tier should pick up those (field, name) pairs and try to create the missing entity
pages. Example flow:

1. signal-detector captures a meeting with `attendees: [Alice Known, Unknown Person]`
2. put_page returns `auto_links.unresolved = [{field: 'attendees', name: 'Unknown Person'}]`
3. enrichment tier consumes `Unknown Person` → web search → creates `people/unknown-person.md`
4. The next put_page (or a backfill run) wires up the `attended` edge automatically

3. idea-ingest/SKILL.md (optional)

Where: Same pattern as meeting-ingestion — check auto_links.unresolved after put_page, route names to enrichment.

Unchanged skills (no diffs needed)

  • brain-ops/SKILL.md — auto-link mechanics are internal; the write path stays the same.
  • signal-detector/SKILL.md — signal capture path unchanged.
  • query/SKILL.mdtraverse_graph now returns richer results automatically.
  • daily-task-manager/SKILL.md, briefing/SKILL.md, citation-fixer/SKILL.md, media-ingest/SKILL.md — unchanged.

New edge types you can filter in graph queries

v0.13 edges carry new link_type values. If your fork has graph-query skills that filter by type, these are now available:

  • works_at (person → company) — from company:, companies:, or key_people:
  • founded (person → company) — from founded:
  • invested_in (investor → deal/company) — from investors: or lead:
  • led_round (lead → deal) — from lead:
  • yc_partner (partner → company) — from partner:
  • attended (person → meeting) — from attendees:
  • discussed_in (source → page) — from sources:
  • source (page → source) — from source:
  • related_to (page → target) — from related: or see_also:

Migration timing

gbrain upgrade takes 2-5 min on a 46K-page brain (one-time). Runs out-of-process via gbrain post-upgrade. If your agent holds a DB connection during the upgrade, reconnect after; otherwise keep serving.

Type normalization NOT in v0.13

Legacy rows with link_type='attendee' or link_type='mention' coexist with new 'attended' / 'mentions' rows. Your queries filtering on old type names keep working. A separate opt-in gbrain normalize-types command in v0.14 handles the rename.

v0.14.0 shell jobs (optional adoption, no skill edits)

Adds a shell job type to Minions so deterministic cron scripts (API fetch, token refresh, scrape + write) move off the LLM gateway. Zero tokens per fire. ~60% gateway CPU headroom at typical scale. Feature is off by default, existing installs keep running exactly as they did before. Nothing breaks.

To adopt, follow skills/migrations/v0.14.0.md. The short version:

  1. Set GBRAIN_ALLOW_SHELL_JOBS=1 on the worker process, then gbrain jobs work (Postgres). On PGLite, every crontab invocation uses --follow for inline execution; no persistent worker.
  2. Classify each of your host's cron entries: LLM-requiring (keep on gateway) vs deterministic (candidate for shell). Typical splits:
    • Deterministic → shell: ycli-token-refresh, x-oauth2-refresh, x-garrytan-unified, calendar-sync-to-brain, github-pulse, frameio-scan, flight-tracker, x-raw-json-backfill.
    • LLM-requiring → stay: social-radar, content-ideas, adversary-vacuum, ea-inbox-sweep, morning-briefing, brain-maintenance.
  3. For each deterministic cron, rewrite as:
    3 13,16,19,22,1,4,7,10 * * * \
      gbrain jobs submit shell \
        --params '{"cmd":"node scripts/your-script.mjs","cwd":"/data/.openclaw/workspace"}' \
        --max-attempts 3 --timeout-ms 300000
    
  4. Watch gbrain jobs get <id> for exit_code / stdout_tail / stderr_tail on each fire. Compare against pre-migration behavior before approving the next batch.

No skill edits required. The handler runs worker-side; skill files don't change. If your host exposed custom handlers via the plugin contract (v0.11.0), they still work the same way.

Iron rule: never auto-rewrite the operator's crontab. Every rewrite is per-cron, human-approved, with a diff. If you want automation later, the upcoming gbrain crontab-to-minions <file> helper is P1 in TODOS.


v0.16.0: durable agent runtime

v0.15 ships gbrain agent run / gbrain agent logs, a new subagent handler type in Minions, and a plugin contract for host-repo subagent defs. None of the existing skills need surgery. The question for downstream agents is how to adopt the new runtime, not how to patch around a breaking change.

1. Run a worker with an Anthropic key

The subagent handlers (subagent and subagent_aggregator) are always registered on the worker. No separate opt-in flag — ANTHROPIC_API_KEY is the natural cost gate (no key, the SDK call fails on the first turn), and who-can-submit is already protected (PROTECTED_JOB_NAMES + trusted-submit: MCP callers get permission_denied; only gbrain agent run can insert these rows).

ANTHROPIC_API_KEY=sk-ant-... gbrain jobs work

Worker startup prints:

[minion worker] subagent handlers enabled

2. Ship your subagents as a plugin (OpenClaw + similar)

Move your custom subagent definitions out of your gbrain fork and into your own repo as a plugin. Concretely:

~/<your-agent>/gbrain-plugin/
├── gbrain.plugin.json
└── subagents/
    ├── meeting-ingestion.md
    ├── signal-detector.md
    └── daily-task-prep.md

gbrain.plugin.json:

{
  "name": "your-openclaw",
  "version": "2026.4.20",
  "plugin_version": "gbrain-plugin-v1"
}

Each subagents/*.md is a plain-text agent definition — YAML frontmatter + body-as-system-prompt. Recognized frontmatter fields: name, model, max_turns, allowed_tools (must subset the derived brain-tool registry).

Turn it on:

export GBRAIN_PLUGIN_PATH="$HOME/<your-agent>/gbrain-plugin"

Worker startup prints [plugin-loader] loaded '<name>' v<ver> (N subagents) per plugin; any rejection (bad manifest, unknown tool in allowed_tools, version mismatch) shows up as a loud warning at startup, not a silent dispatch- time failure. See docs/guides/plugin-authors.md for the full contract.

3. Replace ephemeral subagent runs with durable ones

If your agent currently spawns ephemeral subagents (OpenClaw Agent(), ad-hoc Anthropic API calls, etc.) for work that should survive crashes, sleeps, or worker restarts, migrate those to gbrain agent run. The durability is free:

gbrain agent run "analyze my last 50 journal pages for recurring themes" \
  --subagent-def analyzer --fanout-manifest manifests/journal-pages.json

Every turn persists to subagent_messages, every tool call is a two-phase ledger, and gbrain agent logs <job> shows where it died + what the last successful call returned. No more "re-run from scratch because the session context evaporated."

4. put_page from subagents writes under an agent namespace

If you adopted the v0.15 subagent runtime, note that put_page calls originating from a subagent's tool dispatch MUST target wiki/agents/<subagent_id>/.... The schema shown to the model enforces this on first try; a server-side fail-closed check rejects anything else. This does NOT affect your skill files, CLI put_page calls, or MCP put_page — only tool-dispatched writes from inside an LLM loop.

Aggregation output (the final "here's what all N children found" brain page) goes via a separate trusted CLI path, not through a subagent tool call, so it can write anywhere you want.

Iron rule: never grant an agent write access beyond its namespace. The server-side check exists because dispatcher bugs happen; treat it as defense in depth, not the primary boundary.


v0.22.4 — frontmatter-guard adoption

1. Stop hand-rolling frontmatter validators

If your fork has scripts that call js-yaml directly to validate brain page frontmatter, replace them with gbrain frontmatter validate calls. The CLI covers the seven canonical error classes and ships a --json envelope that's stable across releases.

- # Custom validator script
- node scripts/validate-frontmatter.mjs <path>
+ gbrain frontmatter validate <path> --json

For consumers that need the validator inside another script, import from gbrain's markdown export instead of duplicating logic:

import { parseMarkdown } from 'gbrain/markdown';

const parsed = parseMarkdown(content, filePath, { validate: true, expectedSlug });
for (const err of parsed.errors ?? []) {
  // err.code: MISSING_OPEN | MISSING_CLOSE | YAML_PARSE | SLUG_MISMATCH |
  //           NULL_BYTES | NESTED_QUOTES | EMPTY_FRONTMATTER
}

2. Drop any references to lib/brain-writer.mjs

If your fork's skills or scripts referenced an aspirational lib/brain-writer.mjs (it never shipped — the spec was in PR #392 and never landed), replace those references with the gbrain CLI. The frontmatter-guard skill lives at skills/frontmatter-guard/SKILL.md and points at gbrain frontmatter validate / audit / install-hook.

3. Wire the doctor subcheck into your health pipeline

gbrain doctor now reports frontmatter_integrity automatically. If your fork has a custom health pipeline (e.g. a daily Slack post about brain health), pull from gbrain doctor --json and surface the frontmatter_integrity row counts.

4. (Optional) Install the pre-commit hook on brain repos

For sources backed by git, the v0.22.4 install-hook helper drops a pre-commit script that blocks commits with malformed frontmatter:

gbrain frontmatter install-hook

Skip this if your brain isn't a git repo or if your downstream agent already enforces validation at write time. See docs/integrations/pre-commit.md for the full recipe.

5. Migration ergonomics — read pending-host-work.jsonl

After gbrain apply-migrations --yes runs the v0.22.4 audit, your agent should read ~/.gbrain/migrations/pending-host-work.jsonl (filter to migration === "0.22.4") and walk each entry's command field. Each entry points to a per-source gbrain frontmatter validate <source_path> --fix command — surface counts to the user, get explicit consent, then run.

The migration is audit-only. It never mutates brain content during apply-migrations. Your agent runs the fix command with user consent.


Future versions

When gbrain ships a new version, this doc will be updated with the diffs for that version. Each new version appends a section; old sections stay so you can catch up multiple versions at once.

To check what your fork is missing:

diff <(grep -A3 "Based on gbrain" ~/<your-fork>/skills/brain-ops/SKILL.md) \
     <(grep "v[0-9]" ~/gbrain/skills/migrations/ | tail -3)