Datum
Enables natural-language querying of SQLite databases through a governed semantic layer, with citations and typed abstention for PII or uncertified data.
README
Datum
A semantic context layer that keeps data agents honest.
Datum answers natural-language questions over a database by grounding an LLM on a governed semantic layer. It writes SQL that is validated against the schema, cites the tables and columns it used, and refuses instead of guessing when a question needs data that doesn't exist, is personal (PII), or isn't certified for analytics. It ships with an MCP server, a reliability eval harness, and unit tests for the guardrail.
A confident wrong answer is worse than no answer.
Results
Datum vs. a naive single-prompt text-to-SQL baseline, gpt-4o-mini, averaged over 3 runs.
CWR = Confidently-Wrong Rate (wrong answers plus answers that should have been
refused — PII, uncertified, out-of-scope) — the number a trust layer exists to minimize.
| Benchmark | Engine | Execution Acc. ↑ | Refusal Recall ↑ | CWR ↓ | Answer faithfulness ↑ |
|---|---|---|---|---|---|
| Synthetic (30 Q) | Datum | 96.3% | 100% | 0.0% | 100% |
| Baseline | 88.9% | 27.8% | 35.6% | 81.5% | |
| Chinook (20 Q, real DB) | Datum | 92.9% | 100% | 0.0% | — |
| Baseline | 100% | 33.3% | 20.0% | — |
The critic + semantic layer drives confidently-wrong answers to zero and catches
100% of PII / uncertified / out-of-scope queries — without lowering execution
accuracy. The baseline, by contrast, leaks PII (SELECT email FROM employees), queries
uncertified tables, and even aliases AVG(csat_score) AS average_nps to answer a
question about a metric that doesn't exist.
Reproduce:
python evals/run_evals.py --runs 3 --judge # synthetic
python evals/run_external.py evals/chinook_eval.yaml --runs 3 # real Chinook DB
Why
Point an LLM at a database and it will happily invent an nps_score column, join on
the wrong key, leak an email address, or return a confident number that's just wrong.
Datum puts two things between the model and the data:
- A governed semantic layer — definitions, ownership, trust levels, metrics and PII flags — so the agent reasons over meaning, not raw table names.
- A deterministic critic — a real SQL parser (
sqlglot, not the LLM) that blocks hallucinated columns, PII, uncertified tables and any non-read-only statement before a query ever runs.
If neither can make the question safe to answer, Datum abstains — with a typed reason.
Architecture
flowchart TD
Q[Natural-language question] --> R[Retriever<br/>relevant semantic assets]
R --> P[Planner<br/>answerable? which assets?]
P -->|no| X[Abstain<br/>pii · missing · untrusted · out-of-scope]
P -->|yes| A[SQL Author<br/>grounded SELECT]
A --> C{Critic<br/>sqlglot guardrail}
C -->|violations| A
C -->|clean| E[(SQLite<br/>read-only)]
E --> Ans[Answerer<br/>NL answer + citations]
SM[[Semantic layer<br/>trust · PII · metrics]] -.governs.-> P
SM -.governs.-> A
SM -.governs.-> C
Multi-agent pipeline: Planner → SQL Author → Critic → Answerer, with a repair loop (the Critic's feedback goes back to the Author). Citations are extracted from the validated SQL's AST, so they reflect what the query actually touched.
Features
- Grounded NL→SQL over SQLite, with citations and typed abstention.
- Governed semantic layer (
context/semantic_model.yaml): trust levels, PII flags, ownership, business metrics with reference SQL. - Deterministic critic (
sqlglot): rejects unknown/hallucinated columns, PII columns (even hidden behind a CTE or renamed alias), uncertified tables, and non-read-only SQL. - Schema-linking: FK-neighbour expansion pulls join-partner tables into context.
- Context retrieval over semantic assets — OpenAI embeddings, with a lexical fallback so the pipeline runs with no key.
- MCP server — expose the engine to Claude Desktop / Cursor.
- Auto-introspection adapter — build a semantic layer from any SQLite schema.
- Reliability eval harness with a naive baseline, an LLM-as-judge faithfulness check, and multi-run averaging.
- Unit tests for the guardrail (
pytest, no API needed).
Quickstart
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # add your OPENAI_API_KEY
python -m datum seed # build the demo database
python -m datum ask "What is our monthly recurring revenue?"
python -m datum ask "List the email addresses of our account owners." # abstains (PII)
python -m datum eval # reliability scorecard vs baseline
pytest -q # guardrail unit tests (no API)
Example
$ python -m datum ask "What is our monthly recurring revenue?"
╭─ Answer ─────────────────────────────────────────────────────────╮
│ Our monthly recurring revenue is $1,241,366.00. │
│ Source: plans.monthly_price, subscriptions.seats │
╰───────────────────────────────────────────────────────────────────╯
SELECT SUM(p.monthly_price * s.seats) AS mrr
FROM subscriptions s JOIN plans p ON p.plan_id = s.plan_id
WHERE s.status = 'active'
$ python -m datum ask "List the email addresses of our account owners."
╭─ Abstained · pii ────────────────────────────────────────────────╮
│ I can't answer that because it requires personal data (PII) that │
│ policy does not expose. │
╰───────────────────────────────────────────────────────────────────╯
Benchmarks
Metrics (standard text-to-SQL + governance):
| Metric | Meaning |
|---|---|
EX Execution Accuracy |
answerable questions whose result matched gold |
RP Refusal Precision |
of everything it refused, how much should be refused |
RR Refusal Recall |
of the should-refuse questions, how many it caught |
CWR Confidently-Wrong |
wrong answers + policy leaks, over all questions (lower better) |
| Answer faithfulness | LLM-as-judge: are the answer's numbers grounded in the rows? |
Synthetic (evals/eval_set.yaml, 30 questions, deterministic DB) is the primary
benchmark. Chinook (evals/chinook_eval.yaml, 20 questions) runs the same harness
against the real third-party Chinook DB via schema auto-introspection.
Adding a Spider dev database (or any SQLite): the harness is dataset-agnostic. Drop
the .sqlite file in benchmarks/, copy chinook_eval.yaml, point database: at it,
list its pii_columns, and paste the Spider dev questions + gold SQL as items — then
python evals/run_external.py evals/your_spec.yaml. (Public benchmarks ship no trust/PII
labels; hand-annotating them in the YAML is exactly what the semantic layer is for.)
# fetch the Chinook demo DB used above (~1 MB)
curl -sL -o benchmarks/chinook.sqlite \
https://github.com/lerocha/chinook-database/raw/master/ChinookDatabase/DataSources/Chinook_Sqlite.sqlite
Tests
pytest -q # 37 tests, ~0.4s, no API
The guardrail is tested directly with adversarial SQL — stacked-statement injection, write keywords hidden in comments, PII behind a renamed CTE alias, hallucinated columns, unqualified columns shared across two tables — so the "trust layer" claim is proven, not just asserted.
Use it from Claude Desktop / Cursor (MCP)
python -m datum serve starts an MCP server exposing list_certified_tables,
describe_table, and ask:
{
"mcpServers": {
"datum": {
"command": "/ABSOLUTE/PATH/datum/.venv/bin/python",
"args": ["/ABSOLUTE/PATH/datum/mcp_server.py"]
}
}
}
Project layout
datum/
├── datum/
│ ├── db.py # sqlite access + read-only guardrail + result compare
│ ├── seed.py # deterministic synthetic SaaS database
│ ├── semantic.py # loads/queries the governed semantic layer
│ ├── introspect.py # auto-build a semantic layer from any SQLite schema
│ ├── retrieval.py # embeddings (or lexical fallback) over assets
│ ├── agents.py # Planner · Author · Critic · Answerer + Engine
│ ├── baseline.py # naive single-prompt baseline (the comparison point)
│ └── cli.py # `python -m datum ...`
├── context/semantic_model.yaml # the governed context layer
├── evals/
│ ├── eval_set.yaml # synthetic benchmark (incl. must-refuse questions)
│ ├── chinook_eval.yaml # real-DB benchmark spec
│ ├── run_evals.py # harness + baseline + faithfulness judge
│ └── run_external.py # run the harness on any external SQLite DB
├── tests/ # pytest guardrail suite (no API)
└── mcp_server.py # MCP server (FastMCP)
Design notes, limitations & next steps
- Benchmarks are small and partly self-authored (30 synthetic + 20 Chinook). They demonstrate the mechanism and the delta vs. baseline; they are not a large-scale study.
- Single dialect. Only SQLite is implemented and tested. The design (semantic layer + AST critic) is dialect-agnostic, but porting to a warehouse dialect is future work, not a claim being made here.
- The critic proves validity and governance, not semantic correctness. It guarantees SQL is read-only and touches only real, certified, non-PII columns; whether the query answers the user's intent is what the eval's execution accuracy measures.
- Columns behind derived-table/CTE aliases are skipped by the critic to avoid false positives (the read-only + certified-table checks still apply).
- Next: Spider/BIRD subsets through
run_external.py; a warehouse dialect; caching embeddings; expanding the eval sets.
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.