Skip to main content
A query says what you want and never names an index. Choosing and combining indices is the implementation’s job, and treating no single index as authoritative is a protocol requirement.

The request

Three parts, and the split is deliberate:
Filters work with no text at all — Query(filters=QueryFilters(memory_types=[MemoryType.PROCEDURAL])) returns everything procedural.
mode names a strategy, never an engine: auto, exact, lexical, semantic, associative. A conforming implementation may ignore it and still be conforming — that is why it lives under hints.

The Evidence Bundle

EvidenceBundle has no answer field. Not omitted — absent by design. Composing prose is your work, and citing block_id is what keeps the answer checkable.
Each match carries everything needed to audit it:
score is a string rather than a float for the same reason a payload refuses floats: a value that round-trips differently in two languages is not a value two clients can compare. See Identity.
No match is an answer, not an error. An empty bundle means the brain holds nothing matching — and since matching is left to the implementation, that is a legitimate result.

Supplying a planner

A planner must return knowledge blocks with their provenance and a retrieval score, must verify every returned block against the installed snapshot, and must treat no single index as authoritative.

The built-in scan

Without a planner, the brain falls back to a term scan:
It drops function words before matching, and it is deliberately not a retrieval engine — correct and unranked. It will not find a synonym. Supply a planner and a vector Index for real semantic retrieval.

Accessibility

By default a superseded or demoted block does not surface. That is a retrieval decision, not a membership one — the block is still in the composition and still proves into the root.
Pass include_superseded=True to see them anyway, which is what an audit wants.