Embedded storage for agent memory

One file for graph, vector, and provenance.

ffs is a Rust storage engine for AI systems that need semantic recall, relationship traversal, typed facts, and lineage to commit together.

ffs.db local engine
Cypher subset HNSW vector search typed column groups CSR graph edges MVCC + WAL
Shape
embedded Rust crate
Atomicity
one WAL, one transaction
Status
252 tests passing
Graph traversal relationships live next to the facts they explain
Vector similarity semantic recall without a separate vector service
Provenance writes derived memory keeps a first-class source trail

Agent memory should not require three databases and a prayer.

Most AI apps split memory across a graph database, a vector database, and a relational store. The glue is where IDs drift, writes stop being atomic, and latency budgets get spent on translation.

ffs collapses those shapes into one embedded engine. The app opens a file. Graph edges, vectors, typed properties, and provenance records share the same buffer pool, WAL, and commit.

Built for local, high-churn retrieval workloads.

ffs favors the hot paths agents hit constantly: neighborhood reads, vector recall, schema-checked writes, and recovery after a crash.

querytyped Cypher subset
executionoperators + morsels
indexesB+-tree + HNSW
storagenode groups + CSR rels
durabilityMVCC, pager, WAL
01

Typed graph storage

Columnar node groups and CSR relationship tables for cache-friendly traversal.

02

Vector index

HNSW search in tree today, with persistence moving into the storage substrate.

03

Schema boundary

Types are checked before bad data reaches disk, not cleaned up in app code.

04

MVCC and WAL

Snapshot isolation and crash recovery across graph, vector, and facts.

05

Cypher subset

Graph-native pattern matching, with read and mutation paths in tree.

06

Provenance API

Derived nodes can carry source links and confidence as first-class data.

Benchmarks for the paths AI memory leans on.

The eval harness compares in-process reads, vector search, graph traversal, and server-stack overhead. The point is architectural: fewer systems means less coordination tax.

Comparator Path Result
sled KV lookup 1.8x
instant-distance HNSW query 2.6x
petgraph 1-hop traversal 9x
pgvector HNSW query 3.01x

Open a graph. Traverse it. Keep the engine local.

use ffs::cypher::{compile_query, parse};
use ffs::exec::collect_column;
use ffs::planner::{compile, CompileCtx};
use ffs::storage::RelTable;

let mut knows = RelTable::new(0, "KNOWS", 4, 4);
knows.add_edge(0, 0, 1, 1);
knows.add_edge(0, 0, 2, 2);

let q = parse("MATCH (a:Person)-[:KNOWS]->(b:Person) RETURN b")?;
let plan = compile_query(&q, |_| vec![0, 1, 2, 3]);
let ctx = CompileCtx::empty().with_rel_table("KNOWS", &knows);
let mut op = compile(plan, &ctx)?;
let neighbours = collect_column(&mut *op, 0);

Pre-v0, with the spine already in tree.

ffs is early. The storage spine, transactions, schema and type system, B+-tree indexes, in-memory HNSW, Cypher parser/planner, executor, and Python binding work are underway in the repo.

  1. Now persistent schema, vector persistence, SQL compatibility track
  2. Next cost-based planner, secondary index persistence
  3. Later broader bindings, server wrapper only if embedded earns it