The data layer for AI agents.
Memory that evolves. State that recovers. Context that stays current.
The Problem · Quick Start · Architecture · Core Concepts · Comparison · FAQ · Contributing
Vector databases give you embed → store → search. That's retrieval, not memory. Real agent memory needs to know that "user prefers TypeScript" should replace "user prefers Python," that a preference should persist across sessions while a scratch note should not, and that contradictions should be detected — not silently accumulated.
Scoped visibility. Fact superseding with audit trail. State checkpointing with branching. Context assembly within a token budget. These are the building blocks every agent needs, but no database provides natively.
The result: every team building agents writes its own scoping logic, extraction pipeline, deduplication checks, and compaction safety nets on top of general-purpose storage. db0 is that layer — an SDK that encodes agent data semantics on top of SQLite or PostgreSQL, so you don't have to.
npm install @db0-ai/core @db0-ai/backends-sqliteWrite memory with scope — user-scoped facts persist across all sessions:
import { db0 } from "@db0-ai/core";
import { createSqliteBackend } from "@db0-ai/backends-sqlite";
const backend = await createSqliteBackend();
const harness = db0.harness({ agentId: "main", sessionId: "s1", userId: "user-1", backend });
await harness.memory().write({
content: "User prefers TypeScript",
scope: "user", // visible in every future session
embedding: await embed("User prefers TypeScript"),
});Supersede stale facts — old fact preserved for audit, excluded from search:
await harness.memory().write({
content: "User now prefers Rust",
scope: "user",
embedding: await embed("User now prefers Rust"),
supersedes: oldMemoryId, // marks the old entry as superseded
});Pack context for the LLM — assemble relevant memories within a token budget:
const ctx = await harness.context().pack("help with current task", { tokenBudget: 2000 });
// ctx.text → formatted markdown ready for the system promptBranch execution state — checkpoint and explore alternatives:
const cp = await harness.state().checkpoint({ step: 1, label: "before-decision" });
await harness.state().branch(cp.id, { step: 2, label: "try-alternative" });Spawn sub-agents — shared backend, automatic memory isolation:
const child = harness.spawn({ agentId: "researcher", sessionId: "s2" });
// user-scoped facts flow both ways; session-scoped facts stay isolatedOpenClaw — zero-config ContextEngine plugin:
npx @db0-ai/openclaw initPersistent memory, automatic fact extraction, sub-agent support. See packages/apps/openclaw.
Claude Code — MCP server with skills and hooks. See packages/apps/claude-code.
┌──────────────────────────────────────────────────────────┐
│ Applications │
│ │
│ ┌──────────┐ ┌─────────────┐ ┌──────────────────┐ │
│ │ OpenClaw │ │ Claude Code │ │ Your Agent │ │
│ └──────────┘ └─────────────┘ └──────────────────┘ │
└──────────────────────────┬───────────────────────────────┘
│
┌──────────────────────────▼───────────────────────────────┐
│ db0 Core │
│ │
│ ┌────────┐ ┌─────────┐ ┌───────┐ ┌─────┐ ┌──────┐ │
│ │ Memory │ │ Context │ │ State │ │ Log │ │Spawn │ │
│ └────────┘ └─────────┘ └───────┘ └─────┘ └──────┘ │
│ │
│ ┌──────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Profiles │ │ Extraction │ │ Embeddings │ │
│ └──────────┘ └────────────┘ └────────────┘ │
└──────────────────────────┬───────────────────────────────┘
│
┌──────────────────────────▼───────────────────────────────┐
│ Backend Interface │
│ │
│ ┌────────────────┐ ┌────────────────────────────┐ │
│ │ SQLite (sql.js) │ │ PostgreSQL + pgvector │ │
│ └────────────────┘ └────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
| Feature | What it does |
|---|---|
| 4 scopes | task (ephemeral) → session → user → agent (permanent), each with visibility rules |
| Superseding | Correct stale facts without losing history — old entries preserved but excluded from search |
| Hybrid search | Semantic similarity + recency + popularity, with scope/tag/metadata/time filters |
| Typed relationships | related, derived, contradicts, supports, supersedes edges with graph expansion |
| Entity extraction | Auto-extract people, dates, places for entity-aware retrieval |
| Noise filtering | Rejects refusals, greetings, and process narration before extraction |
| L0 summaries | Auto-generated one-line summaries for token-efficient context assembly |
| Provenance | Every fact tracks source type, extraction method, and confidence |
The context lifecycle — what goes into the LLM's context window and what gets preserved:
| Verb | What it does |
|---|---|
ingest |
Write a fact with deduplication, contradiction detection, and entity enrichment |
pack |
Assemble relevant memories into a token budget with relationship annotations |
preserve |
Batch-extract and batch-embed facts from conversation messages before compaction |
reconcile |
Background maintenance — promote high-access chunks, merge duplicates, clean stale edges |
Checkpoint and branch execution state. Restore to any prior checkpoint. Branch from any point to explore alternatives in parallel. Not a cache — a recoverable execution record.
harness.spawn() creates a child harness sharing the same database. User-scoped memories flow between parent and child automatically. Session-scoped memories stay isolated. Same DB, no extraction, no serialization.
| Strategy | Tradeoff |
|---|---|
| Rules (default) | Signal-word matching. Zero LLM calls, deterministic, near-zero latency |
| LLM | Higher precision via configurable prompt. Latency and cost tradeoff |
| Manual | You call memory().write(). Full control, no surprises |
Auto-detected on startup — no configuration needed:
Gemini (GEMINI_API_KEY, free tier)
→ Ollama (local)
→ OpenAI (OPENAI_API_KEY)
→ Hash (built-in, zero API calls, always works)
When the provider changes, existing memories are re-embedded automatically.
Named config bundles tuned for different workloads:
| Profile | Best for | Key trait |
|---|---|---|
| conversational | Chat, support | Fast decay, high recency weight |
| agent-context | Agent harnesses | Balanced hybrid scoring, auto-reconcile |
| knowledge-base | RAG, document search | Enrichment, query expansion, latent bridging |
| coding-assistant | IDE tools | High precision, slow decay |
| curated-memory | Human-authored facts | Near-zero decay, manual extraction |
| high-recall | Benchmarks, research | Large topK, low threshold, 2-hop expansion |
The right profile can swing retrieval quality by 40+ points on benchmarks.
- CLI —
db0 list,search,stats,export,import - Inspector — web UI for browsing memory, state, and logs
- Benchmarks — LoCoMo, LongMemEval, and feature-level test suites
| Package | Description |
|---|---|
@db0-ai/core |
Types, harness, memory/state/log/context, profiles, extraction |
@db0-ai/backends-sqlite |
SQLite via sql.js — zero native deps |
@db0-ai/backends-postgres |
PostgreSQL + pgvector |
@db0-ai/openclaw |
OpenClaw ContextEngine plugin + CLI |
@db0-ai/claude-code |
Claude Code MCP server + skills + hooks |
@db0-ai/inspector |
Web UI for memory/state/log inspection |
@db0-ai/cli |
CLI for memory operations |
@db0-ai/benchmark |
Memory quality benchmarks |
SQLite (default) — pure JS via sql.js. Zero native deps, works everywhere. Local-first, your data stays on your machine.
PostgreSQL + pgvector — native hybrid vector search. Any hosted Postgres (Neon, Supabase, Railway) for production, cross-device sync, and disaster recovery.
import { createSqliteBackend } from "@db0-ai/backends-sqlite";
import { createPostgresBackend } from "@db0-ai/backends-postgres";
// Local — zero config
const local = await createSqliteBackend();
// Production — swap one line
const prod = await createPostgresBackend("postgresql://user:pass@host/db0");db0 occupies a different layer than most "memory" tools. It's an embeddable SDK that controls the full data lifecycle — not just storage or retrieval, but context assembly, state management, and sub-agent coordination.
| db0 | Mem0 | Zep | Letta | |
|---|---|---|---|---|
| What it is | Embeddable SDK (library) | Memory API service | Memory server | Full agent runtime |
| Deployment | In-process, no sidecar | Cloud or self-hosted server | Cloud or self-hosted server | Self-hosted server |
| Memory scoping | 4 scopes with visibility rules | User/agent/session | User/session | Agent-level blocks |
| Fact correction | Superseding with audit trail | Overwrite | Overwrite | Self-editing memory blocks |
| State management | Checkpoints + branching | No | No | Managed by runtime |
| Sub-agent memory | Shared backend, automatic isolation | No | No | No |
| Context assembly | context().pack() with token budgets |
No (retrieval only) | No (retrieval only) | Yes (owns the runtime) |
| Extraction | Pluggable: rules / LLM / manual | LLM-only | Automatic summarization | LLM self-editing |
| LLM required | No (rules + hash embeddings) | Yes | Yes | Yes |
| Storage | SQLite or Postgres (bring your own) | Managed | Managed or Postgres | Managed |
| Framework lock-in | None — plain TypeScript | None (API) | None (API) | Letta runtime |
When to use what:
- db0 — You're building an agent and want memory, state, and context as an embedded library. You want control over extraction, scoring, and context assembly without running a separate service.
- Mem0 — You want a managed memory API you can call from any language. You're okay with LLM-driven extraction on every write.
- Zep — You want a memory server with built-in temporal knowledge graphs and automatic summarization.
- Letta — You want a complete agent runtime where the agent manages its own memory. You're okay adopting Letta's execution model.
Why not just use a vector database directly?
A vector database gives you storage and similarity search. db0 gives you the agent-specific primitives on top: scoped visibility, fact superseding, hybrid scoring with recency decay, state branching, context assembly with token budgets, sub-agent sharing, and pluggable extraction. You'd build all of this yourself on top of a vector DB — db0 is that layer, already built and tested.
Does db0 require an LLM to work?
No. The default configuration uses rule-based extraction (signal-word matching) and built-in hash embeddings. Zero API calls, zero cost, works offline. Upgrade to LLM extraction or real embeddings when you need better precision — it's a config change, not a rewrite.
How is this different from LangChain Memory or LangGraph Store?
LangChain Memory and LangGraph Store are memory adapters within their respective frameworks. db0 is framework-agnostic and covers more ground: scoped memory with superseding, execution state with branching, context assembly with token budgets and contradiction detection, structured logging, and sub-agent context sharing. You can use db0 with LangChain, or without any framework.
What about scaling?
SQLite handles single-agent workloads with zero network overhead. For production, multi-agent, or cross-device scenarios, switch to PostgreSQL + pgvector — one line change. Any hosted Postgres works: Neon, Supabase, Railway, or your own.
Can I use this with Python?
Not yet. db0 is TypeScript-first. A Python SDK is planned — it will be Python-native (async, pydantic), not a port of the TypeScript API.
What's the license?
MIT. Fully open source, no commercial restrictions.
See CONTRIBUTING.md for development setup and guidelines.