Use
Search
This page is for anyone looking something up in their own corpus: how a search is ranked, the filters you can type into a query, the commands that read, trace and delete what you find, and read-only SQL over structured data. The same search runs in the portal, the CLI and the mobile apps; the agent uses it too when it answers a question.
Searching
A search runs your query two ways at once: as BM25 keyword matching over full-text chunks, and as vector similarity against embeddings of the same chunks. The two ranked lists are merged with Reciprocal Rank Fusion (RRF), which rewards a document for ranking high on either list, so a document that matches your exact words or only your meaning still surfaces near the top.
Small indexed scopes use bounded exact vector scoring, so unrelated source updates do not change their nearest-neighbor ranking. Larger scopes use approximate search; its recall can change as the index evolves. Visibility and source filters apply to both.
During a backfill, completed indexing pages become searchable while later pages are still processing. Results remain incomplete until indexing catches up; a completed scan can still contain documents that were skipped or could not be embedded.
Keyword matching ranks from a copy of the full-text index that the gateway holds in
memory, so it takes milliseconds even for queries made of common words. The copy is built
in the background after the gateway starts and rebuilt as your corpus changes; until it is
ready, searches rank from the index on disk. It uses memory in proportion to your corpus,
about 0.7 GB for 200,000 emails, files and messages, and up to twice that while a rebuild
runs. Set search.bm25.memoryIndex to false in
omnesis.json and restart the gateway to rank from disk only.
-
Query
invoice from:maya after:2026-01-01 - ParseInline filters split from the free text; person filters resolved to people
Keyword
- BM25Full-text match over chunks
Always runs.
Semantic
- EmbedThe free text becomes a vector
- Nearest chunksVector index lookup
Skipped until an embedder is assigned and chunks are embedded.
- FuseReciprocal Rank Fusion of both lists
-
RankType boosts from
search.boostsand a balance across sources - ResultsDuplicates dropped, top results kept, each with a short ID
-
Read
omnesis show <id>
Filters restrict every lane before anything is ranked. The ranking settings, including
search.boosts.typeBoosts, are described under
Operating → Configuration.
The semantic lane needs an embedder assigned (see Operating → Models) and chunks that have already been embedded. Documents are indexed for keyword search even without an embedding model. Until both hold, keyword matching alone carries queries, and meaning-aware ranking joins in for each document as its vectors land. There is nothing to switch on; the pipeline uses whatever signals exist at query time. When embeddings become available after keyword-only indexing, vectors are rebuilt for the retained corpus while keyword results remain available. Search responses report the active embedding model as assignments change, without requiring a gateway restart. The semantic lane also stays off while the vector index does not fit in the gateway's memory budget; see Semantic search is degraded.
A query made only of filters, with no free text (from:maya type:email), skips
ranking altogether and lists the matching documents newest first.
❯ omnesis search "lease renewal"
1. Re: Lease renewal — 12-month extension (8.3%) a1b2c3d4 gmail email 05/14/26 Maya Reeves Attached is the signed renewal for the 12-month extension starting July 1... https://mail.google.com/mail/u/0/?authuser=you%40example.com#all/18f2a9c4e7b1d3a0 2. Lease renewal checklist (6.1%) e5f6a7b8 apple-notes note 05/02/26 Confirm the deposit terms, ask about bike storage, forward the signed copy...
2 results in 41ms, bm25:8ms, vec:23ms
# narrow with inline filters and a result cap
❯ omnesis search "invoice from:maya after:2026-01-01" --limit 5
Each result leads with a short document ID you can paste straight into
omnesis show, and ends with a link to the original when the source provides
one. The portal's search page and the apps run the same pipeline against the same index,
with the same query language. The portal's search address carries its query
(/portal/search?q=lease%20renewal), so a search can be bookmarked or linked.
Time in queries
Words that name a time, such as last week, tomorrow,
in March, Q3 2025 or 15 juin, are read as a
calendar window. A third lane then ranks only the documents inside that window by the rest
of the query, within the same filters, and its list is fused with the keyword and semantic
lists. A document is inside the window when it was sent or written there, or when it is
about a day there: a calendar event, a booking, or a date mentioned in its text. So
dentist next month finds the confirmation that arrived weeks ago, and
invoice from last March prefers that March's invoice over older ones that use
the same words.
The window is a preference, not a filter: a strong match from another time still appears.
To restrict results to a range, use after: and before: (see
Query syntax). A day or month written without a year reads as
its nearer occurrence, or as both the last and the next one when they are close or when
the period is a month or longer; words like last, ago and
paid, or next, upcoming and tomorrow,
settle the direction. English, French and Spanish phrases are read, in the time zone the
client sends (the portal, the CLI and the agents send theirs) or else the gateway's. The
lane is on by default; set search.temporal.enabled to false in
omnesis.json and restart the gateway to turn it off.
search.temporal.weight sets its weight in the fusion.
Graph context is enabled by default for unrestricted agent search. Set
search.v2.enabled to false in omnesis.json and
restart the gateway to restore the legacy projection or run an A/B comparison. Operator
portal sessions with read and admin access show additional facts beside search results:
other documents with matching text, device paths and observed connections described in
ordinary sentences. Up to five other document titles are linked inline, with a source icon
before each title. The current document is omitted from that list; IDs and internal edge
codes are hidden. The CLI's --agent-context option exposes the corresponding
agent search projection. Matching extracted text does not establish identical file bytes,
and bounded trails do not establish a complete sharing history. Built-in agents receive
readable graph facts with a document reference table and explicit traversal limits, on the
leading results and on later results that several documents link to. References resolve to
document IDs and available links; matching text does not establish identical file bytes.
The iOS and Android Search screens also show these facts beneath the highest-ranked
results when the gateway supports graph context and search.v2.enabled is
enabled. Linked document titles open in the app. Search rankings and snippets remain
unchanged. An older gateway, or one with graph context disabled, continues to serve
ordinary search results; older apps continue to search an upgraded gateway.
Query syntax
Filters are typed inline, mixed freely with search text. Whatever is left after the filters are stripped becomes the query.
| Filter | Matches | Example |
|---|---|---|
from: |
Person is the sender, author, or owner. Alias: by: |
from:maya |
to: |
Person is a recipient of a message or an attendee of an event | to:"Jamie Lopez" |
with: |
Person appears in any role | with:maya |
type: |
Document type. Alias: in: |
type:email |
source: |
A source or provider — bare type, full source ID, or provider | source:gmail |
after: |
Date lower bound. Alias: since: |
since:"last week" |
before: |
Date upper bound. Alias: until: |
before:2026-03-01 |
#tag |
Tagged documents. Alias: tag: |
#travel |
Values with spaces take quotes (with:"Maya Reeves"). Dates are ISO
YYYY-MM-DD or a relative keyword: today, yesterday,
"last week", "last month", "last year". A date that
fails to parse is dropped, and the response carries a notice saying so (visible with
--json) rather than silently pretending the filter applied. Relative keywords
resolve to a UTC calendar date on the gateway's clock, not the device you are searching
from; pass an absolute date when a day boundary is what the query turns on.
Person filters resolve to people, not strings. A value is matched as an exact email
address, then as an exact phone number, then as part of a name, so
from:maya matches every person whose name contains "maya" (up to ten). Use a
full name to narrow the match or an email address to pin one person, and
me (from:me) for yourself.
Once resolved, every identity merged into that person counts: Omnesis merges identities
across sources into one person (see
People & graphs), so
from:"Maya Reeves" finds her whether a document carries her work email, her
personal address, or her phone number. A value that matches no one is reported as a notice
(visible with --json). Repeating a person filter widens it (from:maya from:jamie
means either); different filters combine with AND.
Beyond search
Search finds documents; these commands work with what you found. The document commands —
show, trail, and delete — accept the short IDs
printed in search results; any unambiguous prefix works.
# read one document in full
❯ omnesis show a1b2c3d4
# find the indexed document for a page you have open
❯ omnesis lookup "https://docs.google.com/document/d/1AbC.../edit"
# the latest documents from one source (IDs from: omnesis sources)
❯ omnesis recent gmail:you@example.com
# the chronological story around a document — replies, attachments, related events
❯ omnesis trail a1b2c3d4
# the same neighbourhood as a graph: documents, people and the links between them
❯ omnesis graph walk a1b2c3d4
# fuzzy people lookup by name, email, phone, or handle
❯ omnesis people search maya
# delete a document for good (a later sync or capture will not add it back)
❯ omnesis delete a1b2c3d4
# delete only this copy; the next sync or capture may add it again
❯ omnesis delete a1b2c3d4 --copy
trail walks the reference graph — thread replies, attachments, links, shared
people — outward from a document and lays the connected documents out in time order. One
invoice becomes the whole story: the quote before it, the chat where it was discussed, the
calendar event it paid for.
graph walk follows the same links but returns the neighbourhood as a graph
rather than a timeline: every document and person reachable from the seed, and the edge
that connects each pair. --edges and --vertex-types limit what
the walk follows, --hops bounds how far it goes (at most 15),
--bound-rows adds the analytics rows bound to the documents it reaches, and
--json prints the raw result.
Deleting has two forms, and the CLI, the portal and the phone apps all offer both. Delete for good removes the document and its extracted attachments, and records that it must stay gone: the source that produced it will not add it back on a later sync or capture, and the analytics rows that were about that page go with it. Removing the whole source clears that record, so a re-added source starts clean. Delete this copy removes the document as well, but the next sync or capture may add it again. Neither touches the original in the provider or on the phone, and neither removes the tasks or memories built on the document: they stay, without their link to it, along with any text they quoted from it.
omnesis delete asks you to confirm, with Cancel preselected unless you passed
--copy; in a script, or with --json, pass --yes. A
day document built from quick captures cannot be deleted directly: delete or amend its
notes on the portal's Tell Omnesis page instead.
SQL over your analytics
Structured sources — health metrics, screen time, workouts, browser visits — land as typed
rows in an analytics database (DuckDB) alongside the document index.
omnesis analytics lists every table with its description and row count (add
--json for column schemas); omnesis sql queries them directly,
as does the Debug → Data tools → SQL tab in the portal.
# which apps ate the last 30 days?
❯ omnesis sql "SELECT app_name, round(sum(total_seconds)/3600.0, 1) AS hours FROM screen_time_daily WHERE date >= current_date - INTERVAL 30 DAY GROUP BY app_name ORDER BY hours DESC LIMIT 3"
app_name hours ─────────────── Safari 31.4 Mail 18.2 Messages 12.9
3 rows (12ms)
# monthly running volume this year
❯ omnesis sql "SELECT strftime(start_time_local, '%Y-%m') AS month, round(sum(distance_m)/1000.0, 1) AS km FROM strava_activities WHERE sport_type = 'Run' GROUP BY 1 ORDER BY 1"
Queries are read-only by construction: each one runs inside a read-only transaction on the gateway's own database instance, whose access to the filesystem is switched off, so SQL can inspect your data but never modify it or reach outside the database. Which tables exist depends on which sources you have connected.
A timestamp stored with its zone comes back as a UTC instant
(2026-10-18T17:28:00.000Z), a date as YYYY-MM-DD, and a
timestamp stored without a zone as the wall-clock time the source recorded.
From your own tools
Everything on this page is a thin client over the gateway's authenticated HTTPS API. The
portal, the CLI and the apps all call the same endpoints, and so can any script holding a
token; Setup → Tokens covers minting one with
omnesis tokens create and choosing its scopes. To let an AI tool such as
Claude or ChatGPT search your corpus, connect it over MCP instead: see
Agents & MCP. The full command list is in
omnesis --help.
The graph walk behind omnesis graph walk is one endpoint,
POST /graph/walk, open to any token with the read scope. It
starts from up to 50 documents, named by ID or unambiguous prefix, takes the same limits
as the command's flags, and returns the vertices and edges it
reached, with truncated set when a limit cut the walk short.
curl -s -X POST "$OMNESIS_GATEWAY_URL/graph/walk" \
-H "Authorization: Bearer $OMNESIS_TOKEN" -H "Content-Type: application/json" \
-d '{"start": [{"kind": "document", "id": "a1b2c3d4"}], "maxHops": 2}'