Dex lets your agent build your analytics.
Overview
Most deadly errors arise from obsolete assumptions. Frank Herbert, Children of Dune Explore your data, build models and semantic layers, and keep them in sync as schemas change. Works with databases, data warehouses, lakehouses, and SQL engine endpoints through supported connectors. (run these inside Claude Code, one at a time): - your database, data warehouse, or SQL endpoint. Find the tables that matter, understand their structure, and verify how they join. Get column profiles, personal-data flags, and an ER diagram. - your dbt project and semantic layer. Create models, tests, docs, and metrics as reviewable plans, then build and verify on a dev target. - your models and metrics as sources change. Detect drift in schemas, volumes, grain, and metric definitions, with proposed fixes to review. Your source data stays read-only. Builds run on a dev target, query costs are quoted before spend, and every project change is a diff you review.
README
Most deadly errors arise from obsolete assumptions.
Frank Herbert, Children of Dune
Dex
Dex lets your agent build your analytics.
Explore your data, build models and semantic layers, and keep them in sync as schemas change.
Works with databases, data warehouses, lakehouses, and SQL engine endpoints through supported connectors.
Built by Exmergo
Install
Any agent (run in your terminal):
npx skills add exmergo/dex
Claude Code (run these inside Claude Code, one at a time):
/plugin marketplace add exmergo/exmergo-agent-plugins
/plugin install dex@exmergo
Codex:
npx skills add exmergo/dex --agent codex
What you get
- Explore your database, data warehouse, or SQL endpoint. Find the tables that matter, understand their structure, and verify how they join. Get column profiles, personal-data flags, and an ER diagram.
- Transform your dbt project and semantic layer. Create models, tests, docs, and metrics as reviewable plans, then build and verify on a dev target.
- Maintain your models and metrics as sources change. Detect drift in schemas, volumes, grain, and metric definitions, with proposed fixes to review.
Your source data stays read-only. Builds run on a dev target, query costs are quoted before spend, and every project change is a diff you review. Works in Claude Code, Codex, or any agent that loads Agent Skills.
[!IMPORTANT] Dex needs
uvon yourPATH. No agent installs it for you. Runbrew install uvorpipx install uv, or see the uv installation docs for other platforms.uvsupplies Python and the engine. Use uv 0.13.4 or later (uv self update): earlier releases still trust the emSign CA roots withdrawn after their keys were compromised.
In Claude Code the skills appear as /dex:explore, /dex:transform, and
/dex:maintain and trigger on matching intent. Update later with
/plugin marketplace update exmergo. Codex also gets a native plugin, with no MCP
server needed. Any other agent can be pointed at AGENTS.md.
Run Dex from your project directory, so it finds your .dex/config.yml and keeps
its cache next to your project. Dex needs an agent with a local shell, so it does
not run in claude.ai chat.
[!TIP] Skip the first-run wait. The first command installs the engine, which takes tens of seconds on a cold
uvcache. Ask your agent to warm Dex once after installing, or run the command below in a CI or container build step. Add--connector snowflake(or any connector) to warm one before a project exists.
uv run --no-project --script skills//scripts/run.py --warm
Why
Writing SQL is one part of analytics engineering. Your agent also needs to:
- understand the schema without starting from scratch every session,
- find the relevant tables among thousands,
- account for what a query costs,
- keep personal data out of its context,
- keep models and metric definitions coherent as their sources change.
Dex gives the agent a repeatable explore, transform, maintain loop, with guardrails enforced in the engine.
Try it in three commands
No existing database, no credentials, no cloud account, and no network once the package is installed.
pip install "exmergo-dex-core[duckdb]"
dex demo
dex explore map
dex demo writes a small e-commerce DuckDB database (dex_demo.duckdb, 7 tables,
29,512 rows) and a .dex/config.yml into the current directory, so every command
after it runs with no flags. It refuses rather than overwrite anything. The data
comes from a pinned seed, so what you see is what is written here.
explore map maps all 7 tables, infers 5 joins, flags 6 columns as personal data,
and reports 6 data-quality findings. Every command answers with one JSON envelope.
An excerpt, for one table:
{
"identifier": "dex_demo.main.order_items",
"row_count": 14000,
"grain": null,
"data_quality": [
"order_item_id is not unique: 13000 distinct over 14000 rows (1000 rows would have to be removed for it to be unique, so it is unique for 92.9% of rows); joins on it will fan out"
]
}
It is broken on purpose
A first run that reports a clean bill of health teaches you nothing, so the demo ships with real defects. Dig into them:
dex explore profile order_items products
dex explore relationships --verify
dex explore query "select email from customers"
- A broken grain. A batch was loaded twice, so
order_item_idis unique for only 92.9% of rows. Dex reports the duplicates and leaves the grain unknown rather than guessing a key. - A key that mixes id schemes.
skuis90% numeric, 10% 32-character hexadecimal (md5-shaped). Cast it to a number and you silently drop 10% of products. - A join that looks right and is not.
web_events.customer_idshares a name with the CRM’s key, but verification finds 100% of its values have no match. - A refusal. The query firewall will not put
customers.emailinto context.select count(distinct email) from customersruns, because a statistic is not a value.
There is also a table an interrupted load left empty, two columns whose declared
type contradicts their content, and two designed PII false positives. See the
dex demo reference.
[!NOTE] DuckDB is free and local, so nothing here asks you to confirm a spend. On a metered connector the same commands return an estimate first and run only once you agree to it.
How it works
flowchart LR
Agent[Coding agent] --> Skills[Dex skills]
Skills --> Engine[exmergo-dex-core engine]
Engine -->|SELECT-only SQL, cost-capped| Database[(Your database, data warehouse, or SQL endpoint)]
Engine -->|dbt builds, dev target only| Database
Engine -->|one sanitized JSON envelope| Agent
Engine -->|plans as diffs| Repo[Your repository: dbt project + semantic layer]
Engine Cache[.dex/ cache and snapshot]
The skills connect your agent to the exmergo-dex-core engine, which holds the
logic and guardrails behind a small command contract.
Your dbt project and semantic-layer definitions live in your repository as
reviewable files. The .dex/ directory holds Dex’s cache and snapshots.
Explore
Find the tables that matter, profile their columns, and verify joins before writing SQL. Answer ad-hoc questions through a query firewall that checks for personal data, read and query the semantic layer, and map relationships as a Mermaid ER diagram. Exploration is read-only and needs no dbt project. Skill · methodology · commands
Transform
Build and refactor dbt models from staging to marts, with tests, docs, and declared grain and population. Define semantic models and metrics over them, or work with a native semantic layer without a dbt project. Review each stored plan before applying it, then build and verify on a dev target. Skill · what Dex writes · commands
Maintain
Compare database schemas and profiles, the dbt project, and the semantic layer
with the last snapshot. See which models and metrics a change affects and review
the proposed edits. maintain verify also checks a project as it stands, with no
baseline needed.
Skill · commands
[!TIP] Give every agent in your repository the same procedure.
dex procedure --blockprints the procedure every Dex skill follows, ready to paste into yourCLAUDE.mdorAGENTS.md, so an agent follows it even before it loads a skill. Dex never writes the file;dex procedure --check CLAUDE.mdtells you when an upgrade has made your copy stale. Seedex procedure.
Connectors
| Connector | Type | Self-hostable | Extra / --connector |
Cost guardrail | Connection details |
|---|---|---|---|---|---|
| Snowflake | Cloud warehouse | ❌ | snowflake |
Warehouse-seconds, with credits | connections.toml, SNOWFLAKE_* env, or a dbt profile |
| BigQuery | Cloud warehouse | ❌ | bigquery |
Bytes scanned | Application Default Credentials |
| Databricks | Lakehouse via SQL endpoint | ❌ | databricks |
Warehouse-seconds, with DBUs | databricks auth login, DATABRICKS_* env, or a dbt profile |
| Amazon Redshift | Cloud warehouse, Serverless-first | ❌ | redshift |
Compute-seconds, with RPU-hours | The AWS credential chain or REDSHIFT_* env |
| Postgres | Operational database | ✅ | postgres |
Database-seconds | pg_service.conf, DATABASE_URL, PG* env, or a dbt profileAlso works with Supabase, Neon, and more managed Postgres platforms |
| DuckDB | Embedded analytical | ✅ | duckdb |
Free and local | None, just a file path |
| ClickHouse | Analytical database | ✅ | clickhouse |
Compute-seconds on Cloud, database-seconds self-hosted | CLICKHOUSE_URL, CLICKHOUSE_* env, or a dbt profile |
| Trino | Federated query engine | ✅ | trino |
Cluster-seconds | TRINO_URL, TRINO_* env, or a dbt profileAlso works with: MySQL, SQL Server, MongoDB, and more databases through Trino catalogs |
Credentials are discovered and never enter the agent’s context. Every scan is estimated, confirmed, and capped server-side, and settled spend is recorded in a local ledger (cost controls). Self-hosted databases bill no dollars and are still gated, because an unbounded scan on a production Postgres primary is a real cost too.
Coming next: MotherDuck, Starburst Galaxy, Microsoft Fabric.
Semantic layers
Choose the semantic layer independently of your database connector. Dex supports
dbt semantic models and native Ossie, SLayer, or Cube files. Configure the choice
in .dex/config.yml; Ossie, SLayer, and Cube need no dbt project.
(overview)
| Semantic layer | Hosted | Queryable | vendor / deployment |
Read through | Documentation |
|---|---|---|---|---|---|
| Apache Ossie (incubating) | ❌ | ❌ | ossie / local |
Native documents in the repository, no dbt or MetricFlow in the path | Docs |
| dbt | ✅ | ✅ | dbt / local or dbt_cloud |
MetricFlow locally, run through the Dex connector and its cost guard, or the hosted dbt Cloud Semantic Layer API | Docs |
| Cube | ❌ | ✅ | cube / local |
Plain YAML model files, read statically with no Node or Cube server; querying asks a running Cube server to render, Dex runs it under the cost guard | Docs |
| SLayer (by Motley) | ❌ | ✅ | slayer / local |
SLayer model files, validated by one pinned release; SLayer renders, Dex runs it under the cost guard | Docs |
Coming next: hosted Cube, hosted SLayer, Snowflake Semantic Views, Looker / LookML, and Databricks Metric Views.
See it on a real project
github-repo-analytics is a template that tracks GitHub traffic, stars, downloads and contributors for your open-source projects, free on GitHub Actions.
Every model and metric was built and is maintained with Dex. Its audit trail holds the raw envelopes, including the drift Dex blocked.
Use Dex from Python
The engine is a plain Python package, exmergo-dex-core:
pip install exmergo-dex-core # or: uv add exmergo-dex-core
Drive the same loop from Python instead of parsing CLI output:
from exmergo_dex_core import DexEngine
with DexEngine(connector="duckdb", path="shop.duckdb") as eng:
mapped = eng.map() # a DexCache, not a JSON blob
rows = eng.query("select status, count(*) from orders group by status")
print(mapped.relationship_count, rows.cells)
Every guarantee the CLI makes holds here, because it is the same code. An
unconfirmed billed call raises ConfirmationRequiredError carrying the estimate.
By default nothing is written to disk; DexEngine.from_repo("path/to/repo") opts in
to a project on disk, the way the CLI does.
For hosts embedding Dex:
- Values-free mode keeps every table value out of the model’s view, aggregates only. (values-free mode)
- Per-user credentials: pass a
ConnectionSourceso each request reaches the connected system as its own principal. - Multi-process lifecycles: export a plan, verify and apply it elsewhere, and get typed evidence of what a build established. (host integration)
- Other formats and stores: plug in a project format or a storage backend.
More in the package README.
Benchmarks
We run Dex on two public analytics-engineering benchmarks and commit every run’s raw per-task results, including the ones that flatter us least.
| Benchmark | Setup | Result | Details |
|---|---|---|---|
| data-eng-bench (Snowflake, 103 tasks) | Dex + Claude Sonnet 5 | 57.3% resolved, 89.7% of assertions pass | README |
| ADE-bench (dbt Labs, 75 tasks) | Dex + Claude Sonnet 5 | 76% resolved, at 2.5x lower cost than Fable 5 | README |
We believe that benchmarks are important, but not as important as user/agent experience.
Trust in a diff, cost surfaced before spend, and sensitive data kept out of context. We optimize for that experience
and treat these scores as guide posts. (evaluation)
Managing the Dex lifecycle
What Dex sends where
- On install,
uvdownloads the pinned engine (and a Python 3.11 to 3.14 if you have none) from PyPI or your configured index. - Your connected database, data warehouse, or SQL endpoint gets SELECT-only SQL from Dex, plus the dbt builds you confirm on a dev target, with credentials from your existing credential chain.
- dbt Cloud is contacted only if you enable the hosted semantic layer.
- dbt-core, when Dex runs it, sends dbt Labs no usage statistics: Dex sets
DO_NOT_TRACK=1for every dbt process it starts.transform depsdownloads the packages yourpackages.ymldeclares. - Your repository holds Dex’s state in
.dex/. dbt writes its usualtarget/andlogs/.
[!IMPORTANT] Dex sends nothing to Exmergo. No telemetry, analytics, license check, or update ping. See the Dex privacy policy and the Dex terms of service.
What to commit in .dex/
Dex keeps its working state in .dex/. Most of it is safe to commit; the
exception is any file that can carry data values. Commit the lockfile and the
config, and keep the exploration cache out of a repo that must not publish
data values:
| File | Commit? | Can it contain data values? |
|---|---|---|
.dex/config.yml |
Yes | No: connector targets, pii_overrides (column names, not values), budgets and limits. Credentials live in environment variables or dbt profiles, never in this file. |
.dex/snapshot.json |
Like a lockfile, where its values may be public; otherwise take a metadata-only baseline or keep it out | Yes: when snapshotted from a cache it pins the cache’s datasets wholesale, including each non-PII column’s capped value domain and min/max. A metadata-only baseline (no cache) carries schema and volume only. PII-flagged columns never carry value domains. |
.dex/cache.json |
Only if values may be public | Yes: column profiles with capped value domains (actual values with counts). Never for PII-flagged columns. |
.dex/plans/*.json |
Optional, as an audit trail | No data values: the proposed contents of project files. |
.dex/queries.jsonl |
Optional, as a ledger | SQL text, which may hold literals. |
.dex/drift.json |
No: regenerate with maintain check |
Aggregates only: counts, names and schema metadata in drift findings. |
For a repo that must not publish data values, ignore the rest:
# Dex state that can publish data values, or is local-only output.
.dex/cache.json
.dex/dex.db
.dex/dex.db-journal
.dex/queries.jsonl
.dex/drift.json
.dex/spend.jsonl
.dex/spend.lock
.dex/cache.lock
.dex/dex.db is the SQLite backend’s equivalent of cache.json, so it gets
the same caution. .dex/spend.jsonl is the billed-command ledger: byte
counts, job ids and statement hashes only, never SQL values or credentials,
but it is local spend history, so there is no reason to commit it.
What Dex will never do
- Write to your source data. Dex’s own SQL is SELECT-only. The only data writes are the dbt builds you confirm, on a dev target.
- Put personal data in your agent’s context. PII is flagged by column, category, and confidence, and never surfaced. Only a human clears a flag. (PII policy)
- Spend before quoting. A metered scan returns an estimate and runs only with your confirmation and a budget. (cost controls)
- Change your project behind your back. Every edit is a diff, and a human edit made since planning is never overwritten. (source of truth)
- Build anywhere but dev. Prod-looking targets are refused outright.
Further reading
- Documentation: start here
- CLI reference: every command and flag
- Command contract and
AGENTS.md: how any agent drives the engine - Cost controls and PII policy: the two guardrails that cut across everything
- Configuration: read and change
.dex/config.ymlas a confirmed diff - Connectors: setup, cost, and read-only enforcement per connector
- Changelog
references/: the same material as Markdown, for agents and offline reading
Dex Enterprise
Dex Enterprise runs Dex as automated workflows in your own CI. It turns tickets into
draft pull requests with explore and transform, and runs maintain on a schedule
to turn drift into draft pull requests for your engineers to review. No Exmergo
service sits in the request path, and everything in this repository stays
Apache-2.0. Learn more.
Community
Community Integrations
| Integration | Maintainer | What it does | Details |
|---|---|---|---|
| dagster-dex | CatInCloud Labs | Explore and maintain your Dagster assets with Dex, using the asset graph in place of a dbt project. | Repository |
| OpenLakeForge | OpenLakeForge | Explore an OpenLakeForge lakehouse alongside Dex through the olf CLI, with read-only access to Trino data, OpenMetadata domains and products, and Dagster jobs and runs. |
Skill |
Connect with the Community
Join the agent-native data/analytics community!
- 🌟 Star Us on GitHub
- 👾 Join Our Discord Community
- 🔗 Follow Us on LinkedIn
- 🐦 Follow Us on X
- 🔨 Follow Us on GitHub
Contributing
See CONTRIBUTING.md for local setup, linting, the pre-commit
hook, and changelog fragments. Every pull request into main must pass Lint and
CI, and adds a fragment under changelog.d/ unless no user can
see the change. Please also read the code of conduct.
License
Apache-2.0. See LICENSE and NOTICE. The licence governs the software. Exmergo’s distribution, documentation, support, and trademarks are covered by the Dex terms of service.
Recommended Tools
Try a different keyword or remove a filter.
Install
npx skillfish add exmergo/dex