Skip to main content

ModusBrain Installation Verification Runbook

Run these checks after install to confirm every part of ModusBrain is working. Each check includes the command, expected output, and what to do if it fails. The most important check is #4 (live sync). “Sync ran” is not the same as “sync worked.” A sync that silently skips pages because of a pooler bug is worse than no sync at all, because you think it’s working.

1. Schema Verification

Command:
Expected: All checks return "ok":
  • connection: connected, N pages
  • pgvector: extension installed
  • rls: enabled on all tables
  • schema_version: current
  • embeddings: coverage percentage
If it fails: The doctor output includes specific fix instructions for each check. See skills/setup/SKILL.md Error Recovery table.

2. Skillpack Loaded

Check: Ask the agent: “What is the brain-agent loop?” Expected: The agent references MODUSBRAIN_SKILLPACK.md Section 2 and describes the read-write cycle: detect entities, read brain, respond with context, write brain, sync. If it fails: The agent hasn’t loaded the skillpack. Run step 6 from the install paste (read docs/MODUSBRAIN_SKILLPACK.md).

3. Auto-Update Configured

Command:
Expected: Returns JSON with current_version, latest_version, update_available (boolean). The cron modusbrain-update-check is registered. If it fails: Run step 7 from the install paste. See MODUSBRAIN_SKILLPACK.md Section 17.

4. Live Sync Actually Works

This is the most important check. Three parts.

4a. Coverage Check

Compare page count in the DB against syncable file count in the repo:
Then count syncable files:
Expected: Page count in modusbrain stats should be close to the file count. Some difference is normal (files added since last sync), but if page count is less than half the file count, sync is silently skipping pages. If page count is way too low: The #1 cause is an unreachable direct connection on an IPv4-only host. ModusBrain uses the Transaction pooler (port 6543) for reads, but routes migrations, DDL, and sync transactions to a derived direct connection (db.<ref>.supabase.co:5432), which is IPv6-only.
  • On an IPv4-only host, reads work but sync transactions fail and silently skip pages.
  • Fix: set MODUSBRAIN_DIRECT_DATABASE_URL to the Session pooler string (port 5432 on the pooler.supabase.com host, IPv4), or enable Supabase’s IPv4 add-on. Then run modusbrain sync --full to reimport everything.

4b. Embed Check

Expected: Embedded chunk count should be close to total chunk count. If embedded is much lower than total:
If OPENAI_API_KEY is not set, embeddings can’t be generated. Keyword search still works without embeddings, but hybrid/semantic search won’t.

4c. End-to-End Test

This is the real test. Edit a brain page, push, wait, search.
  1. Edit a page in the brain repo (e.g., correct a fact on a person’s page):
  1. Wait for the next sync cycle (cron interval or --watch poll).
  2. Search for the corrected text:
Expected: The search returns the corrected text, not the old version. If it returns old text: Sync failed silently. Check:
  • Is the sync cron registered and running?
  • Is modusbrain sync --watch still alive (if using watch mode)?
  • Run modusbrain config get sync.last_run to see when sync last ran.
  • Run modusbrain sync --repo /data/brain manually and check for errors.
  • If sync errors mention an unreachable host or connection timeout, the direct connection isn’t reachable on IPv4 (see 4a above).

5. Embedding Coverage

Command:
Expected: Embedded chunk count matches (or is close to) total chunk count. If zero or very low: OPENAI_API_KEY may be missing or invalid. Check:
If blank, set the key. Then:

6. Brain-First Lookup Protocol

Check: Ask the agent about a person or concept that exists in the brain. Expected: The agent uses modusbrain search or modusbrain query FIRST, not grep or external APIs. The response includes brain-sourced context with source attribution. If it fails: The brain-first lookup protocol isn’t injected into the agent’s system context. See skills/setup/SKILL.md Phase D.

7. Knowledge Graph Wired

The v0.12.0 graph layer needs to be populated for existing brains. New writes are auto-linked, but historical pages need a one-time backfill. Command:
Expected: Both links and timeline_entries are non-zero (assuming the brain has content with entity references and dated markdown). If it’s zero on a brain with imported content: Run the backfill.
Bonus check — graph traversal works:
Expected: Indented tree of typed edges (--attended-->, --works_at-->, etc.). If the slug has no inbound or outbound links, try a different one or run extract again. If extract finds nothing: Your pages may not use entity-reference syntax. The extractor matches [Name](people/slug), [Name](../people/slug.md), and bare people/slug references. If your brain uses a different format, the auto-link heuristics won’t find them — file an issue with a sample page.

8. JSONB Frontmatter Integrity (v0.12.2)

Postgres-backed brains created before v0.12.2 had double-encoded JSONB columns (frontmatter->>'key' returned NULL, GIN indexes were inert). modusbrain upgrade runs modusbrain repair-jsonb automatically via the v0_12_2 orchestrator. Verify the repair succeeded. Command:
Expected: totalRepaired: 0 across all 5 columns (pages.frontmatter, raw_data.data, ingest_log.pages_updated, files.metadata, page_versions.frontmatter). A zero count means every row is properly-typed JSON objects, not string-encoded JSON. If the count is > 0: The repair didn’t run or was interrupted. Re-run without --dry-run:
Idempotent. PGLite brains always report 0 (unaffected by the original bug). Bonus check — frontmatter-keyed queries actually resolve:
If this returns rows on a brain with person pages, the JSONB path is healthy.

Quick Verification (all checks in one pass)

If all eight return successfully, the installation is healthy. For the full end-to-end sync test (4c), push a real change and verify it appears in search.