Query a database you've never seen,
in your own words

sans_schema — a Semantic Query Gateway

sans-schema-playground.vercel.app

QR code to the playground

Open it now — you'll use it during the talk.

Every client hardcodes someone else's schema

{want, where} — your words, their data

POST /query
{
  "want": ["book name", "writer", "cost"],
  "where": "science fiction under 25 dollars"
}
{
  "rows": [
    { "book name": "Vingt mille lieues sous les mers",
      "writer": "Jules Verne",
      "cost": 15.5 } ],
  "interpreted": {
    "want": { "writer": {
      "field": "books_view.author_name",
      "confidence": 0.95 } },
    "where": { "ast": { "op": "and", … },
               "confidence": 0.9 } }
}

want: fields in your vocabulary · where: a plain-language filter · the answer comes back in your keys, with an inspectable interpreted echo.

Natural-language easy on the outside, a deterministic contract on the inside — stable enough for a traditional application to build against.

The gateway never sees a schema config

The schema block sits behind a prompt-cache boundary — after the first request it costs ~0.1× tokens per query.

How it stays safe

NL → validated predicate AST → execute. Never NL → SQL.

The shape is an hourglass: many protocols on top, many data sources at the bottom — one narrow waist everything must squeeze through.

RequestAdapter — your protocol, your words ↓ RawQuery resolver — AST checked against an operator whitelist + the real fields (the injection boundary, in code) ↓ CanonicalQueryIR Connector — parameterized SQL on a real Postgres

A hijacked model can at worst mis-resolve inside the allowed schema — it can never emit SQL. You'll see the proof live: the playground echoes the exact SQL it ran, values as bound parameters.

Spike before build

The one risky bet — can a model resolve fields + compile filters reliably? — was measured before any gateway code existed.

The spike harness is frozen and re-runnable — every resolver change re-takes the same exam.

Live demo

sans-schema-playground.vercel.app

Made-up field names → real answers. Every run shows its work: what the gateway understood (resolved fields, confidence, cache hits, the AST), the exact SQL with bound parameters, and a copy-paste curl of the whole request.

Try it with your own data

  1. git clone + docker build
  2. docker run with your DATABASE_URL + your LLM key
  3. curl it in your own words

sans-schema-playground.vercel.app/own-data

QR code to the playground

Deliberately not solved yet

Stated limits are how you know the numbers are honest.

What's next — swap the hourglass ends

Plus symbolic dates (bind_today) — compile “published over 20 years ago” date-independent, bind today at execute time, so the cache survives midnight.

Thanks

· ← →