FAQ
Short answers to the questions that come up most. For “is this the right tool” see Positioning.
Does engrava call an LLM? Do I need an API key?
No. engrava never calls a language model and needs no API key to run. It stores and retrieves what your agent gives it; deciding what to remember (extraction, summarisation) is your agent’s job, above the storage layer. The one feature that synthesises new thoughts — dreaming — is purely structural (clustering, centroids, keyword counts), with no LLM involved.
An API key is only relevant if you choose a remote embedding provider (e.g. an OpenAI-compatible endpoint) — and that’s for embeddings, not for any engrava-side reasoning.
Does it need network access or any running service?
No. engrava is an embedded library built on SQLite — one pip install, runs
in-process, no server, no network. The only time network is involved is if you
configure a remote embedding provider yourself.
Are embeddings required?
No. Without an embedding provider, search runs on FTS5/BM25 (keyword), priority,
and recency signals — semantic vector matching is simply skipped. Add a provider
(local or remote) when you want semantic retrieval. Note that storing on write
only embeds when you set both an embedding provider and auto_embed=True.
How large a corpus can it handle?
The default vector backend brute-forces cosine similarity in Python, which works
well up to roughly 100k embeddings. Beyond that, install the sqlite-vec
backend (pip install engrava[vec], then set extensions.vector.backend: sqlite-vec) for indexed vector search. FTS5 scales well independently. SQLite
itself has been exercised into the multi-GB / millions-of-thoughts range. See
Known Limitations.
Can multiple processes or tasks use the same store at once?
A single process can drive many async tasks against one store safely —
aiosqlite serialises them on its background thread, and WAL mode lets readers and
a single writer coexist. SQLite is single-writer, so heavy concurrent writes
from multiple processes are out of scope. For multi-tenant isolation, give
each tenant its own database file via EngravaManager (each has its own lock).
See Known Limitations → Concurrent Write Safety.
How do I scope search to one user or session?
The search_* methods are unscoped by default — they take no user_id /
session_id filter and rank across the whole store. Scope it yourself with one
of three patterns: over-fetch + post-filter, one store per tenant via
EngravaManager, or a raw-SQL pre-filter on metadata_json with json_extract.
The tradeoffs are laid out in the
migration guide’s scoping section.
When should I enable dreaming?
Enable dreaming when memory accumulates over time
and you want the store to surface and link what matters: it promotes important
thoughts to P1, builds associative edges, and clusters related thoughts into
REFLECTION summaries. It is not useful on a tiny or write-once store. Run it
periodically (every N cycles, a cron job, or manually) — never on the hot CRUD
path. For single-write batch ingest, keep allow_zero_confirmation=True or
nothing will ever pass the confirmation gate.
What is a “cycle” and do I have to manage it?
A cycle is a consumer-owned monotonic logical clock — your agent’s tick.
engrava never advances or persists it for you; you pass current_cycle into
search and consolidation. It drives the recency signal and the dreaming age gate.
On restart, recover it from max(created_cycle) in the store.
Two ways to get it wrong have different effects: passing current_cycle=None
(the search_hybrid default) makes the recency signal inactive — it is
dropped from the ranking. Passing a constant (e.g. always 0, never
advancing created_cycle/updated_cycle) keeps recency active but useless —
every thought’s age collapses to the same value, so nothing looks more recent
than anything else, and the dreaming age gate (min_age_cycles) never opens.
Advance the cycle each turn.
How do I back up the database safely?
Because engrava uses WAL mode, a naive copy of just the .db file can miss
in-flight data in the -wal file. Use a WAL-safe approach — checkpoint then
copy, VACUUM INTO, or SQLite’s backup API. Note that a logical snapshot does
not include the audit journal. See the OSS
backup-and-recovery
docs for current guidance.
Is the audit trail tamper-proof?
It is tamper-evident, not tamper-proof. The journal is a keyless in-file
SHA-256 hash chain: it reliably detects accidental corruption and naive edits or
truncation, but a write-capable actor who rewrites the whole file and recomputes
the chain is out of its threat model. Treat it as integrity evidence with OS
file permissions and periodic off-box verification, not as a cryptographic
guarantee against a privileged attacker. It is off by default
(journal.enabled: false). See Configuration → journal
and the OSS
Audit Trail
docs.
Is engrava production-ready?
engrava is published on PyPI and maintained to a strict quality bar (typed, linted, high test coverage). For production, the things to plan are the same as for any embedded SQLite system: pick the right vector backend for your corpus size, respect the single-writer model, set up WAL-safe backups, monitor with the Observability snapshot API, and (if you need it) enable and verify the audit trail. The OSS Known Limitations page is the honest list of constraints to design around.