![]()
One ~9 MB binary. Three engines. One query language. Zero cloud dependency.
Vector + Graph + ColumnStore — unified under VelesQL
The explainable agent memory: why() returns the evidence path behind every recall —
measured on public benchmarks, not vibes.
Download latest release • Quick Start • Architecture • Roadmap • Quality Bar • Documentation • DeepWiki
Every AI agent today stitches together 3 databases for memory — vectors for "what feels similar", a graph for "what is connected", and SQL for "what I know for sure". That's 3 deployments, 3 configs, 3 query languages, and a pile of glue code.
VelesDB replaces all of that with a single Rust binary — smaller than a single smartphone photo.
| 🔍 It shows its work | 🔑 No cloud bill per memory | 📊 Measured, not vibes |
|---|---|---|
Ask why() and the memory returns the evidence trail behind every answer — which facts it used and how they connect, not just the answer itself. That's a built-in audit trail, exactly what regulations like the EU AI Act (enforceable Aug 2026) will ask of AI systems. |
With the leading alternatives, every single memory saved runs 2–3 AI-model calls — by default, paid cloud calls with an API key. VelesDB stores memories with zero AI calls and zero keys: one small program (~9 MB) on your machine, no extra databases to install or operate. | We publish how often the memory finds the right information — measured with no AI grader in the loop that could flatter the score. On public test sets: +7.2 pts on multi-hop (HotpotQA) and +9.7 pts on time-scoped recall (TimeQA); on a controlled task needing both engines at once, +29 pts. Anyone can re-run the tests. |
| Today (3 systems to maintain) | With VelesDB (1 binary) |
|---|---|
| pgvector for embeddings | Vector Engine — 450us p50 end-to-end (10K/384D, WAL ON, recall>=96%) |
| Neo4j for knowledge graphs | Graph Engine — MATCH clause, BFS/DFS |
| PostgreSQL/DuckDB for metadata | Typed ColumnStore + secondary indexes — filtering API 130x faster than JSON scanning at 100K rows*¹ |
| Custom glue code + 3 query languages | VelesQL — one language for everything |
| 3 deployments, 3 configs, 3 backups | ~9 MB binary — works offline, air-gapped |
¹ ColumnStore filtering API micro-benchmark, integer equality: 130x at 100K rows, 55x at 10K rows — see docs/BENCHMARKS.md § 6.
SELECT ... WHEREmetadata filtering uses secondary indexes when available, and an adaptive ColumnStore payload mirror for scan-heavy filters (see [2] below).
VelesDB is a local-first database for AI agents that fuses three engines into a single ~9 MB binary [3]:
| Engine | What it does | Performance |
|---|---|---|
| Vector | Semantic similarity search (HNSW + AVX2/NEON SIMD) | 450us p50 end-to-end (384D, WAL ON, recall>=96%) [1] |
| Graph | Knowledge relationships (BFS/DFS, edge properties) | Native MATCH clause |
| ColumnStore | Structured metadata filtering (typed columns) | 130x faster than JSON scanning [2] |
[1] Reproduce:
python benchmarks/velesdb_benchmark.py --recall(Python SDK path, 10K/384D, WAL fsync on, i9-14900KF reference machine). See docs/BENCHMARKS.md and CHANGELOG v1.13.0. Re-verified on v3.3.0 (2026-06-24): p50 ≈ 360 µs (356–366 µs across two clean isolated runs), recall@10 0.986–0.989 on Apple Silicon — report (latency is hardware-specific; the canonical 450 µs is the i9-14900KF figure). [2] Reproduce:cargo bench -p velesdb-core --bench column_filter_benchmark. See docs/BENCHMARKS.md § 6 — at 100K rows: ColumnStore 29.5 us vs JSON scan 3.84 ms (integer equality filter). Micro-benchmark of the ColumnStore filtering API, which now servesSELECT ... WHEREmetadata filtering through a per-collection payload mirror (built adaptively for scan-heavy workloads) and backs JOIN execution; secondary indexes are used first when they cover the filter. [3] Binary size:velesdb-server, stripped release build — 9.3 MB on Apple Silicon for v3.3.0 (the v1.18.0 release artifact was 9.4 MB). Across platforms and binaries (CLI / server / migrate), release artifacts span 6–13 MB. Enforced in CI:scripts/check_binary_size.py(workflowbinary-size.yml) fails the build if a binary exceeds its ceiling.
All three are queried through VelesQL — a single SQL-like language with vector, graph, and columnar extensions:
MATCH (doc:Document)-[:AUTHORED_BY]->(author:Person)
WHERE similarity(doc.embedding, $question) > 0.8
AND author.department = 'Engineering'
RETURN author.name, doc.title
ORDER BY similarity() DESC LIMIT 5
Built-in Agent Memory SDK provides semantic, episodic, and procedural memory for AI agents — no external services needed.
One binary. No cloud. No glue code. Runs on server, browser, mobile, and desktop.
Built-in memory for AI agents — semantic, episodic, and procedural. No external services needed.
why() — connected memory that survives restartsMost "agent memory" is vector recall: it finds text that looks like your query. VelesDB's high-level MemoryService adds the part that's missing — it connects memories with typed links, so it can answer why something happened by walking the graph to context that shares no words with your question. The store is on disk, so it works across sessions. Offline, deterministic, no API key, no model download:
Where Mem0 and Zep are cloud-coupled orchestrators (several backing services plus AI-model calls — cloud by default — on every memory write), this is one local binary — fully offline, zero AI calls to store a memory, and an auditable why() evidence trail. On the standard LoCoMo memory test, our fully-local setup answers 56% of the answerable questions (the benchmark's unanswerable "adversarial" category is excluded, as is standard practice — every configuration detail is disclosed) and 55–61% of time-related questions ("when did X happen?") — spanning both configurations the leading vendor's own paper reports for itself in that category, on powerful cloud AI models, while we run on a model on your own machine. Scores from different labs can't be fairly compared (the same product's score can swing ~21 points with the test setup alone), so instead of a bar chart we publish the full sourced landscape, method, and statistics. Pick it when your data can't leave the box.

from velesdb import MemoryService # pip install velesdb
mem = MemoryService("./agent_memory") # a real on-disk store; survives restarts
reason = mem.remember("Robert is recovering from knee surgery")
mem.remember("Booked the aisle seat on Robert's flight", links=[(reason, "because")])
# A *new* process, weeks later, reopens the same store and asks why:
mem.why("why the aisle seat on Robert's flight?") # walks booking → reason — recall() can't
Memories are permanent by default; forget(id) deletes one, and remember(…, ttl_seconds=…) (or a server-wide VELESDB_MEMORY_DEFAULT_TTL) gives a fact a durable, restart-surviving expiry.
The same wedge ships in Python (pip install velesdb), Node (npm i @wiscale/velesdb-memory-node), as a local MCP server, and — in-memory only, no disk access under WASM — in the TypeScript SDK (npm i @wiscale/velesdb-sdk), running entirely in the browser or Node.js with no server.
Four runnable ways to see it — each shows what plain vector recall misses and why() recovers:
| Demo | What it shows |
|---|---|
why_across_sessions.py |
the reason survives a process restart — recall of the top 5 of 16 memories stays blind, why() reaches it |
why_magic_constant.py |
why a magic constant has its value — a business reason that shares no words with the code |
memory_builds_its_own_graph.py |
paste raw prose → a local model auto-wires the graph (no relate()), why() walks it to the root cause |
why_magic_constant.mjs |
the same engine and wedge in the Node binding |
Not a weak-embedder trick. In each retrieval demo, recall stays blind to the reason even under a real semantic embedder (
ollama/all-minilm), not just the offlinehashdefault — the reason is connected by a decision, not by surface similarity, which is exactly what a vector store cannot follow.
For the lower-level building blocks (episodic, procedural, TTL, snapshots):
from velesdb import Database, AgentMemory
db = Database("./agent_data")
memory = AgentMemory(db, dimension=384)
memory.semantic.store(1, "Paris is the capital of France", embedding)
memory.episodic.record(1, "User asked about geography", timestamp, embedding)
memory.procedural.learn(1, "answer_geography", steps, embedding, confidence=0.8)
| Feature | API |
|---|---|
| TTL / Auto-expiration | store_with_ttl(), auto_expire() |
| Snapshots / Rollback | snapshot(), load_latest_snapshot() |
| Reinforcement | reinforce(success=True) — 6 strategies (strategy selection via the Rust API; Python uses the FixedRate default) |
And because memories live in the same engine as the graph and the ColumnStore, one VelesQL statement recalls by similarity, graph context, and session — in a single query (tested end-to-end):
SELECT memory.*, similarity() FROM agent_memory AS memory
WHERE vector NEAR $embedding
AND MATCH (ctx)-[:RELATES_TO]->(fact)
AND session_id = $current_session
ORDER BY similarity() DESC LIMIT 10
Full guide: docs/guides/AGENT_MEMORY.md | Source code
| VelesDB | Chroma | Qdrant | pgvector | |
|---|---|---|---|---|
| Architecture | Unified vector + graph + columnar | Vector only | Vector + payload | Vector extension for PostgreSQL |
| Metadata filtering | Typed ColumnStore [2] + secondary indexes | JSON scan | JSON payload | SQL (PostgreSQL) |
| Deployment | Embedded / Server / WASM / Mobile | Server (Python) | Server (Rust) | Requires PostgreSQL |
| Binary size | ~9 MB | ~500 MB (with deps) | ~50 MB | N/A (PG extension) |
| Search latency | 450us p50 (10K/384D, WAL ON, recall>=96%) | ~1-5ms | ~1-5ms (in-memory) | ~5-20ms |
$ claude mcp add VelesDB \
-- python -m otcore.mcp_server <graph>