Skip to content

Architecture Overview

Eric Mey edited this page Apr 21, 2026 · 2 revisions

Architecture Overview

This page is the 10-minute tour. For the exhaustive design documents, see docs/Musubi/ in the repo — it's an Obsidian vault with one markdown file per spec.

The three planes + two channels

         ┌─────────────────────────────────────────────────────────────┐
         │                        MUSUBI CORE                          │
         │                                                             │
         │   ┌──────────┐      ┌──────────┐      ┌──────────┐          │
   write ─►│ EPISODIC │──┬──►│ CONCEPT  │──┬──►│ CURATED  │─► Obsidian │
         │   └──────────┘  │   └──────────┘  │   └──────────┘  vault    │
         │        ▲        │        ▲        │        ▲                 │
         │        │  mature│ synth  │ gate   │        │                 │
         │        └────────┘        └────────┘        │                 │
         │                                            │                 │
         │   ┌──────────┐                   ┌─────────┴─────────┐       │
         │   │ ARTIFACT │                   │ THOUGHTS (pub/sub)│       │
         │   └──────────┘                   └───────────────────┘       │
         │     blobs                         agent ↔ agent msgs         │
         └─────────────────────────────────────────────────────────────┘

Plane: Episodic

Purpose: the firehose. Every observation, quote, or short thought an agent ingests lands here.

State machine: provisional → matured → demoted.

  • A new row starts provisional. An LLM scores its importance; if the score is low and the row isn't reinforced, it TTL's out.
  • After a dwell window (hours), and if nothing contradicts it, it flips to matured.
  • The retriever only returns matured rows by default — so the firehose doesn't pollute queries while it's still settling.

Storage: Qdrant collection musubi_episodic. Named vectors: dense (BGE-M3), sparse (SPLADE-v3), rerank (BGE-reranker).

Plane: Concept

Purpose: distilled themes. A daily pass clusters recent matured episodics by shared topic + semantic similarity, then asks an LLM to summarise each cluster into a SynthesizedConcept.

Key property: reinforcement, not duplication. If a new cluster is close to an existing concept (cosine ≥ 0.85), the existing concept's reinforcement_count increments and its last_reinforced_at updates — no new row. Over time, the rows that reach high reinforcement counts are the ones your fleet has "learned."

State machine: synthesized → matured → promoted → demoted.

Contradiction detection runs after synthesis: pairs at 0.75 ≤ similarity < 0.85 get asked "consistent or contradictory?" by the LLM; contradictory pairs are blocked from promotion until resolved.

Plane: Curated

Purpose: the human-readable knowledge base. Concepts that pass the promotion gate (reinforcement ≥ 3 AND importance ≥ 6 AND age ≥ 48h AND no active contradiction) get rendered as markdown and written to an Obsidian vault.

The vault is the store of record for curated content. A watcher observes vault edits; changes flow back into Musubi through the vault-sync pipeline. An edit to curated/eric/aoi/api/retrieval.md becomes an update on the corresponding musubi_curated row.

Plane: Artifact

Binary blobs — images, PDFs, audio clips — that episodic or curated rows reference. Stored content-addressed on disk; the database holds a content_sha + metadata only.

Channel: Thoughts

Not a persistent memory plane; a pub/sub channel. Agents send(thought) to a named channel with namespace, from_presence, to_presence, content. Subscribers receive over server-sent events. It's how the fleet talks to itself without a coordinator.

The lifecycle engine

Five sweeps run on cron:

Job Cadence (UTC) What it does
maturation hourly at :13 Scores episodic importance; flips provisional → matured after dwell; TTL's unreinforced provisionals.
synthesis daily 03:00 Clusters matured episodics per namespace, generates concepts, runs contradiction checks.
promotion daily 04:00 Promotes eligible concepts → curated markdown files in the Obsidian vault.
demotion daily 05:00 Soft-deletes episodic/concept rows past their decay window.
reflection daily 06:00 Writes a daily digest markdown back to the vault (what was captured, promoted, demoted, what themes emerged).

Each sweep:

  • Runs per-namespace (so a noisy tenant can't block a quiet one).
  • Is file-locked (/var/lib/musubi/locks/<job>.lock) so two workers don't duplicate work.
  • Emits structured LifecycleEvent rows to a SQLite journal.
  • Is idempotent — re-running on the same window is a no-op.

Implementation lives in src/musubi/lifecycle/.

Retrieval

Three paths:

  • Fast — dense-only kNN on the named dense_bge_m3_v1 vector. Low latency, good for autocomplete-style use.
  • Hybrid — dense + sparse (SPLADE) RRF-blended, optional rerank pass. The default for retrieve.
  • Deep — hybrid + rerank + query expansion via the LLM. Higher latency, better recall on hard queries.

All three honor state filters (default: matured), namespace scoping, and recency decay.

API surface

  • HTTP — FastAPI, OpenAPI 3.1 spec at src/musubi/api/openapi.yaml. Routes under /v1/.
  • gRPC — partial coverage generated from proto/. Same port; protocol negotiated on the connection.
  • SSE — /v1/thoughts/stream for the pub/sub subscription side.

SDK and adapters

  • SDK (src/musubi/sdk/) — the Python client. Depends on types/ only; no server-side code.
  • Adapters (src/musubi/adapters/) — each downstream interface (MCP, LiveKit, OpenClaw) gets its own subdirectory. Adapters import SDK + types only; they do not reach into plane or API code.

The split keeps the core stable while adapters iterate. An adapter change is never a core change.

What Musubi is not

  • It's not a chat history store. Thoughts are ephemeral; curated notes are the persistent layer.
  • It's not a multi-tenant SaaS. Namespacing is there (<tenant>/<presence>) but there's no billing, no per-tenant quotas, no admin UI.
  • It's not a distributed system. Today's releases run single-node; multi-node HA is a post-1.0 design space and will require a real ADR.
  • It's not a vector store — it's a memory server that uses a vector store.

Where to go next

Home

Getting started

Operating

  • Deployment Guide (TBD)
  • The Lifecycle (TBD)
  • Supply Chain & Verification (TBD)

Building

  • SDK Guide (TBD)
  • Adapters (TBD)
  • Writing a new plane (TBD)

Reference

Community

Clone this wiki locally