Inspiration

Monday 9:04 a.m. - finance and the executive dashboard disagree on revenue by 12%. Three definitions looked reasonable. None were governed.

I wasn't on the analytics team. I was on the platform team - the person who keeps dbt, the warehouse, and the catalog running. When numbers disagree, everyone looks at whoever touched the pipeline last.

Finance used recognized_revenue from a legacy report. Looker used a calculated field from two years ago. Our dbt Semantic Layer stub had revenue_usd - a column that does not exist - because an analyst asked ChatGPT to draft YAML and the PR looked professional.

I spent that week reading SQL people actually run. On Thursday I opened DataHub query history on orders - dozens of real SELECT statements. I didn't need a model to invent revenue. I needed a pipeline that reads institutional SQL, validates every column against the catalog, compiles dbt Semantic Layer YAML, and writes back so the next agent inherits an official definition.

QueryMint is that pipeline.

Cover

Before vs after


What it does

QueryMint turns catalog-grounded query history into validated, mergeable dbt Semantic Layer artifacts.

The pipeline:

  1. Mine - institutional SQL from DataHub via get_dataset_queries
  2. Extract - sqlglot parses SELECT, GROUP BY, aggregations, CTEs, UNIONs (deterministic - no LLM on compile path)
  3. Cluster - structural hash deduplicates recurring patterns
  4. Compile - Jinja templates emit semantic_models/, metrics/, staging SQL
  5. Validate - fail-closed schema gate; dbt parse in CI
  6. Write-back - PENDING → read-back → VERIFIED

Pipeline

War Room demo

Dual-dataset proof (orders revenue + customers LTV/signups):

Dataset Queries Clusters Validation VERIFIED
orders 20 10 10/10 passed 10/10
customers 12 8 8/8 passed 8/8
Combined 32 18 18/18 18/18

Measured eval (pipeline-derived grounded vs ungrounded A/B):

Check Result
Column picks grounded 18 / 18
Ungrounded baseline 0 / 18
Hallucinated columns in sealed run 0
pytest + coverage 176 tests, 92%
Transports Fixture · GraphQL · MCP stdio

Eval scoreboard

Validation proof


Why DataHub is essential

Step DataHub capability
Mine get_dataset_queries
Validate schema field allow-list
Write-back document + tags → next agent inherits answer

Without query history I am guessing. Without schema metadata I am back to revenue_usd. Without write-back the next agent still hallucinates.

DataHub loop


What makes QueryMint different

QueryMint is a batch compiler, not a chat agent:

QueryMint
Input Institutional SQL from get_dataset_queries
Output dbt Semantic Layer YAML + staging SQL - merge-ready artifacts
Proof Fail-closed schema gate · dbt parse in CI · PENDING → VERIFIED read-back
Scope Compiles what your organization already runs into governed metrics

YAML comparison


Next-agent flip

Question Without write-back With QueryMint VERIFIED
Official revenue on orders? "Use revenue_usd" (unverified) Cites validated sum_amount
Official LTV on customers? "Use ltv_usd" (not in schema) Cites sum_lifetime_value

Write-back protocol

Try it in 60 seconds:

git clone https://github.com/HawaleShailesh004/querymint-app.git
cd querymint-app && pip install -e ".[dev]"
querymint demo && querymint verify

Terminal verify

Interactive: War Room - switch orders ↔ customers in the top bar.


How I built it

Python 3.11 · Typer · sqlglot · Jinja2 · Pydantic · acryl-datahub · pytest · GitHub Actions

Module Responsibility
extract/parser.py + normalizer.py sqlglot intent (CTE/UNION/subquery)
cluster/hasher.py Structural deduplication
compile/compiler.py dbt Semantic Layer YAML
validate/schema_gate.py Fail-closed catalog allow-list
writeback/protocol.py PENDING → VERIFIED state machine
eval/runner.py Pipeline-derived A/B eval
datahub_client_mcp.py MCP stdio transport (QUERYMINT_TRANSPORT=mcp)

Design choices:

  • Deterministic compile path - sqlglot + templates, not LLM generation
  • Fail-closed gate - column not in catalog → artifact does not ship
  • Two-phase write-back - emit ≠ landed; read-back before VERIFIED
  • Fixture mode - identical proof offline; judges not blocked by Docker
  • Sealed bundle - examples/ + SHA256SUMS; querymint verify recomputes integrity

Upstream skill contribution prepared for datahub-skills: contributions/datahub-skills/


Accomplishments

I built the pipeline I wished existed that Monday. QueryMint reads SQL your organization already runs and ships compiled dbt Semantic Layer YAML - not just a conflict report.

Dual-dataset proof. Orders (revenue) and customers (LTV/signups) both pass schema gate and VERIFIED write-back - not a one-table demo.

Reproducible by design. querymint demo && querymint verify → same numbers I report: 18/18 eval, 18/18 VERIFIED, 176 tests, 92% coverage.

I closed the agent loop. Write-back means the next agent answering "what is revenue?" reads catalog metadata instead of inventing revenue_usd.

Judge-friendly packaging. Offline fixture mode, War Room, docs/JUDGES.md, sealed examples/HEADLINE.json.


Contributed to DataHub

  • datahub-skills PR #140 - adds the datahub-query-to-semantic skill: institutional SQL from get_dataset_queries → validated dbt Semantic Layer YAML → optional catalog write-back.

Reference implementation: QueryMint


Challenges

Trust was harder than parsing. Every column ref checked against catalog schema or it does not ship.

Real SQL is messy. Structural clustering tuned so near-duplicates collapse without hiding real differences.

YAML is unforgiving. COUNT(*) → expr: * broke dbt parse; fixed templates + CI gate.

Write-back ≠ read-back. Rebuilt as two-step protocol after emit succeeded but UI showed nothing.

Windows + DataHub locally was painful. Port conflicts, empty query history, datapack path bugs - fixture mode ensures judges get identical proof without my laptop.

Knowing when to stop. LLM column names hallucinated revenue_usd in early experiments. QueryMint's value is boring and catalog-grounded.


What's next

  • CI on schedule: query history shifts → PR with updated semantic YAML
  • Steward approval queue before promoting semantic-layer-candidateofficial
  • Multi-dataset semantic models via lineage-proven joins
  • Continuous drift detection when analysts change SQL patterns

Built With

  • acryl-datahub
  • apache-2.0
  • datahub
  • datahub-skills
  • dbt
  • dbt-semantic-layer
  • github-actions
  • graphql
  • mcp
  • mcp-server-datahub
  • pydantic
  • pytest
  • python
  • sqlglot
  • typer
Share this project:

Updates