{"id":"5e5351e2-554f-4bcb-83e9-75f272854a24","slug":"verisql","kind":"mcp","name":"veriSQL","summary":"Audit-grade verification gateway for AI-generated SQL — catches silently wrong queries before they hit your dashboard, keeps tamper-evident audit trails, verifies migration equivalence. Zero LLM token","owner":"Sneha21032004","repoUrl":"https://github.com/Sneha21032004/veriSQL","license":"MIT","licenseTier":"permissive","trust":"community","stars":3,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-06-10T09:42:51.000Z","addedAt":"2026-10-21T17:32:06.177Z","logoUrl":"https://avatars.githubusercontent.com/u/170117324?v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["databases","data-analytics"],"tags":["ai-agents","audit","bigquery","compliance","data-engineering","data-quality","hallucination-detection","llm"],"runtime":"python","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-26T04:07:20.754Z","sample":false,"url":"https://conduits.dev/tools/verisql","language":"Python","transports":["stdio"],"install":{"pypi":"verisql"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"<div align=\"center\">\n\n# VeriSQL\n\n**The deterministic oracle for AI-generated SQL: verify it, auto-repair it, prove it.**\n\n*AI writes your SQL now. VeriSQL proves it didn't lie — and fixes it when it did.*\n\n[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Sneha21032004/veriSQL/blob/main/notebooks/verisql_proof.ipynb)\n[![Tests](https://img.shields.io/badge/tests-139%20passing-brightgreen)](tests/)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)\n[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)\n[![Recall](https://img.shields.io/badge/silent--failure%20recall-83%25-brightgreen)](#-benchmark-measured-not-claimed)\n[![Precision](https://img.shields.io/badge/precision-91%25-brightgreen)](#-benchmark-measured-not-claimed)\n\n</div>\n\n---\n\n## 🧨 The problem\n\nEvery BI tool now ships text-to-SQL — Snowflake Cortex Analyst, Databricks Genie, Hex Magic, dbt MCP, Metabase Metabot. The dangerous failures are **not crashes**. They are queries that parse, execute, and return a clean, confident, **wrong** number:\n\n```sql\n-- Question: \"Total revenue last month\"\nSELECT SUM(amount) FROM orders WHERE status = 'paid';\n-- runs fine, sums ALL TIME → number is 10× too big. Nobody notices for weeks.\n```\n\n```sql\n-- Question: \"Customers not in the banned list\"\nSELECT * FROM customers WHERE region NOT IN (SELECT banned FROM blocklist);\n-- one NULL in blocklist → ALWAYS returns zero rows. Compliance thinks they're clean.\n```\n\nAn LLM judging its own SQL is non-deterministic, biased toward self-approval, and costs tokens on every call. A regulator will not accept \"the model checked itself.\"\n\n**VeriSQL is the independent, deterministic layer that can.**\n\n**Don't trust this README — [reproduce the proof yourself in Colab](https://colab.research.google.com/github/Sneha21032004/veriSQL/blob/main/notebooks/verisql_proof.ipynb), 2 minutes, browser only.** Deterministic means it works the same on every machine.\n\n## 🔧 The 10-second demo\n\n```bash\n$ verisql fix --sql \"SELECT * FROM customers WHERE id NOT IN (1, NULL)\"\n\nAuto-repair: 1 fix(es) in 2 round(s) -> VERIFIED\n  [not_in_null_literal] NOT IN list contained NULL -> always-empty result; NULL removed\n      - NOT id IN (1, NULL)\n      + NOT id IN (1)\n\n--- final SQL ---\nSELECT * FROM customers WHERE NOT id IN (1)\n```\n\nThat input query returns **zero rows, always** — one NULL and SQL's three-valued logic silently empties the result. An LLM judging it approves it most of the time. VeriSQL catches it **100% of the time, in ~2ms, for $0** — then rewrites it with a provably-correct AST transform and re-verifies.\n\nWhy this matters: code agents run autonomously because compilers and tests give deterministic feedback. **SQL has no compiler error for \"wrong answer.\"** VeriSQL is that missing oracle — it closes the loop so text-to-SQL agents can self-correct instead of waiting for a human.\n\n## ⚡ What it does\n\n```\n            ┌──────────────────── VeriSQL oracle ─────────────────────┐\nAI writes   │  12 deterministic checks ──▶ AST auto-repair ──▶ re-     │   verified SQL\n   SQL ───▶ │  (AST · schema · plan ·      (provably-correct  verify  │ ──▶ ships; audit\n            │   execution · invariants)     rewrites, $0)              │     trail appended\n            └───────────────────────────────────────────────────────────┘\n               zero LLM tokens          escalate only the unfixable (<10%)\n```\n\nFour modes, one engine:\n\n| Mode | What it answers | Entry point |\n|---|---|---|\n| 🔧 **Repair** | \"Fix the query autonomously and prove it's now right\" | `verify_and_repair(...)` / `verisql fix` |\n| 🔍 **Verify** | \"Is this AI-written query silently wrong?\" | `verify(...)` / `verisql check` |\n| 🧾 **Audit** | \"Prove to an auditor what the AI did and what we caught\" | `AuditLog` / `verisql audit` |\n| 🔁 **Diff** | \"Is this LLM-translated query equivalent to the legacy original?\" | `verify_equivalence(...)` / `verisql diff` |\n\n## 🚀 Quickstart\n\n```bash\npip install -e \".[duckdb]\"   # from a clone (PyPI release pending)\n```\n\n```python\nfrom verisql import verify\n\nreport = verify(\n    sql=\"SELECT SUM(amount) FROM orders WHERE status = 'paid'\",\n    question=\"What was total revenue last month?\",\n    dialect=\"snowflake\",\n)\nprint(report.summary())\n# [ERROR] date_coverage: Question specifies a time range but SQL has no date filter.\n# confidence=0.70, review: YES\n```\n\nGate an agent pipeline in four lines:\n\n```python\nreport = verify(sql, question=q, dialect=\"snowflake\", connector=db, policy=policy)\nif report.has_blocking():    reject(report)\nelif report.suggested_review: escalate_to_human(report)\nelse:                         deliver(sql)\n```\n\n## 🔍 The checks\n\nAll deterministic. All free — **zero LLM tokens**.\n\n| # | Check | Severity | Catches |\n|---|---|---|---|\n| 1 | `ast_parse` | 🟥 critical | Unparseable SQL |\n| 2 | `schema_existence` | 🟥 critical | Hallucinated tables & columns |\n| 3 | `cartesian_join` | 🟥 critical | `FROM a, b` with no join key → inflated aggregates |\n| 4 | `null_semantics` | 🟧 error / 🟨 warn | `NOT IN (NULL)` → always-empty result; `!=` dropping NULL rows |\n| 5 | `timestamp_equality` | 🟧 error | `created_at = '2026-05-01'` matches only exact midnight |\n| 6 | `date_coverage` | 🟧 error | Question says \"last month\", SQL has no date filter |\n| 7 | `filter_required` | 🟧 error | Full scan of transactional tables, no WHERE/LIMIT |\n| 8 | `explain_plan` | 🟨 warn | Planner chose full scan despite filter (index defeated) — via `EXPLAIN`, never executes |\n| 9 | `zero_row_execution` | 🟨 warn | Runs read-only, flags suspicious empty results |\n| 10 | `business_invariant` | 🟥 critical | Result violates declared rules (`revenue >= 0`) |\n| 11 | `required_filter` | 🟧 error | Policy-governed table queried without mandated filter |\n| 12 | `pii_access` | 🟧 error / 🟨 warn | `SELECT *` or PII columns on governed tables (DPDP/GDPR) |\n\nEach flag lowers a confidence score; thresholds decide **deliver / review / reject**.\n\n## 🧾 Audit mode — the compliance artifact\n\nEvery verification can land in a **hash-chained, tamper-evident** JSONL log: who asked, which AI generated the SQL, what was flagged, the verdict, and any human override. Edit, insert, or delete a record retroactively → the chain breaks, detectably.\n\n```python\nfrom verisql import verify, AuditLog\n\nlog = AuditLog(\"audit_trail.jsonl\")\nreport = verify(sql, question=q, dialect=\"snowflake\", connector=db, policy=policy)\nlog.record(report, actor=\"analyst@firm.in\", generator=\"cortex-analyst\")\n```\n\n```bash\n$ verisql audit --log audit_trail.jsonl\nOK: chain intact (1,204 records)\n\n$ verisql audit --log audit_trail.jsonl --evidence\n{ \"total_verifications\": 1204, \"decisions\": {\"delivered\": 1031, \"review\": 158, \"rejected\": 15},\n  \"flags_by_check\": {\"pii_access\": 41, \"date_coverage\": 87, ...}, \"chain_valid\": true }\n```\n\nBuilt for evidence packs in regulated data teams — RBI / SEBI / DPDP / SOC2 contexts where \"the AI touched our numbers\" needs provenance.\n\n## 🔁 Diff mode — migration equivalence\n\nBanks migrate Teradata/Oracle → Snowflake/Databricks and use LLMs to translate thousands of queries. Nobody can eyeball 4,000 procs. VeriSQL ranks them:\n\n```bash\n$ verisql diff \\\n    --old-sql \"SELECT id FROM orders WHERE status='paid' AND amount>100\" \\\n    --new-sql \"SELECT id FROM orders WHERE status='paid'\" \\\n    --old-dialect tsql --new-dialect snowflake\n\nEquivalence verdict: LIKELY_NOT_EQUIVALENT\n  [MAJOR] filter: WHERE clauses are not structurally identical after normalization\n```\n\nTwo independent signals, cheapest first:\n\n1. **Structural diff** *(free, no DB)* — cross-dialect AST normalization catches dropped predicates, changed join types, renamed output columns, altered grouping\n2. **Result diff** *(read-only)* — executes both, compares row counts and order-insensitive content hashes on real data\n\nVerdicts — `equivalent · likely_equivalent · likely_not_equivalent · not_equivalent` — sort the batch so humans review only the risky tail.\n\n## 🧱 dbt CI gate — `verisql dbt`\n\nsqlfluff catches style. **VeriSQL catches wrong answers.** One command verifies every model in a dbt project for the silent-failure class of bugs — after `dbt compile`, before merge:\n\n```bash\n$ verisql dbt --project-dir .\n\n  PASS  stg_orders        passed  (0 flag(s))\n  FAIL  fct_clean_users   blocked (1 flag(s))\n          [ERROR] null_semantics: NOT IN with NULL always returns zero rows\n2 model(s): 1 passed, 0 review, 1 blocked, 0 skipped\n```\n\n- **No dbt dependency, no warehouse credentials** — reads `target/manifest.json` (plain JSON), parse-only by default, runs in seconds in any CI\n- Dialect auto-detected from the manifest's adapter type (Snowflake, BigQuery, Postgres, Databricks, …)\n- Non-zero exit blocks the merge; `--warn-only` for advisory mode; `--json-out` for tooling; `--select` to scope\n- Add `--duckdb-path` (or a policy YAML) for live schema/plan/invariant checks\n\n```yaml\n# .github/workflows/sql-gate.yml — the whole integration\n- run: dbt compile\n- uses: Sneha21032004/veriSQL@main        # or: pip install verisql && verisql dbt\n  with:\n    project-dir: .\n    # policy: policy.yaml                 # optional governance rules\n    # warn-only: \"true\"                   # advisory mode\n    # verisql-version: \"git+https://github.com/Sneha21032004/veriSQL.git\"  # until PyPI release\n```\n\n## 🧩 Drop into any agent framework\n\nThe oracle is one import away, whatever your stack:\n\n```python\n# Framework-free — zero extra deps\nfrom verisql.integrations import sql_guard, SQLVerificationError\n\n@sql_guard(connector=db, question_arg=\"question\")\ndef write_sql(question: str) -> str:\n    return llm.complete(...)          # returns verified (auto-repaired) SQL\n                                      # raises SQLVerificationError w/ diagnosis if unfixable\n```\n\n```python\n# OpenAI-compatible function calling — works with OpenAI/Groq/Ollama/vLLM/...\nfrom verisql.integrations.openai_tools import OPENAI_TOOL_SPECS, dispatch_tool_call\nresp = client.chat.completions.create(model=m, messages=msgs, tools=OPENAI_TOOL_SPECS)\nresult = dispatch_tool_call(call.function.name, call.function.arguments, connector=db)\n```\n\n```python\n# LangChain                                  # LlamaIndex\nfrom verisql.integrations.langchain import (  # from verisql.integrations.llamaindex import (\n    make_verisql_tools)                       #     make_verisql_tools)\ntools = make_verisql_tools(connector=db)      # same call, same two tools\n```\n\nAll surfaces return the **same payload shapes as the MCP server** — verdict, confidence, diagnosis, repaired SQL — so switching frameworks never re-teaches the agent. Extras: `pip install verisql[langchain]` / `verisql[llamaindex]`; the guard and OpenAI specs need nothing.\n\n## 🤖 LLM critic — optional, gated, any provider\n\nDeterministic checks decide ~90% of queries for free. The rest — ambiguous confidence band `[0.4, 0.8]` with a question to judge intent against — can escalate to a cheap LLM critic:\n\n```python\nfrom verisql import verify, openai_compatible_critic\n\ncritic = openai_compatible_critic(\"gpt-4o-mini\")                       # OpenAI\ncritic = openai_compatible_critic(\"llama-3.1-8b-instant\",\n            base_url=\"https://api.groq.com/openai/v1\")                 # Groq\ncritic = openai_compatible_critic(\"qwen2.5-coder:7b\",\n            base_url=\"http://localhost:11434/v1\", api_key=\"ollama\")    # local & free\n\nreport = verify(sql, question=q, connector=db, critic=critic)\nprint(report.critic_invoked, report.critic_tokens)\n```\n\n**No vendor lock-in**: a critic is any `(CriticRequest) -> CriticVerdict` callable. OpenAI, Groq, DeepSeek, Together, OpenRouter, vLLM, Ollama, or Anthropic (`anthropic_critic`) — your choice. Clean and obviously-broken queries never spend a token.\n\n## 📊 Benchmark — measured, not claimed\n\n`python -m benchmarks.run_benchmark` runs a labeled corpus of wrong + correct queries **live against DuckDB**:\n\n| Metric | Value |\n|---|---|\n| Recall (silent failures caught) | **83.3%** |\n| Precision | **90.9%** |\n| F1 | **0.87** |\n| False-positive rate | 12.5% |\n\nThe misses are `!=`-intent bugs that need the critic tier — the deterministic layer is honest about its limits. The benchmark is a **CI gate** (`tests/test_benchmark_gate.py`): catch-rate cannot silently regress. The labeled corpus grows from real-world misfires — contributions welcome.\n\n## 🔌 Connectors\n\n| Database | Extra | Live checks | Safety mechanism |\n|---|---|---|---|\n| DuckDB | `[duckdb]` | schema · explain · execute · stats | mutation-keyword guard |\n| PostgreSQL | `[postgres]` | schema · explain · execute · `pg_stats` | `BEGIN READ ONLY` + auto `ROLLBACK` |\n| Snowflake | `[snowflake]` | schema · `EXPLAIN USING TEXT` · execute | mutation guard |\n| BigQuery | `[bigquery]` | schema · **dry-run cost estimate** · execute | `maximum_bytes_billed` cap |\n\nAll dialects **parse with zero drivers** — `dialect=\"snowflake\"` etc. runs every structural check without any connection. The verifier is physically incapable of mutating your warehouse.\n\n## 📜 Policy as YAML\n\n```yaml\ninvariants:\n  - \"revenue >= 0\"\n  - \"active_users <= total_users\"\nrequired_filters:\n  transactions: [txn_date]\npii_columns:\n  customers: [email, phone, pan_number]\n```\n\n```python\nfrom verisql import verify, Policy\nreport = verify(sql, connector=db, policy=Policy.from_yaml(\"policy.yaml\"))\n```\n\nInvariants are parsed by sqlglot and evaluated by a fixed-node walker — **no dynamic code execution, ever**.\n\n## 🗂 Project layout\n\n```\nsrc/verisql/\n  verify.py          orchestrator: deterministic-first, gated critic\n  audit.py           hash-chained tamper-evident audit log\n  equivalence.py     migration equivalence verifier\n  policy.py          invariants + governance rules (YAML)\n  critic.py          provider-agnostic LLM escalation\n  dbt_gate.py        dbt CI gate: verify every model in a project\n  checks/            12 checks, one file each\n  connectors/        duckdb · postgres · snowflake · bigquery\n  integrations/      sql_guard · openai_tools · langchain · llamaindex\nbenchmarks/          labeled corpus + live catch-rate harness (CI gate)\nexamples/            quickstart · agent_loop · compliance_gateway\n```\n\n## 🧭 Roadmap\n\n- [x] 12 deterministic checks, 4 connectors, policy DSL, gated multi-provider critic\n- [x] Tamper-evident audit trail + evidence packs\n- [x] Migration equivalence verifier (structural + data)\n- [x] dbt CI gate (`verisql dbt`) — verify every model in a project, no dbt dependency\n- [x] Agent framework adapters — `@sql_guard`, OpenAI function calling, LangChain, LlamaIndex\n- [x] GitHub Action wrapping `verisql dbt` (`uses: Sneha21032004/veriSQL@main`)\n- [ ] Bulk diff runner (`verisql diff --batch manifest.csv`) for 1000s of migration queries\n- [ ] Corpus expansion from Spider/BIRD + real-world misfires\n- [ ] Hex / Snowflake Cortex integration hooks\n- [ ] Column-stats aggregate-range sanity checks\n\n## 🤝 Contributing\n\nNew checks, connectors, and labeled wrong-SQL cases are the most valuable contributions — see [CONTRIBUTING.md](CONTRIBUTING.md). Every check needs a test; the benchmark gate must keep passing.\n\n## 📄 License\n\n[MIT](LICENSE)\n\n---\n\n<div align=\"center\">\n<i>The AI cannot certify its own output. Something independent has to.</i>\n</div>\n"}