Files
zeekay 22cd2c5694 State a version once
A version written into a manifest is written into every manifest that wants it,
which is how eslint came to exist in a hundred and four forms across this estate
and how a package came to resolve twice at run time. The catalog moves the number
out of the manifest: a manifest names the package, the workspace names the
version.

Four are held below their latest because the newer release cannot be used, and
the reason is recorded rather than the version alone: @noble/hashes 2 renamed
every subpath the web3 stack imports, @splinetool/runtime 2 depends on a package
that was never published, @dynamic-labs 5.4.1 the same, and react-resizable-panels
3 points its types condition at the bundle.
2026-08-29 18:13:28 -07:00
..
2026-08-29 18:13:28 -07:00

@hanzo/bot-memory

The Hanzo Brain memory layer. Pluggable BrainStore contract. SQLite default — single file, zero infra. Path shared across every Hanzo SDK at ~/.hanzo/brain/brain.db.

Canonical artifact locations

Every Hanzo SDK on a machine reads/writes the same paths so brains compose across the bot, hanzo-mcp, hanzo-dev, and the Python SDK:

Path What
~/.hanzo/brain/brain.db The brain — pages / edges / facts / FTS5
~/.hanzo/workspace/ Markdown source — auto-ingested
~/.hanzo/config.toml Per-machine bot/mcp config
~/.hanzo/cache/ Embedding cache, tool-output cache
~/.hanzo/logs/ Structured logs

What ships in core

  • SQLite backend (canonical default) — ~/.hanzo/brain/brain.db. FTS5 keyword. Optional sqlite-vec for ANN.
  • Pluggable interface — registerBackend("name", factory). Anyone can ship Qdrant / Meilisearch / Postgres / LanceDB / D1 / libSQL as a sibling extension.

Scale-out backends (sibling extensions, not in core)

Hanzo ships the heavy machinery, all open source — register them by name. Native stack uses ZAP (zero-copy transport) + hanzo-consensus (metastable agent agreement) + zapdb (storage primitives) end-to-end. No libSQL, no Turso — we ship our own.

Backend Repo License Use
qdrant ~/work/hanzo/vector Apache 2 Vector ANN at scale (millions of embeddings, multi-replica)
meilisearch ~/work/hanzo/search MIT Fast keyword FTS when SQLite FTS5 stops being enough
replicate ~/work/hanzo/replicate Apache 2 Background SQLite WAL → S3 backup, point-in-time restore
vfs ~/work/hanzo/vfs Apache 2 S3-backed virtual block FS with PQ encryption — unlimited write storage
zapdb zap-proto/db (canonical, in-flight migration from luxfi/zapdb) Apache 2 The canonical Hanzo storage layer. ZAP-native primitives, multi-language. Currently mirrored at luxfi/zapdb (Go, badger-derived) and ~/work/luxcpp/zapdb (C++) — both moving to zap-proto/db.
luxdb ~/work/lux/database BSD-3 Lux-flavored extension of zapdb. Adds blockchain-specific concerns (chain heads, archival, validator sets) on top of the base zapdb. Don't use for generic brain stores — pick zapdb directly.
postgres (sibling pkg) Multi-tenant team brain with pgvector

The native distributed-SQL story (we ship our own — not libSQL/Turso)

For multi-machine SQLite-shaped semantics with native replication, the canonical Hanzo stack is ZAP + hanzo-consensus + zapdb, not libSQL/Turso:

  • Wire: ZAP (zero-copy transport) — same protocol the rest of Hanzo speaks. Carries MCP, A2A, and ACP natively too. Repos live under zap-proto (one per language: zap-proto/c, zap-proto/cpp, zap-proto/go, zap-proto/py, zap-proto/rust, …).
  • Consensus: hanzo-consensus for metastable agent agreement. For storage-level write ordering we run the same metastable primitive on a node quorum (one quorum per brain shard).
  • Storage — zap-proto/db is the canonical home for zapdb. It's the base store, multi-language, ZAP-native. Currently mirrored at luxfi/zapdb (Go) and ~/work/luxcpp/zapdb (C++) pending the migration to zap-proto/db. luxfi/database is a separate Lux-flavored extension of zapdb that adds blockchain concerns (chain heads, archival, validator sets) — generic brain users want zapdb directly, not luxfi/database.
  • Backup: replicate ships SQLite WAL → S3 for the solo + small-team cases.
  • Streaming: vfs for unlimited-size brains backed by S3 blocks with PQ encryption.

We deliberately don't pull in libSQL or Turso; they'd force us off our own ZAP+consensus path. The multi-replica zapdb primitive is in-flight at luxfi/zapdb (Go) and ~/work/luxcpp/zapdb (C++), both migrating to zap-proto/db.

Default routing:

  • Solo dev, < 100K pages → SQLite + FTS5 (zero infra)
  • Solo dev, > 10K pages with vector → SQLite + sqlite-vec (requires better-sqlite3 driver — bun:sqlite has no extension loading)
  • Durable solo (offsite backup) → SQLite + replicate to S3
  • Multi-machine personal → zapdb over ZAP + hanzo-consensus (our native distributed-SQL story; canonical home is zap-proto/db, in-flight migration from luxfi/zapdb)
  • Team / Hanzo Node → Qdrant for vectors + Meilisearch for FTS + zapdb for facts/edges (or Postgres if multi-tenant + external)
  • Org-scale streaming → VFS-backed brain.db, lazy block-level fetch from S3, unlimited size

Schema

CREATE TABLE pages (
  slug         TEXT PRIMARY KEY,
  content      TEXT NOT NULL,
  frontmatter  TEXT,                   -- JSON
  updated_at   TEXT NOT NULL           -- ISO 8601
);

-- FTS5 virtual table over pages.content
CREATE VIRTUAL TABLE pages_fts USING fts5(content, content='pages', content_rowid='rowid');

CREATE TABLE edges (
  source    TEXT NOT NULL,             -- page slug
  target    TEXT NOT NULL,             -- entity slug
  type      TEXT NOT NULL,             -- mentions/attended/works_at/invested_in/founded/advises
  evidence  TEXT,                      -- verbatim phrase that triggered inference
  PRIMARY KEY (source, target, type)
);

CREATE TABLE facts (
  id          TEXT PRIMARY KEY,        -- subject::predicate::ts
  subject     TEXT NOT NULL,           -- entity slug
  predicate   TEXT NOT NULL,           -- preference/status/decision/replied/…
  object      TEXT NOT NULL,
  source      TEXT,                    -- originating page slug or session id
  ts          TEXT NOT NULL,           -- ISO 8601
  confidence  REAL DEFAULT 1.0
);

Anyone implementing BrainStore for another backend should mirror this shape — @hanzo/bot-graph-links and @hanzo/bot-recipes-brain Just Work against any conforming store.

Pluggability

import { registerBackend, open } from "@hanzo/bot-memory";

registerBackend("my-store", async (cfg) => {
  const store: BrainStore = makeMyStore(cfg);
  return store;
});

const store = await open({ backend: "my-store" });

Environment override: HANZO_BRAIN_BACKEND=my-store.

API surface

const store = await open(); // SQLite, ~/.hanzo/brain/brain.db

await store.upsertPage("people/alice", markdown, { type: "person" });
await store.upsertEdges("people/alice", edges);
await store.upsertFact({
  subject: "people/alice",
  predicate: "preference",
  object: "replies in under 2 hours",
});

const facts = await store.recall("people/alice", { limit: 50 });
const hits = await store.hybridSearch("Acme", 5);
const out = await store.edgesFor("people/alice", "out");

Config

interface MemoryConfig {
  backend?: string; // default "sqlite"
  dataDir?: string; // default ~/.hanzo/brain
  dbPath?: string; // explicit file; overrides dataDir
  embeddingModel?: string; // for the optional vector ANN path
  embeddingApiKey?: string;
}

Driver

  • bun:sqlite (canonical — already built into Bun, no install needed)
  • better-sqlite3 (fallback for Node-only deployments)

Either works. The init step tries bun:sqlite first.

Tests

cd ~/work/hanzo/bot && bun test extensions/memory

Covers: upsert + read pages, upsert + read edges, upsert + recall facts, FTS hybrid search, pluggability (register a stub backend), unknown-backend error message.