Search

Search is lexical by default — fast, offline, no model required — with graceful fallbacks so natural phrasing still works.

Query forms

  • Tokensdeja connection pool matches records containing both words (AND).
  • Phrasesdeja '"connection pool exhausted"' requires the exact contiguous phrase.
  • Regexdeja --re "timeout|deadline exceeded".
  • Filters--harness, --project, --since 30d, --role assistant.

When nothing matches exactly

On zero results deja widens the net in order, and marks how each hit was found:

  • Stop-word handling — natural phrasing like "have we dealt with jwt refresh rotation" drops filler words so the content tokens drive the search.
  • Word formsrotationrotated via suffix folding.
  • Typos — close spellings within edit distance.
  • Semantic — if a vector sidecar exists, a rephrased query with no shared words still matches.

Each result carries a tier — exact, close (with the variant), or semantic (with the cosine) — in the CLI, JSON and MCP output.

Semantic recall

deja embed          # build a vector sidecar from a local embedding endpoint
deja "ran out of db connections"   # matches "connection pool exhausted"

Resolution: DEJA_EMBED_URL, else a probed Ollama or LM Studio. No endpoint, no semantic layer — search is unchanged.

Natural-language queries

Stop words are dropped, word forms bridge morphology in both directions (failing finds fails), and when no session holds every remaining token deja drops up to two — telling you exactly which (ignoring "why" — no session matches it together with the rest). Zero results now mean the content genuinely is not there.

Search by time

Every message also carries its month and year as searchable tokens, so deja "what did we do in may" meets May's sessions structurally, and relative phrases resolve against the moment you ask: a week ago, last month, 10 days ago. These are ranking hints, not filters — for a hard cutoff use --since.

Earlier attempts

When an old session and a newer one from the same project match the same ground, the older hit is labeled an earlier attempt with the newer session's date — in CLI output, MCP digests, and as an additive superseded field in --json. History stays; the direction the project moved is visible.