Search and retrieval
How hybrid retrieval, rerank, temporal metadata, and supersedes filtering shape results.
Hybrid retrieval
Hybrid search is the query path for REST, chat, CLI search, and the search_knowledge MCP tool. Browse endpoints list indexed rows; hybrid search answers a query.
The retrieval contract runs semantic chunk search, full-text chunk search, and document-level summary search in parallel. Results are merged by knowledge and chunk identity before ranking continues.
- Semantic search matches the query embedding against chunk embeddings.
- Full-text search matches lexical terms over indexed chunks.
- Document-level search matches the query against title, summary, and tags so broad document matches are not missed.
Ranking and score honesty
Merge-only scores are useful for ordering but are not calibrated across every branch. Full-text hits currently use a fixed score, while vector and summary hits come from embedding similarity.
When rerank is enabled and quota is available, the service over-fetches candidates, sends the merged pool to the reranker, and uses the reranked scores. Provider errors, timeouts, quota exhaustion, or malformed rerank output fall back to merge-only ordering.
- Chunk-level hits win over document-level hits for the same knowledge row because they produce better citations.
- Rerank is controlled server-side and can be disabled per request for latency-sensitive paths.
- Audit events track rerank calls and temporal/forgotten filter overrides.
Filters and visibility
Every search starts by resolving the caller's visible vaults. Session users, PATs, and MCP clients can only search rows allowed by their active org, vault grants, and action scopes.
Filters narrow that visible set. Common filters include vault, folder, tags, MIME type, date ranges, entity canonical IDs or names, indexing status for browse/list surfaces, and temporal flags.
- Expired and pending rows are hidden by default; include_expired and include_pending are forensic controls.
- Forgotten rows stay out of normal search; dedicated lifecycle surfaces handle Trash and restore.
- Entity filters are best seeded from list_entities or the entities returned by get_knowledge.
Temporal and supersedes behavior
Temporal fields let the system distinguish static reference material, versioned policy-like content, and event-like content. Validity windows can hide rows before their valid_from date or after valid_until.
Temporal scoring applies after merge or rerank. It can favor current valid material without pretending that recency is part of the raw semantic/full-text fusion score.
- content_date is the primary recency anchor when present; updated_at is the fallback.
- Supersedes links can hide older matching rows when a successor also matches.
- At the shipped default temporal weight of zero, temporal multipliers collapse to neutral ranking.
Empty results
Hybrid search returns an empty reason so clients can respond intelligently instead of treating every empty list the same.
- no_visible_vaults means the effective scope is empty.
- no_indexed_knowledge means the scope has no ready indexed content.
- no_matches means indexed content exists, but the query had no recall.
Use search vs. chat
Use search when you need ranked source chunks, filters, or deterministic inspection. Use chat when you want a synthesized answer grounded in those same scoped retrieval results.