open-mem's search goes beyond simple keyword matching. When you call mem-find, it can combine full-text search, vector similarity, knowledge graph traversal, and LLM reranking to surface the most relevant observations — even when you don't remember the exact words used.
mem-find runs a multi-stage pipeline:
- Query parsing — extracts keywords and intent from your search query
- FTS5 full-text search — fast keyword matching against titles, narratives, concepts, and facts
- Vector similarity search (when available) — semantic matching using embeddings
- Reciprocal Rank Fusion — merges results from both search methods
- Graph augmentation (when entity extraction is enabled) — adds related observations from the knowledge graph
- LLM reranking (when enabled) — re-scores candidates using the AI provider
- Filtering — applies type filters and returns top results
SQLite's FTS5 extension provides fast keyword-based search. It indexes:
- Observation titles
- Narratives and facts
- Concepts/tags
- File paths
FTS5 excels at exact keyword matches and phrase queries.
When an AI provider with embedding support is configured, open-mem generates vector embeddings for each observation. These enable semantic search — finding conceptually related results even when exact keywords don't match.
Providers with embedding support:
| Provider | Embedding Model | Status |
|---|---|---|
| Google Gemini | text-embedding-004 |
Supported |
| OpenAI | text-embedding-3-small |
Supported |
| AWS Bedrock | amazon.titan-embed-text-v2:0 |
Supported |
| Anthropic | — | No embedding model (FTS5-only) |
| OpenRouter | — | No embedding model (FTS5-only) |
If no embedding model is available, search falls back to FTS5-only with no degradation in functionality.
When both FTS5 and vector search return results, open-mem merges them using Reciprocal Rank Fusion. RRF combines ranked lists by assigning each result a score based on its position in each list:
RRF_score = Σ (1 / (k + rank_i))
This produces a single ranked list that balances keyword relevance with semantic similarity.
When entity extraction is enabled (OPEN_MEM_ENTITY_EXTRACTION=true), open-mem builds a knowledge graph alongside the observation store. During compression, it extracts entities (technologies, libraries, patterns, concepts, files) and their relationships (uses, depends_on, implements, extends, etc.) from each observation.
At search time, graph-augmented search works like this:
- Extract entity candidates from the query
- Look up matching entities in the graph
- Traverse their relationships (one hop) to find related entities
- Collect observations linked to those related entities
- Append them to the base FTS5/vector results (deduplicated)
This surfaces connections that keyword and embedding search would miss. For example, searching for "authentication" might also return observations about "JWT" or "session tokens" if the graph knows they're related.
Entity types and relationship types are defined by the active workflow mode.
For high-stakes searches, you can enable LLM-based reranking (OPEN_MEM_RERANKING=true). After the initial search pipeline produces candidates, the reranker sends them to your AI provider to judge relevance against the original query.
This is more expensive (one LLM call per search) but produces noticeably better results when the candidate pool is large or the query is ambiguous. Configure with:
export OPEN_MEM_RERANKING=true
export OPEN_MEM_RERANKING_MAX_CANDIDATES=20 # defaultThe reranker respects the rate limiter and fallback chain like all other AI operations.
Best for finding specific terms, function names, or file paths:
mem-find({ query: "calculateDiscount" })
mem-find({ query: "src/pricing.ts" })Best for finding observations about a topic:
mem-find({ query: "authentication flow" })
mem-find({ query: "database migration strategy" })Narrow results to specific observation types:
mem-find({ query: "pricing", type: "decision" })
mem-find({ query: "login", type: "bugfix" })Available types: decision, bugfix, feature, refactor, discovery, change.
Embeddings are generated automatically during observation processing:
- When a pending observation is compressed by AI, the processor also generates an embedding vector
- The vector is stored alongside the observation in the SQLite database (via
sqlite-vec) - At search time, the query is embedded and compared against stored vectors using cosine similarity
No manual configuration is needed — if your provider supports embeddings, they're generated automatically.
- Be specific — "pricing calculation bug in cart" works better than "bug"
- Use file paths — searching for a file path finds all observations related to that file
- Filter by type — if you know you're looking for a decision, filter to reduce noise
- Start broad, then narrow — use
mem-findwith a broad query, thenmem-getfor details - Combine with history — use
mem-historywith an anchor to see temporal context around a result