queryglot
One question, many query languages. Schema-aware natural-language search over your observability stack — Prometheus, Elasticsearch — and any OpenAPI-described API, shipped as an MCP server any agent can plug into.
"p95 latency by route" is easy. Knowing YOUR latency metric is called
http_server_request_duration_secondsand carries aroutelabel — that's the actual problem. Frontier models write fluent PromQL over metric names that don't exist.
How it works
question ──> retrieve ──> compile ──> validate ──> execute
(BM25 + synonyms (LLM, schema (the backend's OWN (real data,
over YOUR schema, slice in the parser + unknown- query shown)
introspected live) prompt) metric check)
│ ▲ │ parse error
│ nothing matches └─── bounded repair ┘
▼
ABSTAIN — refuses to guess a metric name
- Retrieval owns facts (your metric names, labels, index fields — introspected from the live backend, never hallucinated). An LLM reranker orders the candidates by intent — over a closed set it can never add to.
- The model owns syntax (PromQL / Query DSL — swap in your own fine-tune
via any OpenAI-compatible endpoint, including
mlx_lm.serveron a Mac). - The backend owns truth: every query is validated by the server's own
parser (
format_query,_validate/query) before execution, and parse errors drive a bounded repair loop. - Abstention is a feature: off-schema questions get a refusal, not an invented metric. The eval scores this.
Use it from any MCP client
{
"mcpServers": {
"queryglot": {
"command": "queryglot-mcp",
"env": {
"QUERYGLOT_PROMETHEUS": "http://localhost:9090",
"QUERYGLOT_ELASTIC": "http://localhost:9200",
"QUERYGLOT_OPENAPI": "http://localhost:8081/api/v3",
"QUERYGLOT_LLM_URL": "http://localhost:11434/v1",
"QUERYGLOT_LLM_MODEL": "qwen3.5:4b"
}
}
}
}
Tools exposed: search(question, backend?), list_schema(query?),
refresh_schema().
Or the CLI:
queryglot "p95 http request duration" --prometheus http://localhost:9090
Or run an HTTP server with the ask-widget and query playground:
pip install "queryglot[serve]" # or: poetry install --extras serve
queryglot-serve --prometheus http://localhost:9090
queryglot-serve also serves the query playground at / and the embeddable
ask-widget bundle at /widget.js — see "Embed the ask-widget" below.
The playground is a small Discover-style console: your schema in a filterable
rail (type badges, prefix groups, and the items the last answer actually
used), a time-range picker whose window runs as a real query_range — the
window comes from the picker, never the model, so the compile prompt stays
byte-stable — and results as a bar chart or histogram with the raw rows one
toggle away. Answered questions also get a one-sentence conversational
summary, grounded strictly on the returned data (never computed, never
invented — an empty summary beats a wrong one), and repeat questions are
served from a short answer cache with an honest cached Ns ago tag and a
fresh re-run button.
Environment variables (serve only):
QUERYGLOT_SERVE_TOKEN— bearer token for/api/*endpoints. Empty = open (intended for localhost/demo).QUERYGLOT_CORS_ORIGINS— comma-separated allowed origins for embedding.
Any OpenAI-compatible endpoint works as the model: OpenAI, Ollama, or your own
LoRA behind mlx_lm.server — that last one is the point of finetune/.
Embed the ask-widget
queryglot-serve ships a self-contained widget: a floating "Ask" pill that
opens a search panel wired to the same schema-grounded engine as the CLI and
MCP server. Drop one script tag on any page:
<script
src="https://your-queryglot-host/widget.js"
data-api="https://your-queryglot-host"
data-theme="auto"
data-token="optional-bearer-token"
data-backend="optional-backend-name"
></script>
data-api(required) — base URL of the queryglot HTTP API.data-theme—light,dark, orauto(default; follows the host page'sprefers-color-scheme).data-token— bearer token, only needed when the server setsQUERYGLOT_SERVE_TOKEN.data-backend— pins searches to one backend instead of auto-routing.
See frontend/README.md for the build (npm run build:all) that packages
the widget and playground into the Python wheel.
Evaluation — deterministic, no LLM judge
eval/run_eval.py scores golden questions against a live backend: the
outcome must match, required metrics must appear in the query, and the query
must actually execute. Abstention cases score correct only on refusal.
eval/docker-compose.yml brings up real backends; CI runs the full
integration suite against a real Prometheus and petstore on every push.
Status
v0.1.0 — the RAG arm, working end to end.
- Prometheus + Elasticsearch backends (introspect / validate / execute)
- BM25 + synonym schema retrieval, exact-name boosting
- compile -> validate -> repair -> execute LangGraph with abstention
- MCP server + CLI; 141 backend tests (live-Prometheus and live-petstore integration included, always exercised in CI) plus 82 frontend tests; CI gates on all of it
- Verified NL->PromQL dataset generator (parse+execute gated, metric-disjoint splits)
- Bake-off complete — RAG 8/10, FT-only 3/10, FT+RAG 9/10 on the same
golden set; full analysis in
finetune/README.md, build history and bugs inDESIGN_NOTES.md - OpenAPI backend — read-only, GET-only by construction; validated against the spec's own contract; petstore-verified in CI
- HTTP serve layer: answer cache, grounded conversational summaries, structured schema API, bearer auth — engine outcomes are always 200 payloads (an abstention is an answer, not an error)
- Embeddable ask-widget (~15 KB gz, Shadow-DOM, one script tag) +
Discover-style playground: schema rail, time-range windows via
query_range, histogram/bar-chart results with rows one toggle away - Loki (LogQL) backend; Datadog connector
Where this is going: apps that agents can actually use
The Backend protocol (introspect / validate / execute) is not
observability-specific. The same loop pointed at a product's own OpenAPI spec
or database turns any app into something an AI can query safely:
- OpenAPI backend — shipped. Introspects a product's own spec into the catalog; questions compile into validated, GET-only API calls. Existing OpenAPI->MCP generators dump every endpoint as a tool, which measurably degrades agents (arXiv 2411.15399) and executes whatever the model asks. queryglot's contribution is the missing layer: schema-grounded retrieval, server-side validation, and abstention.
- Customer-facing ask widget — an embeddable search box backed by the same engine: visitors' questions become validated queries against the app's data, never hallucinated ones.
llms.txt+ MCP endpoint generation — one schema catalog, two audiences: humans get the widget, agents get a typed, validated interface instead of scraping. Discoverability for the agentic web, with execution semantics — not just markup.
Known limits
metric_candidates(unknown-metric detection) is regex-based and best-effort; the backend parser owns syntax, this only improves error messages. Complex PromQL may slip past it — never through the parser.- Backend auto-routing is retrieval-strength-based; ambiguous questions
("errors in checkout") can route to the wrong store. Pass
backend=to pin. - Synonym table is small and English-only, grown from eval failures.
- When a backend's catalog is smaller than the retrieval k (8), retrieval sends the whole catalog and the abstention gate rarely fires — abstention then rests on the validation layer.
License
MIT
Release files for queryglot 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| queryglot-0.1.0.tar.gz | 1.0 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| queryglot-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 2.0 MB
Release files / queryglot-0.1.0.tar.gz
| Download URL | queryglot-0.1.0.tar.gz |
|---|---|
| Size | 1.0 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a113a9451a44f7b4c232b4cfdb34a945acc6d5929bf11fd03047fa6b48c5e671
|
|
BLAKE2b-256 checksum How to use checksums |
1e2bd83ca121b07ebba62fdb9a7b6db71b95e81e0c4632880aac5aee4c83ca89
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.1 CPython/3.13.2 Darwin/25.5.0
|
Release files / queryglot-0.1.0-py3-none-any.whl
| Download URL | queryglot-0.1.0-py3-none-any.whl |
|---|---|
| Size | 1.0 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3e96e08e58b042d2d4e092609d19235bf66b47471efbd126e04c555cf5e338e0
|
|
BLAKE2b-256 checksum How to use checksums |
040f3c3cbd9a6411647fdf77c0de40d6e150a2ec1a5554f78ba6a73fac79d9c4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.1 CPython/3.13.2 Darwin/25.5.0
|