Querying
Reading is a pipeline: resolve the fast path first, then walk the graph, roll up, or run exact vector search.
FIND vs SCAN
FIND resolves anchor → gravity → scan (fast paths first). SCAN is a filtered lobe walk with a full boolean WHERE; it routes transparently to a ghost when one fits.
FIND "clients" WHERE rfc = "ACME-001" SCAN "creditos" WHERE status = "overdue" AND amount > 1000 LIMIT 50
Paginate large scans with an opaque CURSOR token (no OFFSET).
FETCH
Read several co-located lobes in one call: one record whose fields are a named section per lobe, keyed by a shared WHERE.
FETCH "clientes", "creditos", "operaciones" WHERE rfc = "ACME-001" AS {cliente, creditos, operaciones}
WHERE is required — it's the shared key every lobe co-locates by, so each resolve rides the anchor/gravity fast path. AS renames the sections; omitted, each is named by its lobe.
The pipeline
Chain steps with |. After a FIND/SCAN you can PULL, SET, DELETE, GROUP BY, AGGREGATE, TAKE, SHAPE, NEAREST or FOLLOW.
FIND "clients" WHERE name = "Acme Corp" | PULL depth=2 only=Invoice FIND "creditos" WHERE rfc = "ACME-001" | SET status = "closed"
Aggregate & group
AGGREGATE supports count(), sum, avg, min, max. SCAN | AGGREGATE streams in O(1) memory; a matching precomputed ghost answers with zero scan.
SCAN "creditos" WHERE _type = "Credit" | GROUP BY status | AGGREGATE count(), sum(monto)
Take & shape
TAKE is the canonical top-N / truncate step: n BY metric keeps the top (or bottom) n groups from an AGGREGATE; n alone truncates any stream — the pipeline form of LIMIT. SHAPE projects each record down to named fields, the read-side mirror of PUT.
SCAN "creditos" WHERE _type = "Credit" | GROUP BY rfc | AGGREGATE sum(monto) AS exposicion | TAKE 100 BY exposicion DESC SCAN "clients" WHERE tier = "gold" ORDER BY score DESC LIMIT 10 | SHAPE {name, score}
TOP n BY metric still parses (deprecated alias of TAKE). When a ghost keeps the same metric order, TAKE reads it in O(N) instead of O(M).
NEAREST
Exact top-k over the gravity bucket, canonical phrase form. The query vector is bound out of band as $q, given inline, or taken from another record with REF. Metrics: cosine, dot, l2.
FIND "memories" WHERE topic = "billing" | NEAREST 8 BY embedding TO $q USING cosine SCAN "memories" WHERE topic = "billing" | NEAREST(embedding, REF "mem-42", 5, cosine) # function alias, more like this
USING defaults to cosine in the phrase form; the function alias NEAREST(field, query, k, metric) parses to the same statement. ORBIT was removed in v1 — NEAREST is the only name now. EMBED "text" needs a remote embedding service (opt-in); rejected in the default agnostic mode.
FOLLOW
Cross-entity expansion: resolve a field's value as the matching record in another lobe.
FIND "pagos" WHERE mes = "2026-06" | FOLLOW credito TO "creditos" ON id
DELETE & PURGE
DELETE removes matched records — WHERE is required on the standalone form. PURGE is the explicit, hard-to-typo verb for emptying a whole lobe on purpose.
FIND "fintech" WHERE status = "cancelled" | DELETE DELETE "clients" WHERE name = "Old Corp" PURGE "scratch" # empties the whole lobe
A WHERE-less DELETE used to empty a lobe silently — now it errors and points you to PURGE.
Filters & operators
WHERE is a boolean tree: = != > >= < <=, IS NULL / IS NOT NULL, IN [a, b], CONTAINS (lists), combined with AND / OR / NOT and parentheses. Nested fields use dot notation.
SCAN "creditos" WHERE (status = "overdue" OR amount > 1000) AND NOT closed SCAN "orders" WHERE items.0.price >= 50 AND tags CONTAINS "vip" SCAN "creditos" WHERE status IN ["active", "overdue"]
Note · Null = Null is true (unlike SQL). IN (a, b) parenthesized form still parses.