JSON wire format
The canonical machine representation of a SemQL query, key by key.
The JSON form is what implementations exchange. Every text query compiles to it, and a client may submit either.
Top level
{
"match": { },
"namespace": { },
"window": "P30D",
"limit": 50
}
| Key | Required | Description |
|---|---|---|
match |
yes | The boolean expression |
namespace |
no | Namespace selector |
window |
no | ISO 8601 duration |
limit |
no | Positive integer |
Expressions
Boolean composition uses and, or and not. A bare clause object is itself
a valid expression, so a single-clause query needs no wrapper.
{ "and": [ { "distance": { } }, { "direction": { } } ] }
{ "or": [ { "distance": { } }, { "direction": { } } ] }
{ "not": { "distance": { } } }
and and or take at least two children; not takes exactly one. See
composition.
Clauses
{ "distance": { "anchor": "payment failure", "within": 0.8 } }
{ "direction": { "toward": ["customer frustration"], "cone": 0.4 } }
{ "contrast": { "attract": ["enterprise"], "repel": ["free tier"], "within": 0.75 } }
Field tables live with each clause:
DISTANCE,
DIRECTION,
CONTRAST.
Anchors
A string, which the host embeds, or an array of numbers, which is already an embedding:
"payment reconciliation failure"
[0.182, -0.041, 0.389, 0.057]
See anchors for when each is appropriate.
Namespace selector
{
"include": ["org:acme-corp", "org:acme-eu"],
"exclude": ["org:acme-staging"],
"global": true,
"all": false
}
The text keywords GLOBAL and ALL map to the two booleans. See
modifiers.
Durations
The JSON form is always ISO 8601 — "PT30S", "PT15M", "PT24H", "P7D",
"P28D". The text parser also accepts the shorthand (30s, 15m, 24h,
7d, 4w), but the serializer only ever emits ISO 8601.
A round trip therefore normalizes: 4w comes back as "P28D".
Conversion is lossless, with one exception
The two forms are interconvertible, except for one field.
metric on DISTANCE exists only in JSON. There is
no METRIC keyword in the text grammar, so:
- a JSON query using
"euclidean"or"dot"cannot be expressed as text; - converting such a query to text and back silently returns it to the
"cosine"default, with no error and no warning.
The published specification states twice that the two representations are
losslessly interconvertible. For every field except metric, they are.
If you use a non-default metric, keep the query in JSON and do not round-trip it through text.