Skip to main content

Upgrading Downstream Agents

ModusBrain 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, modusbrain 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

modusbrain upgrade ships the new binary. modusbrain 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 modusbrain v0.10.0 at the top, it doesn’t know about v0.12.0 features. The agent will keep manually calling modusbrain link after every put_page (now redundant — auto-link does it), miss out on modusbrain 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 modusbrain 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 modusbrain link after every put_page, which is now redundant and can cause double-add warnings.
Also update the Iron Law section. If your fork still says “Back-links maintained on every brain write (Iron Law)” without qualification, append:

2. meeting-ingestion/SKILL.md

Where: Append to the end of ### Phase 3: Attendee enrichment. Why: Eliminates redundant modusbrain link calls per attendee (auto-link handles them when the meeting page references attendees as [Name](people/slug)).
Where: In ### Phase 4: Entity propagation, the line “Back-link from entity page to meeting page” can be replaced with:

3. signal-detector/SKILL.md

Where: Append to the end of ### Phase 2: Entity Detection. Why: Same logic as brain-ops — eliminates manual modusbrain link after writing originals/ideas pages that reference people or companies.

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):
New (paste):

After all four diffs are applied

  1. Bump the version banner at the top of each forked file:
  2. Run the v0.12.0 backfill (this populates the graph for your existing brain):
    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:
    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)

The v0_12_2 orchestrator runs modusbrain 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:

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:
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): 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”.

2. enrich/SKILL.md (optional)

Where: Add to the enrichment trigger list.

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

modusbrain upgrade takes 2-5 min on a 46K-page brain (one-time). Runs out-of-process via modusbrain 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 modusbrain 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 MODUSBRAIN_ALLOW_SHELL_JOBS=1 on the worker process, then modusbrain 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-shubham-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:
  4. Watch modusbrain 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 modusbrain crontab-to-minions <file> helper is P1 in TODOS.

v0.16.0: durable agent runtime

v0.15 ships modusbrain agent run / modusbrain 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 modusbrain agent run can insert these rows).
Worker startup prints:

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

Move your custom subagent definitions out of your modusbrain fork and into your own repo as a plugin. Concretely:
modusbrain.plugin.json:
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:
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 modusbrain agent run. The durability is free:
Every turn persists to subagent_messages, every tool call is a two-phase ledger, and modusbrain 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 modusbrain frontmatter validate calls. The CLI covers the seven canonical error classes and ships a --json envelope that’s stable across releases.
For consumers that need the validator inside another script, import from modusbrain’s markdown export instead of duplicating logic:

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 modusbrain CLI. The frontmatter-guard skill lives at skills/frontmatter-guard/SKILL.md and points at modusbrain frontmatter validate / audit / install-hook.

3. Wire the doctor subcheck into your health pipeline

modusbrain 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 modusbrain 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:
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 modusbrain apply-migrations --yes runs the v0.22.4 audit, your agent should read ~/.modusbrain/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 modusbrain 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 modusbrain 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:

v0.36.5.0 — Free-form secret inheritance for shell jobs calling modusbrain CLI

The change. Shell-job params get a new inherit: field. Pass any snake_case config-key name on it; the worker resolves the value from its loadConfig() at child-spawn time and injects it into the child env. Names land in the row; values never persist from inherit:. Validation runs pre-enqueue in both submit paths (CLI + submit_job op), so a malformed payload never lands in minion_jobs.data. Why. Pre-v0.36.5.0, agents that wanted to call modusbrain from shell jobs had to either write database_url to ~/.modusbrain/config.json plaintext or pass env: { MODUSBRAIN_DATABASE_URL: "..." } per-job. Both left plaintext secrets somewhere — disk or DB row. inherit: keeps names in the row and resolves values at spawn time. What your agent can do. inherit: is free-form. Pass any config-key:
The env-key name in the child is derived by uppercasing the config-key: database_urlMODUSBRAIN_DATABASE_URL, anthropic_api_keyANTHROPIC_API_KEY, voyage_api_keyVOYAGE_API_KEY, etc. The validator does NOT police which config keys you inherit — the agent is in the same uid as the worker, so it’s the agent’s call. You can still use env:. v0.36.5.0 does not forbid env:{ ANYTHING }. If you have a reason to put a value in the row plaintext (a non-secret correlation token, or a secret you know is OK to persist), pass it via env:. Prefer inherit: when you want the value out of the row. Worker setup (one-time, per host):
  • modusbrain config set database_url postgresql://... (or any other key you want available for inherit)
  • OR put the key in ~/.modusbrain/config.json directly
  • OR set MODUSBRAIN_DATABASE_URL / DATABASE_URL / per-provider env on the worker process
If the worker can’t resolve a requested name, the validator fail-fasts at submit time with modusbrain config set <X> hint. No more silent “No database URL” failures in child stderr minutes after submission. Also new. A modusbrain doctor check home_dir_in_worktree warns if ~/.modusbrain/ lives inside a git worktree. A retroactive ~/.modusbrain/.gitignore (single line *) is now laid down by every saveConfig() call AND by modusbrain post-upgrade, so existing users get coverage without re-running modusbrain init. Honest scope: the .gitignore covers casual git add but does NOT cover already-tracked files, screenshots, backups, or git add -f. Strategy framing. For agent-to-modusbrain calls, the new canonical guide is docs/guides/agent-to-modusbrain.md. Two distinct surfaces: HTTP MCP via OAuth for ops with MCP equivalents (search, query, put_page, etc.), and shell job + inherit: for localOnly admin ops (sync, embed, dream, doctor, etc.). Not a fallback hierarchy — pick by op. Errors to handle (your agent submits shell jobs; surface these clearly):