Metadata-Version: 2.4
Name: askql
Version: 0.20.1
Summary: Safe natural-language-to-SQL: validated, read-only queries across many SQL engines.
Author: askql maintainers
License: MIT
Project-URL: Homepage, https://github.com/TestAutomationArchitect/askql
Project-URL: Source, https://github.com/TestAutomationArchitect/askql
Project-URL: Changelog, https://github.com/TestAutomationArchitect/askql/blob/main/CHANGELOG.md
Keywords: sql,nl2sql,text-to-sql,llm,guardrails,read-only,database
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Database
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: sqlglot>=23.0
Requires-Dist: pyyaml>=6.0
Provides-Extra: postgres
Requires-Dist: psycopg[binary]>=3.1; extra == "postgres"
Provides-Extra: redshift
Requires-Dist: psycopg2-binary>=2.9; extra == "redshift"
Provides-Extra: oracle
Requires-Dist: python-oracledb>=2.0; extra == "oracle"
Provides-Extra: mssql
Requires-Dist: pymssql>=2.2; extra == "mssql"
Provides-Extra: tsql
Requires-Dist: pymssql>=2.2; extra == "tsql"
Provides-Extra: jdbc
Requires-Dist: JayDeBeApi>=1.2; extra == "jdbc"
Requires-Dist: JPype1>=1.5; extra == "jdbc"
Provides-Extra: llm
Requires-Dist: anthropic>=0.40; extra == "llm"
Provides-Extra: llm-aws
Requires-Dist: anthropic[bedrock]>=0.40; extra == "llm-aws"
Provides-Extra: llm-vertex
Requires-Dist: anthropic[vertex]>=0.40; extra == "llm-vertex"
Provides-Extra: llm-openai
Requires-Dist: openai>=1.40; extra == "llm-openai"
Provides-Extra: embeddings
Requires-Dist: sentence-transformers>=2.2; extra == "embeddings"
Provides-Extra: api
Requires-Dist: fastapi>=0.110; extra == "api"
Requires-Dist: uvicorn[standard]>=0.27; extra == "api"
Provides-Extra: mcp
Requires-Dist: mcp>=1.2; extra == "mcp"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Dynamic: license-file

# askql — governed natural-language data access, for humans and AI agents

Turn a plain-English question into a **validated, read-only SQL** answer against your real
database — and get back not just rows, but **proof the query was correct, authorized, and
defensible.** Self-hosted. Nothing leaves your perimeter. Any SQL engine.

> **Correct *and* defensible.** Most tools optimize one: a raw LLM writes plausible SQL (often
> wrong, always ungoverned); a BI tool is governed but can't answer a novel question. askql does
> both — it grounds the question in your data's real meaning, and it can't be talked into running
> anything unsafe.

## Ground · Govern · Prove

Three things happen on every request. All three ship today.

- **Ground** — *understand what you're asking.* A per-database graph of your schema with join paths
  **proven against the data** (not guessed from names), business-term glossary, and the real values
  your columns hold. This is what turns "how many active customers" into the *right* SQL instead of
  a confident wrong one.
- **Govern** — *guard the execution.* Every query is parsed and checked by an **AST validator** (the
  single source of truth): read-only, no DDL/DML, no `SELECT *` on a bare table, sensitive columns
  blocked, a row cap and timeout enforced — then run through a least-privilege, rolled-back
  connection. The safety is *structural*: an agent can't prompt-inject its way past it.
- **Prove** — *record what happened.* Every query returns a **decision envelope** — what was decided
  (allow / allow-with-masking / deny), which controls applied, which tables and sensitive columns
  were touched, and an `evidence_id` that matches the audit log. Every answer is auditable.

---

## 30 seconds

```bash
pip install "askql[postgres]"          # or [oracle] [mssql] [redshift] [jdbc] … + [mcp] [llm]

askql init --dialect postgres          # scaffold config/ + docs/ + .env (auto-discovered from here)
#   edit .env + config/databases.yaml  # credentials + host:port/db + schemas

askql doctor                            # 10-point connectivity/health check
askql test-db                           # per-dialect smoke battery (incl. read-only check)

# build the grounding — with join paths PROVEN against the data:
askql scrape --include-views --build-graph --infer-fks --verify-edges --sample-values
askql learn ./saved_sql --examples      # (optional) mine real SQL for join paths + examples
askql model validate                    # is the grounding internally consistent?

# ask — with the reasoning and the governance decision exposed:
askql ask "how many active customers are there" --explain
```

`--explain` shows the question coverage, the tables selected, which glossary terms / examples fired,
and the governance decision + `evidence_id`. No LLM key? Generation falls back to your IDE agent
(Copilot / Claude Code) — the safety pipeline is identical.

> **Windows:** if the `askql` launcher ever errors, `python -m askql …` is the shim-free equivalent.

---

## Your AI agent is the UI

askql ships an **MCP server** — seven governed, read-only tools an agent (Claude Desktop, Cursor,
VS Code, or any MCP client) drives directly: `list_tables`, `describe_table`, `compress_schema`,
`validate_sql`, `query`, `check_freshness`, `ask`.

```bash
pip install "askql[mcp]"
askql-mcp                                # stdio server; point your MCP client's command here
#   (bound to one database + identity via T2S_DATABASE / T2S_MCP_USER)
```

Every tool runs through the *same* validator + RBAC + read-only executor + audit as the CLI, and
`query`/`ask` return the decision envelope. So an agent can explore the schema and run SQL — and
**cannot** run a `DELETE`, exceed its row cap, or touch a schema its identity isn't scoped to. The
`mcp` SDK is a lazily-imported opt-in extra: orgs that disallow MCP can ignore it entirely.

---

## How it's different

| | raw LLM agent | traditional BI tool | bare semantic layer | **askql** |
|---|:---:|:---:|:---:|:---:|
| Answers a novel NL question | ✅ *(often wrong)* | ❌ | ❌ | ✅ *grounded* |
| Knows your business definitions | ❌ | in-tool only | schema only | ✅ glossary + values + rules |
| **Join paths proven against the data** | ❌ | ❌ | ❌ | ✅ `--verify-edges` |
| **Unsafe SQL blocked before execution** | ❌ | n/a | ❌ | ✅ AST validator |
| **Survives prompt injection** | ❌ | n/a | ❌ | ✅ structural, not prompt-based |
| **Every answer carries provable evidence** | ❌ | ❌ | ❌ | ✅ decision envelope + audit |
| Works through your agents (MCP) | ✅ | ❌ | ❌ | ✅ |
| Runs on your real DB, real dialect | ✅ | ✅ | definitions only | ✅ Oracle/MSSQL/Redshift/PG/… |
| Open, reviewable, git-native context | ❌ | ❌ | partial | ✅ plain YAML/MD |
| Self-hosted; no data leaves your perimeter | depends | ✅ | ✅ | ✅ |

---

## The grounding is yours — reviewable, versioned, in git

Everything that makes answers accurate is **plain files you own**, not state locked in a UI:
`schema-graph.<db>.json`, `glossary.<db>.yaml`, `examples.<db>.yaml`, `corrections.<db>.yaml`,
`docs/domain-rules.<db>.md`, `synonyms.yaml`. Review changes in a PR; roll them back like code.

```bash
askql model                 # one summary of every grounding layer for a database
askql model validate        # catches silent accuracy-killers (0-edge graph, glossary→missing table…)
askql model explain "vip"   # how a term resolves — glossary hit? column? a real sampled value?
```

The grounding **improves with use**: `askql feedback` captures a confirmed example or a *correction*
("‘active’ means `status='A'`, not `'ACTIVE'`"), and `askql learn` turns your existing SQL into
proven join paths and labelled examples.

---

## Safety is measured, not asserted

```bash
askql eval                                  # 32-case adversarial red-team; exits non-zero on any escape
askql eval --accuracy --cases cases.json    # score generated SQL by result-match against gold answers
```

- Only `SELECT` (+ `UNION`/`INTERSECT`/`EXCEPT`). No DDL/DML or procedural code — even hidden in a CTE.
- No `SELECT *` on a bare table/view; explicit columns (`COUNT(*)` is fine). Row limit required + capped.
- No system schemas, no sensitive columns (SSN, PASSWORD, …), no dangerous functions.
- Read-only session, rollback, timeout, and an audit record — on every query.

The red-team is a **CI gate** (safety is a test that fails the build on a regression). The accuracy
harness gives you a *number* for your own question set. A full evaluation protocol you can hand to a
reviewer is in [docs/partner-verification.md](docs/partner-verification.md).

---

## Bring your own model — any provider

Generation is pluggable; the safety pipeline is identical regardless. Set `T2S_LLM_PROVIDER`:
`anthropic` · `bedrock` (Claude on AWS) · `vertex` (Claude on GCP) · `openai` · `azure-openai` ·
`openai-compatible` (vLLM / Ollama / LM Studio / any self-hosted, **works air-gapped**) · `custom`
(your gateway) · *unset* → **BYO-LLM** (your IDE agent generates; no backend key). Nothing is locked
to one vendor, and no question or schema is sent anywhere you didn't configure.

---

## Also available

- **REST API** (`askql-api`) — run askql as a service so clients hold no drivers, JVM, or
  credentials; they call HTTP and get the same validator + RBAC + audit. `/validate`, `/compress`,
  `/query`, `/ask`.
- **Docker image** — bundles a JRE so the universal JDBC transport works with no local Java/native
  drivers. Mount `config/`, `.env`, and vendor jars at runtime.
- **Python library** — `from askql import validate, compress, execute_sql_text, ask` — typed
  (`py.typed`), optional deps imported lazily, everything config-injectable.

```python
from askql import validate, ask, Settings
r = validate("SELECT id, name FROM app.users LIMIT 10", settings=Settings(dialect="postgres"))
assert r.ok, r.errors
result = ask("how many active users this week")   # needs an LLM provider configured
print(result["sql"], result["decision"]["evidence_id"])
```

---

## Access control (optional)

With an identity present (`$T2S_USER` / `--user`) and `config/access-control.yaml`, a role decides
which **environments**, **schemas**, **PII mode** (blocked / masked / full), **row cap**, and
**rate limit** apply — enforced by the executor and surfaced in the decision envelope. With no
identity it's single-user read-only mode. `pii=masked` redacts sensitive **values** (`***`) at the
executor — the model can't reveal what it never receives.

---

## Docs

| | |
|---|---|
| [docs/partner-verification.md](docs/partner-verification.md) | Reproducible evaluation: connect → safe → correct → defensible |
| [ARCHITECTURE.md](ARCHITECTURE.md) | Design + the security hardenings over the source playbook |
| [CLAUDE.md](CLAUDE.md) | Operating instructions for the AI agent driving askql |
| [SHIPPING.md](SHIPPING.md) | Package / ship / install (wheel · internal index · Docker) |
| [CHANGELOG.md](CHANGELOG.md) | Release history |

**Read-only by construction.** askql executes only read-only `SELECT` through a least-privilege
connection; point it at whatever environment your access policy permits. MIT licensed.
