Brainby arc-labs/docs
Concept

Architecture

Brain is one Rust binary with a strict one-way crate graph — an mmap arena, a WAL, redb, HNSW, tantivy, and bundled models, sharded thread-per-core. No external database.

The single rule that governs every change: dependencies flow downward, never sideways. brain-core has zero I/O dependencies. The write path (brain-ops) depends on storage, metadata, index, and the embed/rerank/llm helpers. The server binary depends on the write and read paths. There is no path from a leaf back up to a binary, and the extraction crates (brain-extractors, brain-llm) are never depended on at the wire or storage layer.

The one-process picture

Brain ships as one binary, brain-server, in one Docker image (brain). There is no Postgres, no pgvector, no Neo4j, no external cache — each process owns its own storage. The connection layer runs on Tokio and accepts TCP; every request is routed to one of N shards. Each shard runs a Glommio executor (thread-per-core, io_uring) and owns the full per-shard state from byte zero.

CONNECTION01 STAGESSHARD N (GLOMMIO)06 STAGESEXTERNAL01 STAGESHyPE + extractionTCP / HTTP edge (Tokio)mmap arena (vectors)WAL (fsync group commit)redb (metadata)HNSW ×3 (RAM)tantivy ×2 (lexical)BGE-small + rerankerLLM provider
One process. The Tokio connection layer fans requests out to N shards; each shard is a thread-per-core Glommio executor owning its own arena, WAL, metadata store, indexes, and models. The only outbound dependency is the LLM provider.

Parallelism is sharding, not a thread pool. Adding cores means adding shards; each shard is single-writer, so writes take no locks and reads use ArcSwap + crossbeam-epoch. Per-shard types are deliberately !Send — the discipline is what makes the lock-free path sound.

What each shard owns

SubsystemBacked byHolds
Vector arenammap file (brain-storage)384-dim f32 vectors in fixed 1600-byte slots
WALpwritev + fdatasync group commitThe durability barrier — no ack before fsync
Metadataredb B-tree (brain-metadata)Memory rows, entities, statements, relations, predicates, audit
Vector searchHNSW in RAM (hnsw_rs)Three indexes: memory, entity, statement
Lexical searchtantivyTwo indexes: memory text, statement text
EmbeddingsBGE-small via candleText → 384-dim vector, in-process
Rerankcross-encoder (bge-reranker-base)Read-time reordering, when loaded
Extraction cacheseparate redbLLM extractor cache

There is no dimension-1536 vector column and no vector() type anywhere — vectors live in the arena as raw bytes; the metadata store is redb, not SQL.

The crate graph

The workspace ships exactly these crates. Adding one requires justification in the commit message.

BINARY02 STAGESPATHS03 STAGESINFRA07 STAGESFOUNDATION02 STAGESbrain-serverbrain-httpbrain-ops (write)brain-planner (read)brain-workersbrain-storagebrain-metadatabrain-indexbrain-embedbrain-rerankbrain-extractorsbrain-llmbrain-protocolbrain-core
Strict one-way dependencies. The server binary depends on the write/read paths and workers; those depend on storage / metadata / index / embed / rerank / llm; everything bottoms out at `brain-core`.
CrateRole
brain-coreShared types — MemoryId, EntityId, StatementId, EdgeKind, Error. Zero I/O deps.
brain-protocolWire protocol — frame, opcodes, CBOR codec, schema DSL parser.
brain-storagemmap arena + WAL + recovery. The only crate allowed unsafe (for mmap).
brain-metadataredb wrapper — memory / entity / statement / relation / predicate / audit tables.
brain-indexHNSW (memory + entity + statement) and tantivy integration.
brain-embedBGE-small embedding service (candle, 384-dim).
brain-rerankCross-encoder reranker (bge-reranker-base) for the read path.
brain-plannerQuery planner + executor — the read pipeline (recall / plan / reason).
brain-opsThe one write path: handlers/ per opcode → apply/ per table → writer/submit, plus the retrievers and extractor writes.
brain-workersBackground workers — auto-edge, temporal-edge, extractor, decay, consolidation, HNSW maintenance, and the rest.
brain-extractorsPattern + classifier extractor tiers.
brain-llmLLM client + cache + budget (the LLM extractor tier and write-time HyPE).
brain-pluginsPlugin surface (enricher + connector) for the knowledge layer.
brain-httpHTTP transport for the operator admin listener.
brain-server (bin)The server binary — wires everything together.

This repo ships the server only. There is no first-party SDK or CLI here; clients speak the wire protocol directly or via the sibling SDK packages. Operators administer over the HTTP edge (brain-http).

The one write path

There is one Write { phases } model, one writer (submit), and one apply layer that dispatches every phase variant. Capabilities differ by which state they touch — memories, entities, statements, relations, edges, schema, audit — not by which "layer" they belong to. A write that references a declared type is accepted; one that references an undeclared type is rejected (explicit create) or dropped (extractor best-effort). The seeded brain: system namespace is active from byte zero, so every shard always has a schema present.

See Write pipeline for the phase-by-phase walk.

Boot requirements

Two things are mandatory at startup, and the shard refuses to spawn without them:

  • An LLM provider API key. Write-time HyPE (hypothetical-question generation) and the LLM extractor tier depend on it, so there is no keyless mode. Set BRAIN__LLM__API_KEY (or [llm] api_key) with a key valid for the provider named in [llm] model. Disabling the LLM extractor tier does not lift the key requirement.
  • The bundled models. The embedder (BGE-small) and the classifier (GLiNER) are hard boot requirements. A capability that fails to load at shard spawn is a hard spawn failure (ShardError::*InitFailed) — the shard refuses to start rather than run with a quietly-missing capability.

The one thing you can turn off at deploy time is the cross-encoder reranker ([rerank] enabled): disabled, no model loads and the read pipeline returns RRF-only ordering. Everything else on the write and read paths is always-on by design — a write step that populated the graph could not be a toggle without silently breaking graph-backed reads. See Policies for the full enable/disable model.

Module rules in one breath

  • brain-core has no I/O — no runtime, no storage, no network.
  • Shards use Glommio; the connection layer uses Tokio. Never mix them: no Tokio inside a shard, no tokio::fs in shard code, no thread pool for parallel work.
  • Per-shard types are !Send. Don't add Send + Sync to them.
  • No lock held across .await; no allocation in the encode/recall hot path.
  • thiserror in libraries, anyhow in binaries. No .unwrap() outside tests.
  • unsafe only in brain-storage, only for mmap, always with a // SAFETY: comment.

Was this page helpful?

On this page