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.
- Claude Code today
- More agents coming
| Checked | 1 SQL file · contracts for 0 of 3 tables |
|---|---|
| Found | 5 errors · 2 warnings |
| Not checked | your data: TrueQuery reads files and never connects to your databaseNames what it couldn't verify |
| No contract | customers, orders, staging_ordersNo written contract |
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.
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). …
One flow, every time.
Every build runs the same seven steps. Here is one real session on the .
Your definitions win: if a request contradicts how your team defines a number, TrueQuery says so before writing, and records the conflict.
- 01LookReads repo, definitions, contracts, schema.
- 02AskAt most 5 questions, each with a default.
- 03ContractWrites down what one row means, first.
- 04BuildIn your stack, with tests.
- 05CheckRuns the offline checker.
- 06ReceiptWhat was checked, and what wasn't.
- 07RememberSaves answers in DATA.md.
02 AskIt asked first, each with a recommended default
- 1.What kind of lifetime value should the mart hold?defaultRealized, to date (Recommended)
- 2.Should subscription revenue (MRR) count toward LTV, or only order revenue?defaultOrders only, MRR shown apart (Recommended)
- 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
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.
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, hooks send findings back before the agent says it's done.
- Works in CI
- In a terminal, with text, JSON or SARIF output.
- Never a false "clean"
- A file it couldn't parse is listed as not checked.
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;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);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;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';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;= 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';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;no WHERE: every row is affected
fix: add a WHERE predicate, or use TRUNCATE if you mean the whole table
220 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: 444 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
| Domain | Share | Enforced by the checker | Practices |
|---|---|---|---|
| Ingest | 1 with a check | 24 | |
| Store | 19 | ||
| Model | 1 with a check | 19 | |
| Orchestrate | 1 with a check | 16 | |
| Data quality | 1 with a check | 18 | |
| Semantics and metrics | 22 | ||
| Consumption | 27 | ||
| Governance | 18 | ||
| Operations | 16 |
| Domain | Share | Enforced by the checker | Practices |
|---|---|---|---|
| SQL | 21 with a check | 26 | |
| Python | 15 | ||
| Total | 25 with a check | 220 |
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, previewNext
- More agents: Codex and Muse verified, then Cursor, Copilot, Gemini CLI and others, with one installer.
- A GitHub Action and a pre-commit hook.
- More checks, each promoted only when it proves precise on real projects.
Later
- More lifecycle commands: data quality, migrations, docs, cost, dialect porting.
- Read-only warehouse connections, BigQuery first.
- Team-wide standards.
Install it now
PreviewOpen source, Apache-2.0Open source under Apache-2.0, in preview. Needs Claude Code and uv (Python 3.11+). On Windows, the per-edit hooks need Git for Windows. The checker ships inside the plugin; uv fetches its dependencies on the first run.
In a terminal
claude plugin marketplace add Analytically-ai/truequeryclaude plugin install truequery@analyticallyThen 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.
For the terminal or CI, without an agent
pip install truequeryuvx truequery detect models/pip installs the commands truequery and its short alias tq, with text, JSON or SARIF output. uvx runs it without installing.
Works with
| Claude Code | Supported: skill, commands, hooks |
|---|---|
| Terminal and CI (any agent, any person) | Supported: truequery detect / review, JSON and SARIF |
| Codex, Muse Code | Hook configs included, not yet verified live |
| Cursor, GitHub Copilot, Gemini CLI and others | Planned |
Follow releases
On GitHub, choose Watch → Custom → Releases to hear about each new version.