"We can wander through the stacks of the Library of Alexandria, imagining the scrolls and the knowledge they contain. Its destruction is a warning: all we have is transient."——Alberto Manguel
AI-oriented memory management system. Stores structured knowledge as a graph of Knowledge entries (nodes) and Statement triples (edges), queried via a custom JSON Search Expression (JSE) language. Built on SQLite FTS5 + DuckDB, with configurable embedding models (local ONNX or remote API) for semantic vector search.
$and, $or, $not, $eq, $ne, $gt, $lt, $contains, $like, $content, $search, $quote, $triple, $k-hop# Build
cargo build --release
# Download embedding model (BGE-M3, recommended)
mkdir -p ~/.hypatia/default
hf download BAAI/bge-m3 --local-dir /tmp/bge-m3
cp /tmp/bge-m3/onnx/model.onnx ~/.hypatia/default/embedding_model.onnx
cp /tmp/bge-m3/onnx/model.onnx_data ~/.hypatia/default/model.onnx_data
cp /tmp/bge-m3/onnx/tokenizer.json ~/.hypatia/default/tokenizer.json
# Create knowledge
hypatia knowledge-create "Rust" -d "systems programming language" -t "language,compiled"
# Create a relationship
hypatia statement-create "Rust" "is_a" "systems language"
# Full-text search
hypatia search "programming language"
# Vector similarity search (requires embedding model)
hypatia backfill # generate embeddings for existing entries
hypatia similar "programming language" # semantic search
# Structured query (JSE)
hypatia query '["$knowledge", ["$eq", "name", "Rust"]]'
hypatia query '["$statement", ["$triple", "Rust", "$*", "$*"]]'
hypatia query '["$knowledge", ["$search", "database migration"]]'
# Interactive REPL
hypatia repl
Hypatia supports multiple embedding backends, configured via shelf.toml in the shelf directory (e.g., ~/.hypatia/default/shelf.toml).
No configuration needed — place model files in the shelf directory and Hypatia auto-detects them.
# Download from HuggingFace
hf download BAAI/bge-m3 --local-dir /tmp/bge-m3
cp /tmp/bge-m3/onnx/model.onnx ~/.hypatia/default/embedding_model.onnx
cp /tmp/bge-m3/onnx/model.onnx_data ~/.hypatia/default/model.onnx_data
cp /tmp/bge-m3/onnx/tokenizer.json ~/.hypatia/default/tokenizer.json
Create or edit ~/.hypatia/default/shelf.toml:
[embedding]
provider = "local"
dimensions = 1536
max_seq_length = 8192
hf download Alibaba-NLP/gte-Qwen2-1.5B-instruct --local-dir /tmp/gte-qwen2
# Export ONNX first (requires optimum-cli or transformers)
# Then place files in shelf directory
hf download google/embedding-gemma-300M --local-dir /tmp/embedding-gemma
# Export ONNX and place files
hf download jinaai/jina-embeddings-v5-text-small-text-matching \
onnx/model.onnx onnx/model.onnx_data tokenizer.json \
--local-dir /tmp/jina-v5-small
cp /tmp/jina-v5-small/onnx/model.onnx ~/.hypatia/default/embedding_model.onnx
cp /tmp/jina-v5-small/onnx/model.onnx_data ~/.hypatia/default/model.onnx_data
cp /tmp/jina-v5-small/tokenizer.json ~/.hypatia/default/tokenizer.json
shelf.toml:
[embedding]
provider = "local"
dimensions = 1024
max_seq_length = 32768
pooling = "last_token"
hf download jinaai/jina-embeddings-v5-text-nano-text-matching \
onnx/model.onnx onnx/model.onnx_data tokenizer.json \
--local-dir /tmp/jina-v5-nano
cp /tmp/jina-v5-nano/onnx/model.onnx ~/.hypatia/default/embedding_model.onnx
cp /tmp/jina-v5-nano/onnx/model.onnx_data ~/.hypatia/default/model.onnx_data
cp /tmp/jina-v5-nano/tokenizer.json ~/.hypatia/default/tokenizer.json
shelf.toml:
[embedding]
provider = "local"
dimensions = 768
max_seq_length = 8192
pooling = "last_token"
For cloud-based embeddings without local model files:
[embedding]
provider = "remote"
api_url = "https://api.openai.com/v1/embeddings"
api_key_env = "OPENAI_API_KEY"
api_model = "text-embedding-3-small"
dimensions = 1536
Works with any OpenAI-compatible API:
- OpenAI (text-embedding-3-small, text-embedding-3-large)
- Azure OpenAI
- Local servers (Ollama, LM Studio, vLLM)
- Other providers (Voyage AI, Cohere, Jina, Gitee AI)
[embedding]
provider = "remote"
api_url = "http://localhost:11434/v1/embeddings"
api_key_env = "OLLAMA_API_KEY"
api_model = "qwen3-embedding:8b"
dimensions = 1024
# Set a dummy key (Ollama doesn't require auth)
export OLLAMA_API_KEY="ollama"
Set the API key as an environment variable:
export OPENAI_API_KEY="sk-..."
| Field | Default | Description |
|---|---|---|
provider |
"local" |
"local" for ONNX, "remote" for HTTP API |
dimensions |
1024 |
Embedding vector dimensions |
max_seq_length |
8192 |
Max tokenizer sequence length (local only) |
pooling |
"mean" |
Pooling strategy: "mean", "cls", or "last_token" (local only) |
model_path |
embedding_model.onnx |
ONNX model path, relative to shelf dir (local only) |
tokenizer_path |
tokenizer.json |
Tokenizer path, relative to shelf dir (local only) |
api_url |
OpenAI URL | API endpoint URL (remote only) |
api_key_env |
OPENAI_API_KEY |
Environment variable name for API key (remote only) |
api_model |
text-embedding-3-small |
Model name sent to API (remote only) |
| Command | Description |
|---|---|
hypatia connect <path> [-n <name>] |
Connect to a shelf directory |
hypatia disconnect <name> |
Disconnect from a shelf |
hypatia list |
List connected shelves |
hypatia knowledge-create <name> [-d <data>] [-t <tags>] [--synonyms <csv>] [--figures <refs>] |
Create a knowledge entry |
hypatia knowledge-get <name> |
Get a knowledge entry |
hypatia knowledge-delete <name> |
Delete a knowledge entry |
hypatia statement-create <subj> <pred> <obj> [-d <data>] [--synonyms <json>] |
Create a triple |
hypatia statement-delete <subj> <pred> <obj> |
Delete a triple |
hypatia search <query> [-c <catalog>] [--limit N] |
Full-text search |
hypatia similar <query> [--limit N] |
Vector similarity search |
hypatia backfill |
Generate embeddings for all entries |
hypatia archive-store <file> [-n <name>] [-s <shelf>] |
Store a file in archives with auto-metadata |
hypatia archive-get <name> [-o <output>] [-s <shelf>] |
Get an archive file path or copy it |
hypatia archive-list [-s <shelf>] |
List all archive files |
hypatia query '<jse-json>' |
Execute a JSE query |
hypatia export <name> <dest> |
Export a shelf |
hypatia repl |
Interactive REPL |
JSE (JSON Search Expression) enables precise queries against knowledge or statement tables.
["$knowledge", condition1, condition2, ...]
["$statement", condition1, condition2, ...]
| Operator | Purpose | Example |
|---|---|---|
$eq |
Equals | ["$eq", "name", "Rust"] |
$ne |
Not equals | ["$ne", "name", "Rust"] |
$gt / $lt / $gte / $lte |
Comparison | ["$gt", "created_at", "2025-01-01"] |
$contains |
Substring in JSON field | ["$contains", "tags", "backend"] |
$like |
SQL LIKE pattern match | ["$like", "name", "Rust%"] |
$content |
Match content JSON key-values | ["$content", {"format": "markdown"}] |
$search |
Full-text search | ["$search", "database migration"] |
$and |
Logical AND | ["$and", cond1, cond2] |
$or |
Logical OR | ["$or", cond1, cond2] |
$not |
Logical NOT | ["$not", cond] |
$quote |
Prevent evaluation | ["$quote", ["$eq", "x", "y"]] |
$triple |
Triple position match | ["$triple", "Alice", "$*", "Bob"] |
$k-hop |
K-hop graph traversal | ["$k-hop", "Alice", "$*", 2] |
# All knowledge entries
hypatia query '["$knowledge"]'
# Knowledge named "Rust" with tag "systems"
hypatia query '["$knowledge", ["$and", ["$eq", "name", "Rust"], ["$contains", "tags", "systems"]]]'
# Statements containing "Alice" in triple
hypatia query '["$statement", ["$contains", "triple", "Alice"]]'
# Triple matching: all relationships where Alice is the subject
hypatia query '["$statement", ["$triple", "Alice", "$*", "$*"]]'
# Triple matching: all "manages" relationships
hypatia query '["$statement", ["$triple", "$*", "manages", "$*"]]'
# Triple matching: exact triple (uses PK index)
hypatia query '["$statement", ["$triple", "Alice", "knows", "Bob"]]'
# Pattern matching: names starting with "Al"
hypatia query '["$knowledge", ["$like", "name", "Al%"]]'
# Content filtering: all markdown entries
hypatia query '["$knowledge", ["$content", {"format": "markdown"}]]'
# FTS search within knowledge
hypatia query '["$knowledge", ["$search", "query optimization"]]'
# Statements where triple contains Alice or Bob
hypatia query '["$statement", ["$or", ["$contains", "triple", "Alice"], ["$contains", "triple", "Bob"]]]'
# K-hop: all entities reachable from Alice in 2 hops
hypatia query '["$statement", ["$k-hop", "Alice", "$*", 2]]'
# K-hop: follow "knows" edges from Alice, 3 hops deep
hypatia query '["$statement", ["$k-hop", "Alice", "knows", 3]]'
src/
├── cli/ # CLI commands + REPL (clap + rustyline)
├── embedding/ # Embedding providers (ONNX local + remote API)
├── engine/ # JSE parser, AST, evaluator, SQL builder
├── model/ # Knowledge, Statement, Content, Query types
├── service/ # Business logic (dual-write to DuckDB + SQLite)
├── storage/ # DuckDB store, SQLite FTS5 store, shelf manager
├── lab.rs # Top-level API facade
├── error.rs # Error types
├── lib.rs # Module declarations
└── main.rs # Entry point
Each shelf is a directory containing data.duckdb (structured data), index.sqlite (FTS5 index), optional shelf.toml (embedding config), embedding model files, and an archives/ directory for attachments. The service layer keeps both databases in sync via dual-write.
Hypatia supports storing archive files (images, PDFs, data, etc.) alongside knowledge entries. Files are stored in the shelf's archives/ directory and referenced via the archive:// convention in knowledge content.
~/.hypatia/default/
├── data.duckdb
├── index.sqlite
├── shelf.toml
└── archives/
└── euclid/
├── fig_1_1.png
└── fig_1_2.svg
# Store a file (auto-creates knowledge with metadata)
hypatia archive-store figure.png -n euclid/fig_1_1.png
# Get the path to a stored archive file
hypatia archive-get euclid/fig_1_1.png
# Copy an archive file to a local path
hypatia archive-get euclid/fig_1_1.png -o /tmp/fig.png
# List all archive files
hypatia archive-list
# Reference an archive when creating knowledge
hypatia knowledge-create "Euclid Prop 1" \
-d "Construction of equilateral triangle" \
--figures "archive://euclid/fig_1_1.png"
archive-store automatically creates:
<path> is_a archive (graph connectivity)This enables JSE queries on archive metadata:
hypatia query '["$knowledge", ["$contains", "tags", "archive"]]'
hypatia query '["$knowledge", ["$content", {"mime_type": "image/png"}]]'
hypatia query '["$statement", ["$triple", "$*", "is_a", "archive"]]'
<shelf>/archives/<path> on the filesystemarchive://<path> in knowledge content's figures fieldarchive://euclid/fig.png resolves to <shelf>/archives/euclid/fig.pnghypatia export copies the archives/ directory along with databasesTested on the LoCoMo long-term conversational memory benchmark (ACL 2024, 10 conversations, 1,540 non-adversarial QA pairs, 6,426 entries). Measures whether the correct evidence passage is found in top-K
$ claude mcp add hypatia \
-- python -m otcore.mcp_server <graph>