ModusBrain Knowledge Runtime — Design Doc
Status: DRAFT for CEO review. Date: 2026-04-18. Supersedes: The earlier “Feynman Ideas Assessment + Phase A/B” plan.0. Context
During a CEO review of a narrow two-feature plan (bare-tweet citation repair + completeness score, borrowed from Feynman), the scope was reframed. The narrow plan duplicated work OpenClaw already does and missed the real leverage point: the bespoke abstractions hiding inside OpenClaw — resolvers, enrichment orchestration, scheduling, deterministic output — should live in ModusBrain as first-class primitives. North star: “When OpenClaw’s Claw upgrades to this version of ModusBrain, it should immediately recognize brilliance and completeness and say ‘It’s time to switch to these abstractions.’” That is the test this document is designed against. Everything else is downstream.1. The Four Layers
The design is four layered abstractions. Each is independently useful; together they are the Knowledge Runtime.2. Why This Order (L1 → L4)
Every higher layer depends on the lower one. L1 must land first or the rest leaks abstractions.- L1 (Resolvers) is the substrate. Without a uniform lookup interface, every orchestrator + writer has bespoke callers.
- L2 (Orchestrator) uses L1 to fetch; without L1 it’s still ad-hoc.
- L3 (Scheduler) runs L2 periodically; without L2 it’s scheduling nothing structured.
- L4 (Output Builder) is what every layer ultimately writes through; without it we have 14 call sites doing
fs.writeFilewith hand-rolled citation discipline.
3. Layer 1 — Resolver SDK
3.1 What’s broken today
OpenClaw has 69 distinct external-lookup patterns across X API (14 shapes), Perplexity, Mistral OCR, Gmail, Calendar, Slack, GitHub, YouTube, Diarize.io, external tools, OSINT collectors, and brain-local lookups. Each one is a bespoke script underscripts/ with its own error handling, retry logic, and output shape. ModusBrain has 3 ad-hoc wrappers (embedding.ts, transcription.ts, enrichment-service.ts) that don’t share an interface.
Common consequences:
- No uniform retry/backoff strategy (some scripts retry, most don’t)
- No cost tracking (Perplexity bills eaten silently when calls return no-substance results)
- No confidence/provenance propagation (callers can’t tell if an answer is verified or inferred)
- Users can’t add a resolver without forking ModusBrain
3.2 Interface
3.3 Context
3.4 Registry + Factory (mirrors src/core/storage.ts)
3.5 Plugin format (unifies recipes/ + data-research formats)
A plugin is YAML + JS module, discovered via filesystem scan of ~/.modusbrain/resolvers/ and recipes/.
src/commands/integrations.ts pattern: only package-bundled resolvers are embedded=true and may run arbitrary commands; user-provided resolvers are restricted to http and validated schemas.
3.6 Wraps every resolver with FailImproveLoop
Existing src/core/fail-improve.ts is the deterministic-first/LLM-fallback pattern. Every resolver automatically gets wrapped: if the deterministic path (e.g. X API) returns a valid result, use it; if it fails, optionally fall back to an LLM-based resolver; log both paths for future pattern analysis and auto-test generation.
3.7 Reference implementations to ship
The OpenClaw survey inventoried 69 resolver shapes. Shipping all of them is wrong (over-scoped); shipping zero is under-scoped. The dogfood set:
The remaining 63 OpenClaw patterns port incrementally, driven by user need. Each port is a new YAML + module under
recipes/ or ~/.modusbrain/resolvers/ with no framework changes.
4. Layer 2 — Enrichment Orchestrator
4.1 What’s broken today
OpenClaw’s enrichment is polished at the data layer, hacky at the control layer:- Completeness = “length > 500 chars + no
needs-enrichmenttag” (lib/enrich.mjs:351-355). Naïve. A rich page of repetitive Perplexity summaries (seebrain/people/0interestrates.md— 38 repeating blocks) passes this check. - 30-day auto-re-enrichment runs forever. No “done” state. A person met once in 2023 still gets re-researched monthly.
- Cascade is convention-only. Person→company stubs are created automatically; company→investors, company→employees traversals are documented but never implemented.
- No hard budget cap. Cost is estimated per batch, never enforced across batches or per day.
- Failure is silent. A bad Perplexity response logs and continues; partial writes can leave a page with a timeline entry but no raw-data sidecar.
4.2 The orchestrator
4.3 Evidence-weighted completeness (replaces length heuristic)
Completeness is a per-entity-type rubric, stored in frontmatter on write and recomputed on demand.non_redundancy + recency_score explicitly kill the two brain pathologies observed in the audit (Wilco-style repeating blocks; stale pages without last_verified).
The completeness field goes in frontmatter as 0.0–1.0. It becomes queryable via list_pages(where: completeness < 0.5).
4.4 Tier routing with hard budget
Two-dimensional routing: importance (tier 1/2/3 from person-score) × budget state.orchestrator.enrich() returns status: 'budget-exhausted' immediately. No silent overages. Circuit-breaker resets at midnight in the user’s configured TZ.
4.5 Cascade (entity graph traversal)
company: Acme field, cascade checks: does companies/acme exist? If not, create stub + enqueue at tier 2. Does companies/acme link back to X? If not, write the back-link. Iron Law is machine-enforced, not skill-enforced.
4.6 Fail-safe transactions
Every enrichment is wrapped in a BrainWriter transaction (Layer 4). Partial writes are rolled back. No asymmetric state like timeline-entry-without-raw-sidecar.5. Layer 3 — Scheduler
5.1 What’s broken today
OpenClaw’s cron is externally-driven JSON (cron/jobs.json) with ~30 jobs manually stagger-offset at different minutes. ModusBrain has zero native scheduling — src/commands/autopilot.ts is a single daemon loop, and docs/guides/cron-schedule.md is architectural guidance, not code.
Failures observed in OpenClaw’s actual state:
X OAuth2 Token Refresh: 11 consecutive timeouts (critical-path silent failure)flight-tracker daily scan: 5 consecutive timeoutsmorning-briefing: 4 consecutive timeouts- Quiet hours are checked at runtime in skills, so a skill that forgets to check will DM at 3 a.m.
- Staggering is manual convention; no protection against two jobs colliding after a config edit.
5.2 ScheduledResolver interface
5.3 Enforcement vs convention (the key delta from OpenClaw)
5.4 Native engine + OS cron adapter
The scheduler runs as either:- Embedded (default for
modusbrain autopilot): native event loop inside the daemon process. One process, many ScheduledResolvers. - OS-driven (for Railway/launchd/systemd):
modusbrain schedule run <id>invoked by OS cron, scheduler state is durable so cross-invocation dedup still works.
Schedule config + state.
5.5 Observability
Every scheduled run emits structured events:started, skipped-quiet-hours, deferred-to-active-hours, failed-retrying, circuit-opened, completed. Events go to:
~/.modusbrain/scheduler/events.jsonl(local, always)engine.logIngest(audit trail in brain DB)- Optional webhook (Slack/Telegram for the user)
modusbrain doctor reads the event log and reports: current circuit-breaker state, any resolver with > 3 consecutive failures, any resolver that hasn’t fired within 3× its interval (freshness SLA like OpenClaw’s freshness-check.mjs but built-in).
6. Layer 4 — Deterministic Output Builder
6.1 The anti-hallucination invariant
Iron Law: LLM picks WHAT. Code guarantees WHERE and HOW. OpenClaw’s existinglib/enrich.mjs:buildTweetEntry is close to this — tweet URLs are built from tweet.id returned by the X API, never from LLM memory. But:
- A past incident: “Sub-agent test #2 FAILED — hallucinated ‘Philip Leung’ entity links across all daily files. LLM rewriting of daily files is too error-prone.” (OpenClaw memory log, 2026-04-13.)
- Back-links depend on
appendTimelinebeing called everywhere; skips are silent. - Slug collisions are unchecked (no conflict detection on
slugify). - Citation format is post-hoc linted weekly, not pre-write enforced.
6.2 BrainWriter
6.3 Scaffolder — deterministic link + citation construction
Every user-visible URL/link/citation is built by code from resolver outputs, not from LLM text.6.4 SlugRegistry — conflict detection
6.5 Pre-write validators (fail-closed for integrity)
OnWriteTx.validate() before commit:
- Citation validator. Every factual sentence in
compiled_truthmust have an inline[Source: ...]within N lines. Non-compliant paragraphs are flagged. Configurable: strict-mode rejects the transaction, lint-mode warns. - Link validator. Every
[text](path)must point to a page that exists OR to a URL the Scaffolder built (so it’s guaranteed-valid). No raw LLM-composed URLs. - Back-link validator. Every outbound link must have a reverse link written in the same transaction.
- Triple-HR validator. Compiled truth / timeline split enforced at the schema level.
writer.transaction({ strictMode: false }, ...) and logs a warning to the ingest log.
6.6 LLM output sanitization
Any LLM output destined for a brain page passes through a JSON-Schema-validated parser first. No free-form markdown goes to disk.- Entity extraction: JSON array of
{ name, type, context }per existingextractEntitiespattern — strict validation. - Compiled-truth synthesis: LLM emits structured
{ sections: [{heading, paragraphs: [{text, sources: [...]}]}]}, scaffolder renders to markdown. - Timeline entries: LLM emits
{ date, summary, detail, sources }, scaffolder renders.
7. Integration with existing ModusBrain
7.1 Reuse (already polished)
7.2 Replace (ad-hoc today)
7.3 Extend
src/core/engine.ts: addgetResolverRegistry(),getWriter(),getScheduler(). Engine becomes the runtime’s root container.src/core/operations.ts:OperationContextinherits fromResolverContext(or vice-versa). Trust flags unified.src/core/types.ts: addcompleteness: numbertoPage,sourcedBy: string[]for provenance.
8. Migration Path (phased, shippable)
Each phase ships independently, passes full E2E, is feature-flagged, and is reversible. No big-bang.Phase 0 — Foundation (human: ~1 wk / CC: ~4 h)
- Define
Resolver<I,O>,ResolverContext,ResolverRegistry,ResolverResult(§3.2–3.4). - Add
src/core/resolvers/index.tswiring + tests for registry (register/get/list). - No behavioral change; ship as
v0.11.0-alphawith feature flag.
Phase 1 — Three reference resolvers (human: ~1 wk / CC: ~4 h)
- Port
src/core/embedding.ts→resolvers/builtin/embedding/openai.ts. - Implement
resolvers/builtin/brain-local/slug-lookup.ts(wrapsengine.resolveSlugs). - Implement
resolvers/builtin/url-reachable.ts(HEAD-check). - Prove the interface: old callers swap to
registry.resolve('openai_embedding', ...).
Phase 2 — BrainWriter + Slug Registry (human: ~1.5 wk / CC: ~6 h)
- L4 core:
BrainWriter.transaction,Scaffolder,SlugRegistrywith conflict detection. - Pre-write validators: citation, link, back-link, triple-HR.
- Migrate
src/commands/publish.ts+src/commands/backlinks.tsto route through BrainWriter. - Now OpenClaw’s “Philip Leung” hallucination is structurally impossible — LLM output passes through JSON-Schema validator before reaching Scaffolder.
Phase 3 — modusbrain integrity command (human: ~0.5 wk / CC: ~2 h)
- Ship the originally-scoped user-facing feature on top of the new foundation.
- Uses Resolver SDK:
x_handle_to_tweet+url_reachable. - Uses BrainWriter: all auto-repairs go through validated writes.
--auto --confidence 0.8mode as user approved in cherry-pick #1.- User-visible value ships in Phase 3, not Phase 7.
Phase 4 — Enrichment Orchestrator (human: ~2 wk / CC: ~8 h)
- L2 core:
EnrichmentOrchestrator,BudgetLedger,CompletenessScorer,EntityGraph.cascadeFrom. - Migrate
src/core/enrichment-service.tscallers (deprecate the old file after). - Completeness score in frontmatter on every write (dogfooding cascades).
Phase 5 — Scheduler (human: ~2 wk / CC: ~8 h)
- L3 core:
Scheduler,ScheduledResolver,DurableState, circuit breaker, quiet-hours enforcer. - Migrate
src/commands/autopilot.tsto a ScheduledResolver set. - Ship
modusbrain schedule list|run|pause|tailCLI for observability.
Phase 6 — Port 5–8 OpenClaw resolvers (human: ~1.5 wk / CC: ~6 h)
perplexity_query,text_to_entities,mistral_ocr_pdf,x_search_all,x_user_to_tweets,gmail_query_to_threads,calendar_date_to_events.- Each ships as YAML + TS module under
resolvers/builtin/— proof of the plugin format.
Phase 7 — OpenClaw Adoption Integration (human: ~1 wk / CC: ~4 h)
- Write
docs/openclaw/ADOPTION.mdshowing your OpenClaw how to replace its 69 bespoke scripts with calls tomodusbrain registry.resolve(...). - Ship a
modusbrain claw-bridgesubcommand that proxies OpenClaw’s current script invocations to the resolver registry — zero-edit adoption path. - This is the test of the north star. If your OpenClaw can stand up a 1-line shim and drop
scripts/x-api-client.mjs, the abstraction succeeded.
9. Critical Files
New directories / files
Replaced / removed
src/core/enrichment-service.ts— folded intoenrichment/orchestrator.tssrc/core/embedding.ts— moved intoresolvers/builtin/embedding/openai.tssrc/core/transcription.ts— moved intoresolvers/builtin/transcription/
Extended
src/core/engine.ts— addgetResolverRegistry(),getWriter(),getScheduler()src/core/operations.ts— unify with ResolverContext; every operation validator reusable by resolverssrc/core/types.ts— addcompleteness: number,sourcedBy: string[],lastVerified: Date
10. Testing Strategy
Contract tests
Every Resolver implementation tested against the interface spec. Table-driven: run the same suite againstopenai_embedding, x_handle_to_tweet, etc. Ensures plugin authors can’t ship broken resolvers.
Property tests
- Idempotency: running a ScheduledResolver twice with the same state produces the same output and doesn’t double-write.
- Atomicity: a BrainWriter transaction that throws mid-flight leaves the brain bit-for-bit identical to pre-transaction.
- Deterministic scaffolds: given the same resolver outputs, the Scaffolder produces byte-identical citations/links.
Integration tests
EnrichmentOrchestratorend-to-end against PGLite (in-memory, no API keys) with mocked resolver registry.Schedulerwith fake clock + quiet-hours scenarios.- BrainWriter transaction rollback on validator failure.
Chaos tests
- Kill the process mid-enrichment; next run must resume cleanly.
- Simulate API timeout mid-transaction; transaction must roll back completely.
- Corrupted state file; scheduler must escalate, not silently skip.
Regression tests vs. OpenClaw behavior
For each OpenClaw pattern we port (e.g. X-handle → tweet URL), a regression test proves the new resolver produces the same answer on real-world inputs from the brain audit. This is the “your OpenClaw would adopt” proof.11. Open Questions (flagged for CEO re-review)
- Scope shape. Is this the right four-layer decomposition, or are some layers better left to OpenClaw (e.g. Scheduling lives above ModusBrain, not in it)?
- Phase 3 user-value break. Does Phase 3 (user-visible
modusbrain integrity) ship early enough, or do we need an even smaller MVP? - LLM-as-resolver. Should
text_to_entitiesbe a Resolver, or does that blur the “code vs LLM” line the invariant relies on? - Plugin format. YAML + TS module (§3.5) vs. pure TS module with decorator-style metadata. Latter is more type-safe; former is more discoverable.
- Cross-resolver transactions. Do we support “atomic fetch-from-Perplexity + write-to-brain” at the L2 layer? Current design says yes; implementation is tricky (Perplexity call isn’t rollbackable).
- OpenClaw bridge scope. Phase 7
modusbrain claw-bridge— is that worth a phase of its own, or should adoption be documentation-only? - Completeness rubric coverage. Do we define rubrics for all 9 PageTypes upfront, or ship people/company/meeting first and extend incrementally?
- Budget config UX. Hard daily cap is strict; should we also expose a soft-cap warning mode, and how is the cap set (env var? config file? prompt on first use?)
- Backwards compat.
src/commands/publish.tsandsrc/commands/backlinks.tshave been running cleanly for weeks. Refactoring through BrainWriter carries migration risk. Acceptable? - Existing TODOS alignment.
TODOS.mdhas P0 “Runtime MCP access control” and P2 security hardening. The new RuntimeContext.remote flag interacts with both — do we fold MCP access control into Phase 0 or keep separate?
12. Verification (the “your OpenClaw would adopt” test)
The design succeeds iff:- A user can add a new resolver by dropping a YAML + TS module in
~/.modusbrain/resolvers/without editing ModusBrain source. - Your OpenClaw can delete
scripts/x-api-client.mjsand replace all callers with 1-lineawait registry.resolve('x_handle_to_tweet', ...). - No brain page can be written with a bare tweet reference, a missing back-link, or an unverified URL (validators catch it pre-commit).
- Running
modusbrain integrity --auto --confidence 0.8over a real brain fixes ≥1,000 of the 1,424 known bare-tweet citations without human review. - Full E2E test suite passes on both PGLite + Postgres engines.
- The Knowledge Runtime ships across 7 phases with each phase individually shippable and reversible.