semantic-memory
Hybrid semantic search library for Rust, backed by SQLite + FTS5 + HNSW. Built for AI agent memory systems.
Combines BM25 full-text search with approximate nearest neighbor vector search via Reciprocal Rank Fusion, giving you the best of both lexical and semantic retrieval in a single query.
Features
- Hybrid search — BM25 (FTS5) + cosine similarity fused with RRF
- HNSW indexing — Fast approximate nearest neighbor via
hnsw_rs, with brute-force fallback - Knowledge store — Add, update, delete, and search facts organized by namespace
- Document chunking — Ingest long documents with configurable overlap chunking and per-chunk embeddings
- Conversation memory — Session-based message history with token budgeting and message search
- SQ8 quantization — Quantized embeddings stored alongside f32 for space-efficient persistence
- Recency boosting — Optional time-decay weighting with configurable half-life
- Single-file storage — Everything lives in one SQLite database + optional HNSW sidecar files
- Async API — All public methods are async, with SQLite I/O on
spawn_blocking - Zero external services — Only requires Ollama for embeddings (or use
MockEmbedderfor testing)
Quick Start
Prerequisites
- Rust 1.75+
- Ollama running locally with an embedding model:
Installation
[]
= "0.3"
Usage
use ;
async
Conversation Memory
use ;
async
Document Ingestion
let doc_id = store.add_document.await?;
// Chunks are automatically created, embedded, and searchable
let results = store.search.await?;
Architecture
MemoryStore
├── SQLite (FTS5) — BM25 full-text search, f32 + SQ8 embeddings, all metadata
├── HNSW Index — Approximate nearest neighbor (optional, feature-gated)
└── Ollama / MockEmbedder — Embedding generation
Search pipeline:
- FTS5
MATCHproduces BM25-ranked candidates - HNSW ANN (or brute-force) produces vector-similarity candidates
- Reciprocal Rank Fusion merges both lists into a single scored ranking
Storage layout:
base_dir/
├── memory.db — SQLite database (content, metadata, FTS5, embeddings)
├── memory.hnsw.graph — HNSW graph topology (optional)
└── memory.hnsw.data — HNSW vector data (optional)
SQLite is the single source of truth. The HNSW index is a performance accelerator that can be rebuilt from SQLite at any time.
Configuration
All configuration is done through MemoryConfig:
use ;
use PathBuf;
let config = MemoryConfig ;
Feature Flags
| Flag | Default | Description |
|---|---|---|
hnsw |
Yes | HNSW approximate nearest neighbor search via hnsw_rs |
brute-force |
No | Exact cosine similarity search (no external index) |
testing |
No | Enables test utilities and MockEmbedder helpers |
At least one of hnsw or brute-force must be enabled.
# Default (HNSW enabled)
# Brute-force only (no HNSW dependency)
# Run tests
API Overview
Knowledge Store
| Method | Description |
|---|---|
add_fact(namespace, content, source, metadata) |
Store a searchable fact |
update_fact(id, content, metadata) |
Update fact content and re-embed |
delete_fact(id) |
Remove a fact |
get_fact(id) |
Retrieve a fact by ID |
list_facts(namespace, limit, offset) |
List facts with pagination |
Document Store
| Method | Description |
|---|---|
add_document(title, content, namespace, source, meta) |
Ingest and chunk a document |
delete_document(id) |
Remove document and all its chunks |
list_documents(namespace, limit, offset) |
List documents with pagination |
Search
| Method | Description |
|---|---|
search(query, top_k, namespace, domain) |
Hybrid BM25 + vector search |
search_fts_only(query, top_k, namespace, domain) |
BM25-only search (no embeddings) |
search_vector_only(query, top_k, namespace, domain) |
Vector-only search |
search_messages(query, session_id, top_k) |
Search conversation history |
Conversations
| Method | Description |
|---|---|
create_session(channel) |
Start a new conversation session |
add_message(session, role, content, tokens, meta) |
Append a message |
get_recent_messages(session, limit) |
Get latest messages |
get_messages_within_budget(session, budget) |
Get messages fitting a token budget |
session_token_count(session) |
Total tokens in a session |
list_sessions(limit, offset) |
List all sessions |
delete_session(id) |
Remove a session and its messages |
Maintenance
| Method | Description |
|---|---|
stats() |
Database statistics |
rebuild_hnsw_index() |
Rebuild HNSW from SQLite (hot-swap) |
compact_hnsw() |
Clean up HNSW tombstones |
License
MIT