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.
Names on this page are verified; the default values are not
Every variable below was checked against the shipped v0.9.8 and v0.9.9 binaries, and the ones that
aren't read are called out where they appear. The default values, though, are inherited from the v1
documentation: they are compiled numeric constants, so they don't surface in the boot-time
config_lint dump (which covers a
different set of variables) and can't be read back from a running server. Treat them as indicative. If
a specific value matters to your deployment, confirm it 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 — verified via
diagnostics: "full" (only recall.bm25_search, recall.vector_search, recall.fusion fire). 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). |
Verified: recency needs the holistic view
On v0.9.9 the timeline tail is applied in holistic view (the recall default). In granular / raw
views order=recency is a no-op — events return oldest-first and an events cap keeps the oldest N.
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, not TENANT
The v1 docs called this CORTEX_VECTOR_TENANT_OVERFETCH. That name is not read by the server —
verified against the shipped v0.9.8 and v0.9.9 binaries, which contain
CORTEX_VECTOR_POSTFILTER_OVERFETCH instead. Setting the old name 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. |
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. |
Seven switches the v1 docs list do not exist
The v1 page documents a larger table. These names are not read by the server — verified against the
shipped v0.9.8 and v0.9.9 binaries, which contain no such string, so setting them does nothing:
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,
CORTEX_ENUMERATE_COUNT_ENABLE. Only the three above are real. (The binary does carry further
CORTEX_MS_* switches beyond these — they're internal and undocumented, so they're deliberately not
listed here rather than guessed at.)
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 sub-100ms config
- Embeddings — vector dim and model choice
- Benchmarking — how 93.8% was produced with these defaults