ARCHITECTURE · READING FOR NERDS

Generate a query.
Never send the data.

The instinct is to hand the JSON and the question to an LLM and let it answer. For a tool built to open huge files privately, that's the wrong shape. Here's what QDev does instead — and why.

WHY NOT JUST SEND THE JSON?

Four reasons it breaks

SCALE
Files are huge
A 256 KB file already blows past a small model's context. Large files are the whole point.
PRIVACY
Data egress
Shipping your data to any model — even local — is exactly what power users push back on.
COST
Tokens add up
Paid inference on full documents is expensive, and grows with every extra byte.
TRUST
Hallucination
A model that reads-and-answers can invent numbers. You can't tell a real total from a made-up one.
THE SPLIT

Text-to-query, not read-and-answer

The model only ever sees the shape of your JSON — the schema we already generate — plus your question. Execution is deterministic jq on the full file.

SMALL, BOUNDED INPUT — LEAVES THE TAB (HOSTED ONLY)
Your question + schema
keys & types only — no values
Model writes jq
intent → query, structured
.users[]
| select(...)
● YOUR JSON, ANY SIZE — NEVER LEAVES THE TAB
Full document
loaded locally, multi-MB
jq engine (Web Worker)
WASM jq 1.8.2 · timeout · 25 MB cap
Exact result
opens in tree / schema / graph

Aggregations stay exact because jq does the math, not the model: "how much did ben spend in January?" becomes a filter-and-sum that runs on the real values. The model only needed the shape.

THE ENGINE

Why jq

jq compiled to WASM is the only query engine. It's purely functional— no mutation, no I/O, no way to reach the network or DOM — so it's safe to run model-generated code. LLMs know jq well, and it covers filter and transform: merge, group, flatten, reshape.

~1–2 MB, lazy-loaded the first time a query runs — it never touches the initial bundle.

EXAMPLE · find everyone named ben
[.. | objects | select(.name? | strings | test("ben";"i"))]
The strings guard matters — .. also visits objects with no name, and test errors on null. The grounding steers the model to this robust form.
THE PIPELINE

A bounded, self-correcting agent loop

Every query — hosted or local — runs through one pipeline. The model has three tools; a bad query comes back to it as a tool result and it retries within a fixed budget.

inspect(path)
Narrow the schema to one path when a field is ambiguous — structure only, never values.
run_jq(expr)
Execute in the Worker. Errors or empty results return to the model to repair.
final(expr)
Commit → result JSON → opens as a derived, re-runnable view.
ask (NL)
  └─▶ grounding: relevance-sliced schema + samplePaths (value-free)
        └─▶ agent loop (bounded turns)
              ├─ inspect(path)   — narrow the schema slice
              ├─ run_jq(expr)    — error/empty loops back
              └─ final(expr)     — commit → result
● SCHEMA-ONLY — YOUR VALUES NEVER LEAVE

Your values never leave your machine

The model gets exactly two things: your schema and your question. That's it — no values, no sampled rows, redacted or otherwise. If a query comes back empty because a value's format was ambiguous — an ISO date vs an epoch, active vs ACTIVE — you refine the question or edit the jq; the data stays in your tab. Hosted uploads a schema and a sentence; local WebLLM uploads nothing. The proxy is stateless and logs neither prompts nor results.

ONE SEAM, SEVERAL BACKENDS

Where the model runs

The app depends only on a LanguageModel interface. Local AI is free — the gateway; hosted (QDev Pro) is the paid tier.

QDev Pro
PAID · HOSTED
Proxy to a hosted model we keep tuned for jq. Nothing to install, best accuracy, identical on Chrome & Firefox.
→ schema + question leaves
WebLLM (local)
FREE
A 3B-class instruction model via WebGPU. Zero egress; needs a capable GPU and a first-run download.
● nothing leaves the device
Chrome built-in
FREE
Gemini Nano via the Prompt API — browser-managed, no download. Chrome-only.
● nothing leaves the device
Ollama (local)
FREE · ADVANCED
Point at localhost:11434 for the strongest local models. Requires installing Ollama.
● nothing leaves the device

That's the whole trick.

Small structured input to the model, deterministic jq on your machine. Go try it.