Skip to main content

Query Language (MQL)

A compact, composable text syntax for filtering, searching, sorting, and aggregating your memories.

Overview

The Memory Query Language (MQL) lets you express exactly which memories you want in one line: structured filters, boolean logic, graph and geo predicates, full-text and semantic search, aggregation, ordering, and a limit. Run it interactively on the Query page, where you get syntax highlighting, autocomplete of your real spaces and tags, inline error underlines, a plain-English read-out, and one-click refine.

An MQL query
space:work quality>=0.7 created>now-30d ~"postgres decision" order by recency limit 20

A query is an optional filter expression, an optional ~"…" semantic clause, an optional order by, and an optional limit/offset — in that order. Any part can be omitted.

Fields

Predicates take the form field<op>value. The common fields:

  • space, cluster, session — where a memory lives
  • content_type — text, image, audio, … · type (memory_type) — fact, preference, episode, …
  • tags — your labels · origin, source_type — how it arrived
  • pinned, protected — boolean flags
  • created, updated, event_date — timestamps
  • salience, quality, confidence, feedback_score — scores
  • entity, topic, related — graph fields · metadata.* — your custom keys
  • country, region, near, bbox — geo fields

The Query page's cheatsheet lists every field available for your account.

Operators

  • : — equals, or full-text match on content
  • = != — equals / not equals
  • > >= < <= — compare numbers and dates
  • in [a, b] / not in [a, b] — any / none of a list
  • between x and y — inclusive range
  • field:* — field has any value · field:null — field is empty

Combining predicates

A space means and. Use or, not, and parentheses to compose:

space:work tags:urgent          # both (AND)
space:personal or space:work    # either (OR)
not pinned:true                 # negate
(origin:work or origin:private) created>now-7d

Values & time

  • "quoted text" — strings (quote anything with spaces)
  • 0.7 42 — numbers · true false — booleans
  • 2026-01-01 — absolute dates
  • now-7d, today, now+2h — relative time, past or future (units s m h d w)
  • within 30d — sugar for a recent window

Graph filters

Filter through the knowledge graph — extracted entities and topics, clusters, and direct relationships to another memory.

entity:"Postgres"          # memories mentioning an entity
topic:database             # by extracted topic
cluster:"Onboarding"       # within a named cluster
related:<memory-id>        # linked to a specific memory
entity:*                   # has any entity at all

Geo filters

Filter memories by place, radius, or bounding box (for memories with a location).

country:SE                              # ISO country code
region:"California"                     # named region
near:"59.33,18.06,10"                   # within 10 km of lat,lng
bbox:"59.2,17.9,59.4,18.2"              # inside minLat,minLng,maxLat,maxLng

Custom metadata

Any key you store under metadata is queryable with typed comparisons and existence checks:

metadata.priority>=3
metadata.due<now+7d
metadata.owner:"alice"
metadata.reviewed:null

Ordering, limit & offset

  • order by — relevance | recency | quality | confidence | feedback_score | <field> [asc|desc]
  • Sort on multiple keys: order by quality desc, created asc
  • limit 20 — cap the result count · offset 20 — page through results

Aggregation

Instead of a list, ask for a count or a grouped rollup. group by a field and apply count or avg/sum/min/max over a numeric field:

count                             # total matching memories
space:work group by type count    # how many of each memory_type
group by space avg quality        # average quality per space

How it runs

Every valid query runs. Simple filters map directly onto the memory endpoint's parameters; everything richer — score thresholds, type, graph, geo, metadata.*, ranges, aggregation, and any and/or/not combination — is compiled to a parameterised SQL filter on the server and executed after your access checks.

Only the query string travels over the wire — never SQL. Column names come from a fixed field catalogue and every value is a bound parameter, so a query can filter your memories but can never reach beyond them or inject SQL. Invalid queries are rejected with a precise, caret-pointing message before anything runs, and every query runs under a statement timeout.

On the Query page

The interactive Query page turns MQL into a workbench:

  • Result facets — click a type, tag, or space from your results to refine and re-run
  • Cards or table — toggle a dense, sortable grid for scanning many results
  • Export — copy results as Markdown, CSV, or JSON, or download to a file
  • Ask AI — describe what you want in plain English and get an editable MQL query, or "Improve" your current one
  • Advisor — instant, rule-based tips (add a limit, scope a space, prefer structured filters)
  • Saved searches — save a query and run it on a schedule

Examples

Runnable examples
space:work tags:urgent
created>now-7d pinned:true
space:personal or space:work
type:fact quality>=0.7 order by confidence desc
entity:"Postgres" ~"migration plan"
near:"59.33,18.06,25" created>now-90d
group by type count
salience>=0.5 order by recency limit 20 offset 20

Try any of these on the Query page — click an example to load it, then press ⌘/Ctrl+Enter to run.