ADR-007: Personal Memory — sqlite-vec + SQLCipher¶
Status: Accepted
Date: 2026-05-18
Deciders: Mohsen Seyedkazemi Ardebili
Context¶
The personal-memory layer is the foundation for the agent loop's recall capability and v2 RAG-augmented reasoning. Three trade-offs drive the decision: embedded vs. server-based vector store; encryption-at-rest scheme; and which embedding model to bundle. An unencrypted, vendor-controlled personal memory store is a privacy and security failure — the Microsoft Recall 2024 launch is the public example of this failure mode. YazSes' commitment is the opposite: user-controlled, encrypted at rest, fully local.
sqlite-vec is the canonical embedded vector store in 2026: pure C, no external dependencies, KNN and ANN, runs on every platform where SQLite runs. SQLCipher provides AES-256 encryption at rest with a user-derived key. Spike S-4 (2026-05-18) confirmed that sqlite-vec and SQLCipher coexist without issue when compiled with SQLITE_CORE and PRAGMA cache_size tuned appropriately.
Decision¶
The personal-memory store is SQLite + sqlite-vec + SQLCipher, with a bundled BGE-small-en embedding model (384-dimensional; all-MiniLM-L6-v2 as fallback) for query and commit embeddings.
Key implementation details:
- Encrypted database at
~/.local/share/yazses/memory.db. - Encryption key: PBKDF2-derived (default 256k iterations) from a user passphrase + a machine-bound salt at
~/.local/share/yazses/.salt, protected by OS file ACLs. - Passphrase ceremony: first
commit_to_memoryinvocation triggersyazses memory init, which prompts for a passphrase; the derived key is held in daemon RAM for the session lifetime. - Schema: a
vec0virtual table with columns for embedding (float[384]), transcript, source, EditorContext JSON blob, tags, creation timestamp, and TTL. - TTL enforcement: an in-process sweeper deletes expired records on a configurable cadence (default once per hour).
forget_last(minutes)is both a typed LLM tool and a CLI command (yazses memory forget --last 30m).PRAGMA cache_size = -200000(200 MB) is required for acceptable KNN query performance at 100k records. Without this setting SQLCipher re-decrypts embedding pages on every query; with it, P50 query latency is 4 ms vs 40 ms at 10k records.
Consequences¶
Positive: - Single-file encrypted storage on every platform SQLite supports. - Fully auditable via standard SQL tooling once unlocked — transparent to the user. - Open-source dependency chain: sqlite-vec (Apache-2.0), SQLCipher (BSD-3-Clause). - ANN index paths (IVF, DiskANN) are available for scale beyond the brute-force regime (~100k records). - The schema is open and documented; community plugins for personal memory analytics are straightforward.
Negative / trade-offs: - Passphrase loss equals data loss. There is no recovery path by design — any recovery mechanism is a privacy backdoor. - BGE-small adds approximately 80 MB to the install footprint. - SQLCipher is open-source but maintained by a commercial entity (Zetetic); sqleet exists as an alternative fallback if the licence situation evolves unfavourably.
Implementation¶
The PersonalMemory module is in yazses-memory/src/. SQLite FFI uses rusqlite with the sqlcipher feature. sqlite-vec is loaded as a runtime extension. The embedding model runs via ort (ONNX Runtime) in yazses-memory/src/embedder.rs. Memory CLI commands are wired through the IPC layer (see ADR-010).