Recall Tuning
Every recall-strategy knob — graph retrieval, HyDE, multihop, salience, reranker, and the constants that aren't (yet) configurable.
CortexDB's recall pipeline can run several retrieval channels and fuse them with reciprocal rank fusion. About a dozen env vars expose knobs into that pipeline; another two dozen are compiled constants tuned against LongMemEval-S and LoCoMo.
Most deployments shouldn't tune any of these — the defaults match the published 93.8% number.
Treat the default values as indicative
The default values below are compiled constants: they don't appear in the boot-time
config_lint dump and can't be read back
from a running server. If a specific value matters to your deployment, confirm its effect with an A/B
rather than relying on the number printed here.
What runs by default vs what's full capability
On a default self-hosted instance, recall runs BM25 + vector + RRF fusion only (with
diagnostics: "full", only recall.bm25_search, recall.vector_search and recall.fusion appear). The
six channels below describe the full capability: the Graph BFS channel needs the knowledge
graph (CORTEX_ENTITY_GRAPH=1 + enrichment), and the cross-encoder reranker needs a Cohere key.
The entity-name / synonym / temporal channels are internal to fusion. See
Self-hosting defaults.
The pipeline at a glance
Query
├─► Query routing ─────────────────────────► question_type
├─► (optional) HyDE multiquery expansion ──► N hypothesized passages → query vectors
├─► (optional) Multihop query planner ─────► M follow-up queries (LLM)
├─► Parallel retrieval channels:
│ • Vector (HNSW) [default]
│ • Fulltext (BM25 + WordNet)[default]
│ • Entity-name (exact/fuzzy)
│ • Synonym
│ • Graph BFS (KG edges) [needs KG + enrichment]
│ • Temporal (recency + decay)
├─► Reciprocal rank fusion (RRF, k=60) ──► fused candidate list
├─► Cross-encoder rerank (optional) ──► reranked top-K [needs Cohere]
└─► Build response pack (citations, beliefs, episodes)Skipping a stage saves latency at the cost of recall accuracy.
Graph retrieval
The KG channel walks edges around entities mentioned in the query.
| Env var | Default | What it controls |
|---|---|---|
CORTEX_GRAPH_RETRIEVAL_DISABLE | (unset) | Set =1 to skip the graph channel. ~-3–5 pp on multi-session. |
CORTEX_GRAPH_RETRIEVAL_TOP_K | 40 (single) / 120 (multi) | Graph-derived candidates passed to fusion. |
Disable on the voice/realtime hot path (trade ~-3 pp for ~150 ms); bump TOP_K to 80/240 for
entity-rich queries. Non-overridable constants: GRAPH_RETRIEVAL_MAX_ENTITIES = 48,
GRAPH_RETRIEVAL_MAX_EDGES = 512, GRAPH_RETRIEVAL_MAX_EPISODES = 256, GRAPH_WEIGHT = 0.20.
HyDE multiquery expansion
HyDE asks an LLM to write a hypothetical passage that would answer the query, then embeds that instead of (or with) the literal query.
| Env var | Default | What it controls |
|---|---|---|
CORTEX_HYDE_PASSAGES_MS | 1 | Hypothetical passages for multi-session queries. 0 disables HyDE for multi-session. |
CORTEX_HYDE_MULTIQUERY_DISABLED_TYPES | multi-session,open-domain | Question types where HyDE is off. |
Set the disabled-types list to all four types to disable HyDE entirely (saves ~150–400 ms, loses
~1–2 pp on phrasing-mismatch queries). CORTEX_HYDE_PASSAGES_MS=3 uses temperatures [0.3, 0.6, 0.9]
for wider coverage at 3× HyDE cost.
Multihop query planner
For complex queries, an LLM plans 2–N follow-up queries, then runs all of them through retrieval.
| Env var | Default | What it controls |
|---|---|---|
CORTEX_MULTIHOP_QUERY_PLANNER_DISABLE | (unset) | Set =1 to disable multihop entirely. |
CORTEX_MULTIHOP_QUERY_PLANNER_TYPES | multi-session,open-domain | Types where multihop runs. |
CORTEX_MULTIHOP_QUERY_COUNT | 4 | Follow-up queries the planner generates. |
CORTEX_MULTIHOP_MAX_QUERY_FANOUT | 5 | Cap on simultaneously executing planned queries. |
CORTEX_MULTIHOP_COVERAGE_ORDER_DISABLE | (unset) | Use LLM-emitted order instead of coverage-optimal reordering. |
Empty the types list for latency-sensitive deployments (saves 1–3 LLM round-trips, loses ~1–3 pp on
complex multi-session); QUERY_COUNT=6 + FANOUT=8 for offline QA.
Salience prior
A per-memory importance score updated by access patterns; the ranker can use it as a recency prior.
| Env var | Default | What it controls |
|---|---|---|
CORTEX_SALIENCE_WEIGHT | 0.10 | Weight of salience in final ranking. Range [0.0, 1.0]. |
CORTEX_AUTO_ROUTE | (unset) | Set =1 to auto-pick per-type salience weights. |
Bump to 0.20 for "recently relevant" agents; set 0.0 for historical-archive workloads (the right
answer might be years old).
Recency ordering
Salience is a prior on ranked retrieval. order=recency is different — it replaces ranked
retrieval for the events layer with a timeline tail: the scope's newest events by observed_at,
rendered newest-first. Set it explicitly on /v1/recall
or /v1/answer, or let /v1/answer infer it for "recent/latest"
questions. It's the right tool for "what's the latest…" reads, where relevance ranking returns the
most-repeated items and can drop the newest ones.
| Env var | Default | What it controls |
|---|---|---|
CORTEX_RECENCY_TAIL_EVENTS | 100 | Tail size when the request sets no budgets.per_layer_limits.events. |
CORTEX_RECENCY_ORDER | (on) | Set =0 to disable the recency mode entirely — an explicit order=recency then falls back to ranked retrieval. |
CORTEX_RECENCY_INFERENCE | (on) | Set =0 to stop /v1/answer auto-inferring recency for recency-shaped questions (an explicit order still applies). |
Recency uses the holistic view
The timeline tail is applied in the holistic view (the recall default); granular and raw keep
relevance order. For "latest X" reads, keep the default view.
Entity-vector seeding
Take the query's entity mentions, look up their canonical vectors, use those as additional query vectors.
| Env var | Default | What it controls |
|---|---|---|
CORTEX_ENTITY_VECTOR_SEED_ENABLE | (unset) | Set =1 to enable. Off by default. |
CORTEX_VECTOR_POSTFILTER_OVERFETCH | (compiled) | Overfetch multiplier so the scope post-filter still hits K. |
The variable is POSTFILTER
The overfetch setting is CORTEX_VECTOR_POSTFILTER_OVERFETCH (a name such as
CORTEX_VECTOR_TENANT_OVERFETCH has no effect).
Enable for queries with named entities that don't match stored phrasing exactly. Constants:
ENTITY_VECTOR_SEED_TOP_K = 10, ENTITY_VECTOR_SEED_MIN_SIMILARITY = 0.40,
ENTITY_VECTOR_SPAN_LIMIT = 5, ENTITY_VECTOR_PER_SPAN_TOP_K = 5.
Reranker
A cross-encoder that re-scores the top ~25–40 fused candidates as (query, candidate) pairs.
| Env var | Default | What it controls |
|---|---|---|
CORTEX_RERANKER_PROVIDER | (empty = disabled) | cohere or local. Empty disables the reranker. |
CORTEX_RERANKER_MODEL | rerank-v3.5 (Cohere) | Model name. |
CORTEX_RERANKER_MODEL_PATH | (none) | Path to a local ONNX model when PROVIDER=local. |
CORTEX_RERANKER_URL | (provider default) | Point the reranker at an endpoint you control. The usage ledger reports such lanes at 0.0 cost by design, and the reranker records no token data at all. |
cohere + COHERE_API_KEY → ~+2 pp on noisy sets, ~$0.001/recall, +80–200 ms. local +
MODEL_PATH → free but ~200–500 ms on CPU. Leave disabled for voice/sub-100ms paths.
Question-type executor switches
The /v1/answer endpoint routes queries through type-specific executors. These flags disable specific
paths for A/B testing.
| Env var | What it controls |
|---|---|
CORTEX_MS_COUNT_RELEVANCE_ENABLE | Count-based relevance scoring for multi-session (experimental). |
CORTEX_FACT_EVENT_PROMOTION_ENABLE | Promote facts to event-level relevance. |
CORTEX_FACT_VALIDITY_FILTER | Filter recalled facts by bi-temporal validity windows. |
Only these switches exist
The switches in the table above are the supported ones. Names such as CORTEX_MS_EXECUTOR_DISABLE,
CORTEX_MS_EVIDENCE_PACK_DISABLE, CORTEX_MS_STAGE_C_USE_VERIFIER, CORTEX_MS_RETRY_ON_ABSTAIN,
CORTEX_TEMPORAL_EXTRACT_DISABLE, CORTEX_COMPOSITIONAL_ENABLE and CORTEX_ENUMERATE_COUNT_ENABLE
have no effect.
Default stance: don't touch these
They exist for benchmark tooling to validate routing decisions; the compiled defaults produced 93.8%. Flip one only as a diagnostic with an A/B harness.
Synchronous-write kill switches
These affect the write path — and thus when recall has the data available.
| Env var | What it controls |
|---|---|
CORTEX_SYNC_FACT_EXTRACT_DISABLE | Skip sync fact extraction; all extraction async. Faster writes; recall lags. |
CORTEX_SYNC_FACT_EXTRACT_MAX_SESSIONS | Cap on sessions processed sync per batch. |
CORTEX_SYNC_GRAPH_SEED_DISABLE | Skip sync graph seeding. Same tradeoff. |
CORTEX_SYNC_GRAPH_SEED_MAX_BULK_MEMORIES / _MAX_ENTITIES | Caps on sync graph seeding. |
Disable for batch ingest (see the Batch profile) or write-heavy workloads that tolerate 30–60 s recall lag.
Memory evolution (methylation + consolidation)
Background jobs that prune low-utility memories and consolidate related ones.
| Env var | Default | What it controls |
|---|---|---|
CORTEX_METHYLATION_INACTIVITY_HOURS | 168 (7 days) | Unaccessed-this-long memories become pruning-eligible. |
CORTEX_METHYLATION_MIN_ACCESS | 10 | Min access count before pruning-eligible. |
CORTEX_METHYLATION_MIN_UTIL_RATIO | 0.30 | Min utility-to-access ratio. |
CORTEX_METHYLATION_MIN_ACCESSES_FOR_RATIO | 5 | Min accesses before the ratio is evaluated. |
CORTEX_CONSOLIDATION_MIN_MEMORIES | 2 | Min same-entity memories to trigger consolidation. |
CORTEX_CONSOLIDATION_MAX_BATCH | 10 | Max consolidations per scheduler tick. |
CORTEX_CONSOLIDATION_MIN_AGE_HOURS | 24 | Memories younger than this aren't consolidated. |
CORTEX_CONSOLIDATION_MAX_SURPRISE | 0.5 | Don't consolidate memories above this surprise score. |
Tighten methylation for chatty agents (INACTIVITY_HOURS=72), loosen for archival
(INACTIVITY_HOURS=720); CORTEX_SCHEDULER_DISABLE=1 disables the whole scheduler for stable
benchmark evals.
Compiled constants you can't (yet) override
Tuned against LongMemEval-S + LoCoMo; file an issue to request promotion to an env var.
| Constant | Value | What it controls |
|---|---|---|
RETRIEVAL_TOP_K / RETRIEVAL_TOP_K_MS | 40 / 160 | Candidates per channel (single / multi-session). |
RERANK_POOL / RERANK_POOL_MS | 25 / 40 | Top-N passed to the reranker. |
RRF_K | 60.0 | Smoothing constant in the RRF formula. |
GRAPH_WEIGHT | 0.20 | Graph channel's fused weight. |
GRAPH_RETRIEVAL_MAX_ENTITIES / _EDGES / _EPISODES | 48 / 512 / 256 | KG walk caps. |
ENTITY_VECTOR_SEED_TOP_K / _MIN_SIMILARITY | 10 / 0.40 | Entity-vector seed caps. |
Latency budget breakdown (default config)
Rough p50 for a single /v1/recall against a ~100K event scope:
| Stage | p50 | Optional? |
|---|---|---|
| Query embedding | ~50 ms | No |
| HyDE multiquery (if enabled) | ~250 ms | Yes — disable per-type |
| Multihop planner (if enabled) | ~400 ms | Yes — disable per-type |
| Vector + fulltext + KG retrieval (parallel) | ~80 ms | No |
| RRF fusion | ~2 ms | No |
| Cross-encoder rerank (if enabled) | ~150 ms | Yes |
| Response pack assembly | ~30 ms | No |
| Total (default, multi-session) | ~900 ms | |
| Total (voice profile, single-session) | ~180 ms |
HyDE and multihop dominate wherever they run — disabling them is the highest-leverage latency win for voice/realtime.
Next steps
- Profiles & Presets — the Voice profile for a low-latency config
- Embeddings — vector dim and model choice
- Benchmarking — how 93.8% was produced with these defaults