Skip to content

One standard for data work, built into your AI coding agent.

It reads your repo, asks only what it can't find out, builds with tests, checks its own work offline and hands you a receipt, including what it did not check.

Preview
  • Claude Code and Muse Code today
  • Gemini CLI and Codex next
Receipt
TrueQuery receipt: what was checked and what was not
Checked1 SQL file · contracts for 0 of 3 tables
Found5 errors · 2 warnings
Not checkedyour data: TrueQuery reads files and never connects to your databaseNames what it couldn't verify
No contractcustomers, orders, staging_ordersNo written contract
A real TrueQuery receipt from reviewing samples/bad_orders.sql, a sample file of seven common SQL mistakes. An excerpt: the seven findings are in the checker section.

It runs. It looks right. It's wrong.

Someone types "build a pipeline for me" or "fix this" with no context, and the agent builds whatever it likes. Long sessions run past the context window, and it can start to invent things. The result runs, and nobody can tell what was checked.

Why it keeps happening

Inconsistent results
The same vague request gives a different answer every day.
Expensive verification
Senior engineers review by hand, or the model checks its own work: slow, costly and blind in the same places.
Late detection
Problems surface in review or production, not when the code is written.
> /truequery ask how much money did we make last month?

About $8,863 in March 2025

How sure I am: I'm confident in this number, with one caveat. The shop's ready-made revenue report shows $11,820.53 for the same month, and I think that report is wrong, not my number. The $2,958 gap comes from two problems in that report:

  • $2,368 comes from 5 orders by customers whose accounts were deleted. The shop's rules say deleted accounts are left out of headline numbers, but the report includes them.
Show the whole answer

Revenue for March 2025 was $8,862.88 (US dollars). That's money from 20 completed, paid orders placed by 19 customers. No refunds were processed against those orders.

  • The report starts and ends each day on US Pacific time. The shop's rules use UTC (standard world time). …
Asked for last month's revenue on the , TrueQuery disagreed with the shop's own report, and said why.
About the examples. The demo shop is a small online shop with made-up data that ships with TrueQuery: a DuckDB warehouse with 2,571 orders from 600 customers in 4 currencies, a dbt project, and 10 written house definitions. It ships with the repo, so anyone can run the same prompts on it.

One flow, every time.

Every build runs the same seven steps. Here is one real session on the .

About the examples. The demo shop is a small online shop with made-up data that ships with TrueQuery: a DuckDB warehouse with 2,571 orders from 600 customers in 4 currencies, a dbt project, and 10 written house definitions. It ships with the repo, so anyone can run the same prompts on it.

Your definitions win: if a request contradicts how your team defines a number, TrueQuery says so before writing, and records the conflict.

  1. 01LookReads repo, definitions, contracts, schema.
  2. 02AskAt most 5 questions, each with a default.
  3. 03ContractWrites down what one row means, first.
  4. 04BuildIn your stack, with tests.
  5. 05CheckRuns the offline checker.
  6. 06ReceiptWhat was checked, and what wasn't.
  7. 07RememberSaves answers in DATA.md.
> /truequery build a customer lifetime value mart

02 AskIt asked first, each with a recommended default

  1. 1.What kind of lifetime value should the mart hold?defaultRealized, to date (Recommended)
  2. 2.Should subscription revenue (MRR) count toward LTV, or only order revenue?defaultOrders only, MRR shown apart (Recommended)
  3. 3.Which customers get a row?defaultAll customers, flagged (Recommended)

04 Build

  • One row per customer: 600 rows, matching stg_customers exactly.
  • Test and deleted customers: they keep their rows but show zero lifetime value. Use is_ltv_population to filter them out for headline figures.

07 Remember

Your answers, recorded in contracts/fct_customer_ltv.yaml

/truequery build a customer lifetime value mart. A real build on the , shortened: three of its four questions and part of the result.
About the examples. The demo shop is a small online shop with made-up data that ships with TrueQuery: a DuckDB warehouse with 2,571 orders from 600 customers in 4 currencies, a dbt project, and 10 written house definitions. It ships with the repo, so anyone can run the same prompts on it.

A checker that is code, not a second opinion.

Alongside the skill, a checker looks for SQL that silently returns the wrong answer, and points at the line and column.

It reads .sql files and dbt models, SQL inside Python files, and pandas code in Python files that import pandas.

Tested on real code in BigQuery, PostgreSQL and DuckDB. Also parses Snowflake, Redshift, Databricks, T-SQL, MySQL, Trino and more.

Offline and deterministic
No LLM and no network calls in the check path. Your agent still talks to its model provider.
Runs as the agent works
In Claude Code and Muse Code, checks run on every edit and at the end of each turn, and findings go back to the agent.
Works in CI
In any terminal, in pre-commit or as a GitHub Action, with text, JSON or SARIF output.
Never a false "clean"
A file it couldn't parse is listed as not checked.
Pick a mistake. See what the checker says.samples/bad_orders.sql
4-- Revenue per customer, but the join has no predicate: every customer is5-- paired with every order.6SELECT c.name, SUM(o.total) AS revenue7FROM customers c, orders o8GROUP BY c.name;
samples/bad_orders.sql:7:19 [error] sql/accidental-cross-join
no predicate links o: every row pairs with every row on the other side
fix: add ON <keys>, or CROSS JOIN if cartesian is intended
10-- Customers who never ordered. One order with a NULL customer_id makes11-- NOT IN return no rows at all.12SELECT id FROM customers13WHERE id NOT IN (SELECT customer_id FROM orders);
samples/bad_orders.sql:13:7 [error] sql/not-in-nullable-subquery
a NULL in the subquery makes NOT IN return zero rows
fix: rewrite as NOT EXISTS, or add WHERE col IS NOT NULL
15-- Orders per customer, keeping customers with no orders. COUNT(*) counts16-- the unmatched row, so those customers show 1 order instead of 0.17SELECT c.id, COUNT(*) AS order_count18FROM customers c19LEFT JOIN orders o ON o.customer_id = c.id20GROUP BY c.id;
samples/bad_orders.sql:17:14 [error] sql/count-star-after-left-join
COUNT(*) over an outer join counts 1 for unmatched rows
fix: count the nullable-side key instead, e.g. COUNT(o.<key>)
22-- "All customers, with their completed orders". The WHERE on the joined23-- table drops every customer without one: the LEFT JOIN became an INNER.24SELECT c.name, o.total25FROM customers c26LEFT JOIN orders o ON o.customer_id = c.id27WHERE o.status = 'completed';
samples/bad_orders.sql:27:7 [warning] sql/left-join-null-rejecting-where
WHERE rejects NULLs on the nullable side: outer join silently becomes inner
fix: move the filter into the ON clause to keep unmatched rows (or add OR right.key IS NULL: test the join key, not the filtered column)
29-- Orders without a coupon. `= NULL` is never true, so this returns nothing.30SELECT id FROM orders WHERE coupon_code = NULL;
samples/bad_orders.sql:30:29 [error] sql/null-equality-comparison
= NULL is never true (use IS NULL)
fix: rewrite as IS NULL / IS NOT NULL
32-- March orders. A timestamp at 14:00 on 31 March is after '2025-03-31',33-- so the last day is silently dropped.34SELECT COUNT(*) FROM orders35WHERE ordered_at BETWEEN '2025-03-01' AND '2025-03-31';
samples/bad_orders.sql:35:7 [warning] sql/between-date-on-timestamp
BETWEEN with a date-only upper bound on a timestamp drops everything after midnight on the last day
fix: use a half-open range: >= start AND < day-after-end
37-- Clear yesterday's staging rows. No WHERE: this deletes every row.38DELETE FROM staging_orders;
samples/bad_orders.sql:38:1 [error] sql/unguarded-update-delete
no WHERE: every row is affected
fix: add a WHERE predicate, or use TRUNCATE if you mean the whole table

Evidence and limitsFAQReport a false alarm

225 practices, each with its reasons and sources.

Every command works to the same standard. Each practice says what to do, why, what goes wrong without it, and where that comes from: 452 citations, mostly to the docs of the tools you already use.

Most cited: dbt Labs 110 · PostgreSQL Global Development Group 54 · Apache Software Foundation 40 · Google Cloud 33 · DuckDB 31 · Dagster Labs 17 · Snowflake 17

Lifecycle stages
DomainShareEnforced by the checkerPractices
Ingest1 with a check24
Store19
Model1 with a check19
Orchestrate1 with a check16
Data quality1 with a check18
Semantics and metrics22
Consumption27
Governance18
Operations16
Languages
DomainShareEnforced by the checkerPractices
SQL21 with a check26
Python7 with a check20
Total32 with a check225
225 practices by stage and language, counted from the TrueQuery repo when this site was built. Darker: the 32 with a check in the checker; the skill teaches and applies the rest.

For everyone who touches the data.

Data engineer
/truequery build an incremental load of the refunds feed into the warehouse
Analytics engineer
/truequery build a customer lifetime value mart
BI engineer
/truequery metric "active customer"
Analyst
/truequery analyze why March revenue dropped
Non-technical
/truequery ask how much money did we make last month?

Alongside the tools you already use.

  • SQLFluff checks style; TrueQuery checks the data logic.
  • dbt tests check data after a build; TrueQuery has the agent write them, and checks the code as it's written.
  • Great Expectations and Soda run the checks you define; TrueQuery standardizes how the work is built.
  • Observability watches production; TrueQuery works before it.

Where it's going

Today: 0.1.6, preview

Next

  • The full skill in Gemini CLI and Codex, then Cursor and GitHub Copilot.

Later

  • Read-only checks against your data (local files first, then warehouses), so the receipt can say "checked against the data".
  • The rest of the lifecycle as full commands: data quality, migrations and backfills, docs kept in sync, cost.
  • Team-wide definitions shared with every developer's agent.

Install it now

PreviewOpen source, Apache-2.0

Open source under Apache-2.0, in preview. Needs uv (Python 3.11+). On Windows, the per-edit checks need Git for Windows.

Claude CodeReady

In a terminal

claude plugin marketplace add Analytically-ai/truequery
claude plugin install truequery@analytically

Then run /truequery init in your project.

Or inside a Claude Code session

/plugin marketplace add Analytically-ai/truequery
/plugin install truequery@analytically
/reload-plugins
/truequery init

/reload-plugins, or restart Claude Code, so the new plugin loads. /truequery init detects your stack, asks a few questions about your house definitions, and writes DATA.md.

Muse CodeReady

muse plugins marketplace add analytically https://github.com/Analytically-ai/truequery
muse plugins install truequery@analytically
muse plugins approve truequery

The last line approves the plugin's checks, once. Then ask for data work in your own words, or load the skill with /skill truequery.

CodexEarly access

pip install truequery
truequery install --harness codex

This sets up the checks as the agent works, being verified live. Approve them once in Codex with /hooks. The full skill is coming next.

Any agent, terminal or CIReady

In any terminal

pip install truequery
uvx truequery detect models/

pip installs the commands truequery and its short alias tq, with text, JSON or SARIF output. uvx runs it without installing.

pre-commit

repos:
  - repo: https://github.com/Analytically-ai/truequery
    rev: v0.1.6
    hooks:
      - id: truequery

The hook truequery checks staged .sql files. Use truequery-python to check .sql and .py files.

GitHub Actions

name: truequery
on: [push, pull_request]

permissions:
  contents: read

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: Analytically-ai/truequery@v0.1.6
        with:
          path: .

Writes the findings and the receipt to the job summary. Full options and SARIF setup are in the CI guide.

Works with

Where TrueQuery runs, and its status
Claude Code, Muse CodeReadyThe full skill, all commands, checks on every edit and at the end of each turn
CodexEarly accessChecks as the agent works, being verified live; the full skill next
Gemini CLIComing nextThe full skill and checks
Cursor, GitHub CopilotPlannedThe full skill and checks
Any agent, terminal or CIReadyThe checker on its own: text, JSON or SARIF; pre-commit and a GitHub Action

Follow releases

On GitHub, choose Watch → Custom → Releases to hear about each new version.