Retrieval modes
August 9, 2026 · View on GitHub
Perseus Vault exposes a broad retrieval surface — keyword, vector, fused, graph, and proactive/temporal recall — through a single memory store. This page enumerates every mode in one place: what it is, when to reach for it, how to invoke it, and a minimal example.
Tool names. The canonical MCP tool prefix is
perseus_vault_*(the legacyperseus_vault_*/perseus_vault_*aliases remain callable). CLI verbs are shown asperseus-vault <verb>.
At a glance
| Mode | Mechanism | Best for | Invocation |
|---|---|---|---|
| FTS5 (keyword) | SQLite FTS5, Porter-stemmed BM25 | Exact terms, identifiers, quotes; fully offline, no embeddings | perseus_vault_recall mode="fts5" |
| Dense (vector) | Bundled 384-dim MiniLM embeddings, cosine similarity | Meaning-based recall, paraphrases, "find things like this" | perseus_vault_recall mode="dense" |
| Hybrid (RRF) | Reciprocal-rank fusion of BM25 + dense | Best general-purpose recall; the default when embeddings exist | perseus_vault_recall mode="hybrid" (or omit mode) |
| Graph traversal | Walk the entity link graph to a set depth | "What connects to X"; following decisions/evidence chains | perseus_vault_traverse |
| GraphRAG — communities | Deterministic community detection over the link graph | Discovering clusters/themes in a large store | perseus_vault_communities |
| GraphRAG — community summary | Extractive (optionally LLM-polished) summary of one community | A synthesized overview of a cluster, materialized as an entity | perseus_vault_community_summary |
| GraphRAG — global recall | Breadth over community summaries, then depth into the best | Holistic answers that span clusters, not a single hit | perseus_vault_global_recall |
Proactive (recall_when) | Surface entities whose recall_when triggers match context | Just-in-time injection with no explicit query | perseus_vault_recall_when |
Temporal (as_of) | Bitemporal point-in-time reconstruction | "What did we believe on date D"; auditing history | perseus_vault_recall / perseus_vault_as_of with as_of_unix_ms |
Mode selection
perseus_vault_recall with no mode automatically selects hybrid whenever
dense embeddings exist for the store, and transparently falls back to fts5
keyword search when they do not. Pass mode explicitly to pin a specific arm:
mode="fts5"— keyword only; deterministic, zero-embedding, air-gap friendly.mode="dense"— vector only; meaning-based, no keyword fallback.mode="hybrid"— both arms fused via RRF (recovers dense's rank-1 dilution while keeping keyword precision).
Examples
Retrieval is invoked as MCP tool calls against a running perseus-vault serve
(the CLI itself is for admin/write/maintenance). Arguments below are shown as the
tools/call payload.
Keyword (BM25):
perseus_vault_recall { "query": "SSRF localhost health check", "mode": "fts5", "limit": 10 }
Dense / semantic:
perseus_vault_recall { "query": "how do we keep memory off the GPU", "mode": "dense", "limit": 10 }
Hybrid (default when embeddings exist — omit mode):
perseus_vault_recall { "query": "recall latency under load", "limit": 10 }
GraphRAG global recall (holistic, cross-cluster):
perseus_vault_global_recall { "query": "what are the main architectural themes" }
Proactive recall (no query — recall_when triggers + context match). Available
as the perseus_vault_recall_when tool, and pre-turn via the CLI prepare verb:
perseus-vault prepare --db perseus_vault.db "editing the audit-chain module"
Temporal point-in-time (what a fact looked like at an instant):
perseus_vault_recall { "query": "decay policy", "mode": "fts5", "as_of_unix_ms": 1750000000000 }
Notes
- Query contract: empty string enumerates,
*is a literal (#562). An emptyquery("") is the deliberate match-all / enumeration path: it drops the keyword predicate and returns every entity in scope (respectingcategory,type,limit,offset, and the other filters), ranked by the store's default order. Wildcards are not globs —query="*"is treated as the literal FTS5 term*and matches nothing (0 results). To "list all", passquery=""; to search, pass real terms. - Paginated enumeration / scan (#562). The first-class enumeration path is
the dedicated
perseus_vault_scantool: keyset pages ordered by immutable entityid ASCwith anext_cursor/has_morecontinuation contract. Call it with no cursor for the first page, then feed each page'snext_cursorback in untilhas_moreis false — every entity in scope is returned exactly once. It is read-only (no retrieval-count/decay side-effects) and has no depth cap. Prefer it over pagingrecall(query="")withoffset: recall's ranking keys (retrieval_count,last_accessed) mutate as recalls reinforce entities, so offset pages can skip or repeat rows under concurrent use, and recall'soffsetis clamped at 10,000. The official Python client'sVaultClient.scan(category)uses the scan tool automatically (falling back to offset-paged recall only on pre-#562 servers). - Startup-optimized ranking (
startup: true, #675/#676). For startup / pre-session recall, passstartup: true: recall over-fetches a candidate pool and re-ranks it by actionability — memories that carry concrete anchors (issue/ticket keys,#refs, paths, URLs, named systems, decision/escalation language) outrank vague, date-only, or very short near-neighbors — then truncates tolimit. Each item also gets anactionabilityscore (0.0–1.0). Off by default (order is byte-identical without the flag). To find the low-signal memories dragging a startup block down, run the read-onlyperseus_vault_hygienereport. - Offline by default. FTS5, dense (bundled model), hybrid, graph, and
temporal modes all run with zero network calls. Dense embeddings can
optionally be generated via Ollama or an OpenAI-compatible endpoint
(
perseus_vault_embed), but the bundled MiniLM model needs neither. - Recall quality at scale. Keyword recall degrades on large distinct-content
corpora where hybrid holds; see
benchmark/for measured recall@k across modes. - Provenance. All modes return deterministic, inspectable results; see deterministic-recall-and-provenance.md.
- Validity-aware profile (#860). Any recall mode accepts
profile: "validity"(and/orvalidity_annotate: true) to weigh freshness, scope match, provenance class, supersession, and expiry proximity into a per-hit validity block — fused mode additionally re-ranks the pool by the multiplier; see validity-aware-recall.md.
See also: the full tool reference in the README.