> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cognee.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Rust SDK Search Configuration

> cognee-rust settings for search, the triplet and hybrid retrievers, and search history.

Every value here resolves as `defaults < config.json < .env < env < code`
([precedence](https://docs.cognee.ai/rust/configuration.md#precedence)), and can be set from code with
the [config API](https://docs.cognee.ai/rust/configuration.md#runtime-configuration-api) or
[`cognee-cli config`](https://docs.cognee.ai/rust/configuration#cli-config-subcommand).

## Search

The `search` and `search.hybrid` engine sections tune the standard retrievers;
cognee hands them to `SearchBuilder::with_tuning` (`Settings::search_tuning`).

| Env var | Key (alias) | Default | Effect |
| - | - | - | - |
| `ALLOW_CYPHER_QUERY` | `search.allow_cypher_query` (`allow_cypher_query`) | `true` | `false` (or `0`/`no`/`off`) refuses the CYPHER and NATURAL\_LANGUAGE search types (Python's flag). Any other value is ignored with a warning and keeps them allowed. Python's flag is off by default and enables them only on `true`, `1`, or `yes` (case-insensitive), so an unset or unrecognized value allows them in Rust but refuses them in Python. |
| `COGNEE_HYBRID_MAX_CONTEXT_TOKENS` | `search.hybrid.max_context_tokens` | *(unset — the LLM's context length)* | HYBRID\_COMPLETION and TEMPORAL context budget in tokens; `0` turns budgeting off. |
| `COGNEE_HYBRID_SUMMARIZE_OVERFLOW` | `search.hybrid.summarize_overflow` | `false` | Summarize passages that overflow the budget instead of dropping them. |
| `COGNEE_HYBRID_SUMMARIZE_BATCH` | `search.hybrid.summarize_batch` | `1` | Overflow passages per summarization call. |
| `COGNEE_HYBRID_OVERFLOW_SUMMARY_FILE` | `search.hybrid.overflow_summary_file` | *(empty)* | JSON object of precomputed overflow summaries (chunk id → summary). |

Three `Settings` fields tune the search orchestrator itself, lowered by the same
`Settings::search_tuning`:

| Env var | `Settings` field | Default | Effect |
| - | - | - | - |
| `ENABLE_LAST_ACCESSED` | `enable_last_accessed` | `false` | Update `last_accessed` on the source data records of every search's retrieved context, as Python does on every retrieval (Python's flag, also default off). On a plain completion search the context is then fetched by the search itself and handed to the retriever, so it is still fetched once. `FEEDBACK` searches retrieve no data and are not tracked. |
| `AUTO_FEEDBACK` | `auto_feedback` | `false` | Detect feedback in a session search's message (one extra LLM call per session turn) when the request leaves `auto_feedback_detection` unset, and only while `session.caching` is on (Python's `caching and auto_feedback`). **Python defaults it to `true`**; Rust keeps it off so a session search makes no extra LLM call unless asked. |
| — | `default_system_prompt_path` | `answer_simple_question.txt` | System prompt file for a search that names neither a system prompt nor a prompt path. The default (Python's file name for the built-in prompt) and an empty value leave each retriever's own compiled-in prompt; any other value is read as a file. Rust-only (Python has no such setting). |

## Triplet retriever hub cap

| Env var | Key | Default | Effect |
| - | - | - | - |
| `COGNEE_TRIPLET_NEIGHBOR_CAP` | `search.triplet_neighbor_cap` | *(unset — uncapped)* | Per vector-search seed, keep every neighbour that is itself a seed plus at most `n` other neighbours (the smallest ids in byte order), then score the subgraph induced on what is kept. |

> [!WARNING]
>
> **Opt-in, and it changes results.** Unset — the default — the triplet retriever
> loads the full depth-1 neighbourhood of its seeds, which is result-identical to
> loading the whole graph. A cap truncates hub fan-out: edges from a hub seed to
> its dropped neighbours never reach the ranking. Those edges would carry the
> non-seed distance penalty and rank below seed-to-seed edges, but they could
> still have made the top *k*.

Measured on a synthetic 100k corpus, a cap of 100 keeps a Jaccard similarity of
0.93–0.96 against the uncapped result set, with a worst query at 0.67; a cap of
200 keeps 0.92–0.93 but has a worst query at 0.18. The latency it buys is small
on a uniform corpus and large on real hub-heavy text (one `graph_completion`
search went from 332 ms to 76 ms). Treat it as a knob for a corpus with known
hubs, measured on that corpus, not as a default.

The cap bounds single-query graph search at depth 1 only: it has no effect with
a `neighborhood_depth` above 1. Batch graph search
(`brute_force_triplet_search_batch`, several queries at once) loads the whole
graph, as Python's batch mode does, and the cap does not apply to it — see
[Operations: search](https://docs.cognee.ai/rust/operations.md#search-retrieval).

`PgGraphAdapter` applies the cap in SQL; every other backend gets the same
semantics from `GraphDBTrait::get_neighborhood_scoped`'s client-side default.

## Hybrid retriever knobs

The `HYBRID_COMPLETION` search type (`SearchType::HybridCompletion`) accepts a
set of per-request tuning knobs. These are **library / orchestrator-only** —
typed `Option<...>` fields on
[`SearchParams`](https://github.com/topoteretes/cognee-rs/blob/main/crates/search/src/types/search_params.rs),
populated from the **snake\_case JSON keys** inside
`SearchRequest.retriever_specific_config`. They have no env binding.

> [!WARNING]
>
> **Not reachable from the CLI.** `cognee-cli search` hardcodes
> `retriever_specific_config: None`, so these knobs are reachable only from a Rust
> caller that builds a `SearchRequest` with a populated `retriever_specific_config`,
> or from a language binding, which forwards its `retrieverSpecificConfig` search
> option verbatim (camelCase option name, snake\_case knob keys inside).

When a knob is unset the retriever falls back through
`retriever_specific_config.<knob>` → `SearchRequest.top_k` capped at 10 → the
`HybridRetriever::new` constructor default (an explicit per-lane knob is never
capped):

| `SearchParams` field / JSON key | Effective Rust default | Python parity |
| - | - | - |
| `chunks_top_k` | `min(top_k, 10)`, else `5` | `chunks_top_k` (derives from `top_k`) |
| `entities_top_k` | `min(top_k, 10)`, else `5` | `entities_top_k` |
| `facts_top_k` | `min(top_k, 10)`, else `5` | `facts_top_k` |
| `max_edges_per_entity` | `10` | `max_edges_per_entity=10` |
| `text_summaries_top_k` | `None` (no fallback) | `text_summaries_top_k=None` |
| `chunk_lane_fusion` | `"relative_score"` | **diverges** — Python is rank-only RRF (`"reciprocal_rank"`) |
| `summary_lane_weight` | `0.75` | no Python equivalent |
| `use_importance_weight` | `true` | `use_importance_weight=True` |
| `node_name` | `None` | reused query node filter |
| `node_name_filter_operator` | `"OR"` | `"OR"` / `"AND"` |
| `candidate_top_k` | `top_k * 4` (TEMPORAL only) | `candidate_top_k` (defaults to `top_k * 4`) |

**TEMPORAL.** `TEMPORAL` search (`SearchType::Temporal`) runs the same hybrid
fetch, so it reads the same keys, with two differences. The fallback above
applies to the `HYBRID_COMPLETION` lanes only: TEMPORAL's `top_k` is
`SearchRequest.top_k` (`5` when unset) and is **not** capped at 10. And its chunk
and entity lanes are sized by `candidate_top_k` and its fact lane by `top_k`,
overriding `chunks_top_k` / `entities_top_k` / `facts_top_k` (`text_summaries_top_k`
is ignored too: the summary lane follows the chunk lane); the time-window
rerank then cuts the candidates back to `top_k`. A `top_k` of `0` or a
`candidate_top_k` below `top_k` is rejected with `InvalidInput`, as in Python.

**Chunk-lane fusion.** `chunk_lane_fusion` chooses how the `DocumentChunk_text`
lane and the `TextSummary_text` lane are combined:

* `"relative_score"` (default) normalises each lane's similarities to `[0, 1]`
  against that lane's own candidates and adds them, the summary lane weighted by
  `summary_lane_weight` (the chunk lane always weighs `1.0`).
* `"reciprocal_rank"` is Python's `rank_chunk_summary_pairs` verbatim — RRF over
  ranks only.

The default diverges deliberately: RRF's constant is calibrated for candidate
lists of thousands, and on these short lists "present in both lanes" outranks
"similar to the query". Measured over 15 probe questions on *Alice in
Wonderland*, relative-score fusion raised MRR in all four tested configurations
(0.35–0.54 → 0.47–0.56). Set `chunk_lane_fusion = "reciprocal_rank"` to get the
Python ranking back.

**Reserved (Phase 2, inert).** These keys are parsed and stored but have no
effect yet: `use_truth_weight` (default `false`), `include_global_context_index`
(default `false`) and `global_context_index_top_k` (default `3`). The
HTTP-facing degradation notes live with the server's search-router docs, which
are not part of the `cognee-rs` repository.

## Search history

| Env var | `Settings` field | Default |
| - | - | - |
| `COGNEE_LOG_SEARCH_HISTORY` | `log_search_history` | `true` |

When on, each search (CLI `search` / `recall`, bindings) records one query row
and one result row after retrieval. They carry the searched dataset's
`dataset_id` when exactly one dataset was searched. Turn it off with
`cognee-cli config set log_search_history false` or
`COGNEE_LOG_SEARCH_HISTORY=false`. This setting is the only switch: the
per-request `SearchRequest::save_interaction` (`saveInteraction` /
`save_interaction` in the bindings) is removed, and CLI `search`, which used
to skip history, now records it too.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.