{"id":"0578f001-89fd-4f0c-bc9b-fe5320dfeedc","slug":"exmergo-dex","kind":"skill","name":"dex","summary":"Dex is the agent-native analytics engineering toolkit. Point it at your warehouse and your dbt project. It learns the landscape, authors your transformations, and tells you exactly what to fix when th","owner":"exmergo","repoUrl":"https://github.com/exmergo/dex","license":"Apache-2.0","licenseTier":"permissive","trust":"community","stars":78,"match":null,"fewStars":false,"format":"skill","createdAt":null,"addedAt":"2026-10-14T06:04:23.693Z","logoUrl":"https://avatars.githubusercontent.com/u/263040533?v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["data-analytics","databases","developer-tools"],"tags":["agent","analytics-engineering","bigquery","claude-code","claude-code-plugin","data-contracts","data-engineering","databricks"],"runtime":"binary","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-14T06:15:49.248Z","sample":false,"url":"https://conduits.dev/tools/exmergo-dex","language":"Python","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"<img width=\"1920\" height=\"1080\" alt=\"Video 2\" src=\"https://github.com/user-attachments/assets/f9c8c052-32fb-4b2f-8b89-a6f484b55035\" />\n\n\n**Built by [Exmergo](https://exmergo.com)** · The AI Stack for Your Data Stack.\n\n[![PyPI](https://img.shields.io/pypi/v/exmergo-dex-core?logo=pypi&logoColor=white&color=165dfc)](https://pypi.org/project/exmergo-dex-core/)\n[![License](https://img.shields.io/badge/license-Apache--2.0-165dfc)](LICENSE)\n[![data-eng-bench](https://img.shields.io/badge/data--eng--bench-57%25-33cf56)](benchmarks/data-eng-bench/README.md)\n[![ADE-bench](https://img.shields.io/badge/ADE--bench-76%25-33cf56)](benchmarks/ade_bench/README.md)\n[![CI](https://github.com/exmergo/dex/actions/workflows/ci.yml/badge.svg)](https://github.com/exmergo/dex/actions/workflows/ci.yml)\n\n[![LinkedIn](https://img.shields.io/badge/LinkedIn-Exmergo-165dfc?logo=linkedin&logoColor=white)](https://www.linkedin.com/company/exmergo/)\n[![X](https://img.shields.io/badge/Follow-%40exmergo-165dfc?logo=x&logoColor=white)](https://x.com/exmergo)\n[![Star the repo!](https://img.shields.io/github/stars/exmergo/dex?style=flat&label=Star%20the%20repo!%20%E2%AD%90&labelColor=555&logo=github&logoColor=white&color=165dfc)](https://github.com/exmergo/dex)\n\n## Install (Any Agent)\n\nRun this command in your terminal\n```\nnpx skills add exmergo/dex\n```\n\n## Install (Claude Code)\n\nRun these commands **inside Claude Code** one at a time\n```\n/plugin marketplace add exmergo/exmergo-agent-plugins\n```\n```\n/plugin install dex@exmergo\n```\n\nUpdate later with `/plugin marketplace update exmergo`. The skills appear as\n`/dex:explore`, `/dex:transform`, and `/dex:maintain` and auto-trigger on matching\nintent. Ask it to warm dex once after installing, so the first real command does\nnot wait for the engine to install (see [Prerequisite: `uv`](#prerequisite-uv)).\n\n## `dex`: the agent-native analytics engineering toolkit\n\n**`dex` is analytics engineering** for Claude Code and **any agent**: **data warehouse\nexploration**, **dbt transformation** and **semantic modeling**, and **schema-drift\nmaintenance**. Point it at your warehouse (or a local DuckDB file, or the one\n`dex demo` generates for you) and at your repository; it learns the landscape,\nwrites and refactors your dbt transformations and your semantic layer, and tells\nyou what to fix when anything drifts. Your repository is the source of truth, on\ntwo independent axes: the transformation project, which is dbt, and the semantic\nlayer, which is dbt's own, a hosted dbt Cloud deployment, or native Apache Ossie\ndocuments that need no dbt project at all. Every change is a reviewable diff.\nRead-only against your data.\n\n**It closes the gap a general coding agent still has**: agents re-learn the schema\neach session, have no strategy for thousands of tables, are blind to warehouse\ncost, will pull sensitive data into context, do not treat a dbt project as a\nfirst-class object, and have no concept of a semantic model to keep coherent over\ntime. `dex` owns exactly that loop.\n\n## The loop\n\n**Explore. Transform. Maintain. (ETM)**\n\n- **Explore** an unfamiliar warehouse: rank what matters, profile selectively,\n  infer and verify joins, answer ad-hoc questions with guarded SQL probes behind\n  a PII-aware query firewall, read the semantic layer as the object graph it is\n  (semantic models, metrics with their composition, measures, dimensions, and the\n  declared join graph, each resolved to the relation and column behind it, and the\n  whole of it searchable and budgeted), read a\n  dimension's value domain before filtering on it,\n  and query its metrics (locally via\n  MetricFlow or against a hosted dbt Cloud deployment; a native Apache Ossie\n  layer is catalog-first and refuses a metric query by name, because the format\n  specifies interchange metadata and no query runtime), and render the map as a\n  Mermaid ER diagram that draws the joins the semantic layer declares and never\n  claims a cardinality the data has not proven.\n  Persist a draft map. Fully read-only.\n\n<img width=\"522\" height=\"343\" alt=\"image\" src=\"https://github.com/user-attachments/assets/7f16b370-66ed-4596-ae01-041cf3db3525\" />\n\n  \n- **Transform** the project: author dbt models (staging to marts) with tests\n  and docs, and the semantic layer on top, either as dbt semantic models\n  (MetricFlow YAML: entities, dimensions, measures, metrics) or as native Apache\n  Ossie documents written back byte for byte, with a free Viz preview.\n  Validated against a dev target, cost-guarded.\n\n<img width=\"504\" height=\"271\" alt=\"image\" src=\"https://github.com/user-attachments/assets/fda40e48-b481-424c-adc7-d79c0ede346b\" />\n\n  \n- **Maintain** the repository as it drifts: diff the warehouse, the project, and\n  the semantic layer against the last snapshot, surface schema, volume, grain,\n  and definition drift ranked by blast radius, and propose edits. The two project\n  axes are fingerprinted independently, so a repository with a semantic layer and\n  no dbt project still gets a baseline. `maintain verify` also reads the project\n  format seam directly: relation-existence and grain checks run from its declared\n  model relations, while compile, build-status, row-population, column-contract,\n  and join-contract checks are explicitly suppressed when the format cannot\n  provide dbt `target/` artifacts.\n\n<img width=\"484\" height=\"344\" alt=\"image\" src=\"https://github.com/user-attachments/assets/ff714eaf-f0b2-46d6-8a4b-c69791740f18\" />\n\n## Try it in three commands, on your laptop\n\nNo warehouse, no credentials, no cloud account, no network. `dex demo` generates a\nsmall e-commerce DuckDB warehouse locally and points the following commands at it.\n\n```\npip install \"exmergo-dex-core[duckdb]\"\ndex demo\ndex explore map\n```\n\n`dex demo` writes two files in the directory you are standing in, and refuses rather\nthan overwrite anything: `dex_demo.duckdb` (7 tables, 29,512 rows) and a\n`.dex/config.yml` so everything after it runs with no flags. The data is generated\nfrom a pinned seed, so what you see is what is written here. `dex config get` shows\nwhat that config resolves to, and `dex config set` and `dex config unset` change it as\na diff you confirm, keeping its comments.\n\nIt is seeded to be **realistically broken**, because a first run that reports a clean\nbill of health teaches you nothing. `explore map` flags 6 columns as personal data,\ninfers 5 joins, and reports 6 data-quality findings. Then:\n\n```\ndex explore profile order_items products\ndex explore relationships --verify\ndex explore query \"select email from customers\"\n```\n\n- **A broken grain, reported as duplicates rather than as a missing key.**\n  `order_item_id is not unique: 13000 distinct over 14000 rows (1000 rows would have\n  to be removed for it to be unique, so it is unique for 92.9% of rows)`, because a\n  batch was loaded twice. Any join on it silently fans out. The grain comes back\n  unknown rather than as one of the several column pairs that are technically unique\n  here only because `order_item_id` almost is; those are in `key_evidence` with the\n  reason each was suppressed.\n- **A key that mixes id schemes.** `sku` is `90% numeric, 10% 32-character\n  hexadecimal (md5-shaped)`, from a merged catalogue. Cast it to a number and you\n  drop 10% of your rows without an error.\n- **A join that looks right and is not.** `web_events.customer_id` shares the CRM's\n  column name and type, so it is inferred; verification finds **100% of values have\n  no match**, so the inference collapses instead of shipping a join that returns all\n  NULLs and looks like it worked.\n- **A refusal.** The query firewall declines to project `customers.email` into\n  context. `select count(distinct email) from customers` runs, because a statistic\n  is not a value.\n- Plus a table an interrupted load left empty, two columns whose declared type\n  contradicts their content, and two PII **false positives** on a distribution\n  centre's city and coordinates, which are a designed behaviour and worth meeting\n  early.\n\nDuckDB is free and local, so nothing here asks you to confirm a spend. On BigQuery\nor Snowflake the same commands return an estimate first and run only once you agree\nto it.\n\n## Prerequisite: `uv`\n\ndex installs and runs its engine through [`uv`](https://docs.astral.sh/uv/), so you\nneed it on your `PATH` before either install below. Neither Claude Code nor the\nplugin installs it for you.\n```\ncurl -LsSf https://astral.sh/uv/install.sh | sh\n```\n`brew install uv` and `pipx install uv` work too. Nothing else is required: `uv`\nsupplies the Python and the engine, with the connector extra chosen for you at\nruntime.\n\nThe first command in a fresh environment pays for that install, which is tens of\nseconds on a cold `uv` cache. `--warm` pays it up front instead: it materializes\nthe environment, prints what it installed, and exits without running anything.\n```\nuv run --no-project --script skills/<skill>/scripts/run.py --warm\n```\nRun it as a container build step or a CI setup step, or ask your agent to warm dex\nonce after installing. Add `--connector snowflake` (or any other connector) to warm\na warehouse before there is a project to read the choice from.\n\n## Benchmarks\n\nWe run `dex` on two public analytics-engineering benchmarks. Every run's raw\nper-task results are committed, including the ones that flatter us least.\n\n### data-eng-bench (Snowflake, 103 tasks)\n\nEach task hands the agent a **2,356-model dbt project on a 489 MB DuckDB\nwarehouse** and a prescriptive ticket, then runs a hidden pytest suite after a\ncold `dbt run`. Scoring is binary and total: one failed assertion is a zero.\n\n`dex` + **Claude Sonnet 5** resolves **59 of 103 tasks (57.3%)**, with dex firing\non **98% of trials**. That is nominally the highest published Sonnet 5 figure and\nstatistically indistinguishable from the 56.6% Snowflake published for both Claude\nCode and their own CoCo harness, since 0.7 points on 103 tasks is less than one\ntask. Read it as parity, not as a win.\n\nBecause the reward is all-or-nothing, we also publish assertion-level results:\n**89.7% of assertions pass** (task-weighted), and 19 of the 44 unresolved tasks\nmissed by exactly one assertion. Full methodology and the per-check record are in\nthe [data-eng-bench README](benchmarks/data-eng-bench/README.md).\n\n### ADE-bench (dbt Labs, 75 tasks)\n\nFix, build, and extend dbt projects on DuckDB. `dex` + **Claude Sonnet 5** reaches\n**76% task resolution**, at **2.5x lower cost than Claude Fable 5**.\n\n<img width=\"719\" height=\"283\" alt=\"image\" src=\"https://github.com/user-attachments/assets/9f8bca64-6508-4590-9fa7-bb1ac077263d\" />\n\n\nWith `dex`, accuracy clusters tightly across models (72-76%) while cost does not,\nso you can run an inexpensive model and still get top-tier results. One honest\ncaveat on this one: dex was actually invoked in only 15 of the 75 Sonnet 5 trials,\nand on those 15 it netted a single extra task, so the 76% is mostly a statement\nabout the model rather than about `dex`. Per-model cost and the raw `results.json`\nfor every run are in the [ADE-bench README](benchmarks/ade_bench/README.md).\n\n### On benchmarks\n\nWe publish these to be transparent, not to overclaim. A task-resolution score\nmeasures whether tests pass; it does not measure what matters most in practice:\nthe experience of the human engineer working with the agent. Trust in a diff,\nclarity of the proposed change, cost surfaced before spend, and sensitive data\nkept out of context never show up in a pass rate. We optimize for that\nexperience first and treat these scores as guide posts, not as the goal.\n\nTwo habits follow from that. We report **how often `dex` actually ran** next to\nthe accuracy, because a score with the tool firing on 98% of trials and the same\nscore with it firing on 20% are different claims and only the first says anything\nabout `dex`. And we do not turn a gap smaller than the noise into a headline: a\nsingle run, one attempt per task, tells you roughly where a setup stands, not that\nit is better than the one a point below it.\n\n## Connectors\n\n| Connector | Type | Self-hostable | Extra / `--connector` | Cost surfaced as | Credentials discovered from |\n| --- | --- | :---: | --- | --- | --- |\n| <img src=\"https://www.exmergo.com/connectors/snowflake.png\" width=\"20\" height=\"20\" alt=\"\"> **Snowflake** | Cloud warehouse | ❌ | `snowflake` | Warehouse-seconds, credits alongside | `connections.toml`, `SNOWFLAKE_*` env, or a dbt profile |\n| <img src=\"https://www.exmergo.com/connectors/bigquery.png\" width=\"20\" height=\"20\" alt=\"\"> **BigQuery** | Cloud warehouse | ❌ | `bigquery` | Bytes scanned | Application Default Credentials (`gcloud auth application-default login`) |\n| <img src=\"https://www.exmergo.com/connectors/databricks.png\" width=\"20\" height=\"20\" alt=\"\"> **Databricks** | Cloud warehouse | ❌ | `databricks` | Warehouse-seconds, DBUs alongside | The SDK's unified chain: `databricks auth login`, `DATABRICKS_*` env, or a dbt profile |\n| <img src=\"https://www.exmergo.com/connectors/redshift.png\" width=\"20\" height=\"20\" alt=\"\"> **Amazon Redshift** | Cloud warehouse, Serverless-first | ❌ | `redshift` | Compute-seconds, RPU-hours alongside | The AWS credential chain (a pinned Serverless workgroup mints IAM temporary database credentials) or `REDSHIFT_*` env |\n| <img src=\"https://www.exmergo.com/connectors/clickhouse.png\" width=\"20\" height=\"20\" alt=\"\"> **ClickHouse** | Analytical database | ✅ | `clickhouse` | Compute-seconds on Cloud, with live allocated memory translating to approximate compute-unit-hours and optional USD; database-seconds self-hosted | `CLICKHOUSE_URL`, the `CLICKHOUSE_*` env, or a dbt profile |\n| <img src=\"https://www.exmergo.com/connectors/duckdb.png\" width=\"20\" height=\"20\" alt=\"\"> **DuckDB** | Embedded analytical | ✅ | `duckdb` | Free and local, nothing to confirm | None, just a file path |\n| <img src=\"https://www.exmergo.com/connectors/postgresql.png\" width=\"20\" height=\"20\" alt=\"\"> **Postgres** | Operational database | ✅ | `postgres` | Database-seconds, no invoice | `pg_service.conf`, `DATABASE_URL`, the `PG*` env, or a dbt profile |\n\nCredentials are discovered, never asked for. Every scan is estimated and\nconfirmed before it spends, and capped server-side: `maximum_bytes_billed` on\nBigQuery, a per-statement statement timeout on Snowflake, Databricks, Redshift,\nand Postgres, and `max_execution_time` plus `max_bytes_to_read` on ClickHouse.\nAll settled spend is recorded in a local ledger.\n\nSelf-hosted Postgres and ClickHouse bill no dollars, and dex still gates them: an\nunbounded scan on a production Postgres primary or a shared ClickHouse cluster\nis a real cost even when nothing appears on an invoice.\n\n### Upcoming Connectors\n\n- Cloud warehouse: **Trino**, **Azure Synapse**, **Microsoft Fabric**\n\n## Semantic layers\n\nThe semantic layer is a separate axis from the transformation project, chosen\nonce per repository in `.dex/config.yml`. dex reads two vendors across three\ndeployments today:\n\n| Semantic layer | Hosted | Queryable | `vendor` / `deployment` | Read through |\n| --- | :---: | :---: | --- | --- |\n| <img src=\"https://www.exmergo.com/connectors/dbt.png\" width=\"20\" height=\"20\" alt=\"\"> **dbt** | ✅ | ✅ | `dbt` / `local` or `dbt_cloud` | MetricFlow locally, with the rendered SQL run through the dex connector and its cost guard, or the hosted dbt Cloud Semantic Layer over its API |\n| <img src=\"https://www.exmergo.com/connectors/ossie.png\" width=\"20\" height=\"20\" alt=\"\"> **[Apache Ossie](https://github.com/apache/ossie)** (incubating) | ❌ | ❌ | `ossie` / `local` | Native documents read straight out of the repository, with no dbt project and no MetricFlow anywhere in the path |\n\nOssie is catalog-first, and that is a statement about the format rather than\nabout how far we got: Ossie specifies interchange metadata and no portable query\nruntime, so dex reads and authors the layer, folds its declared keys and\nrelationships (composites kept whole) into exploration and drift detection, and\nrefuses a metric query by name instead of inventing execution semantics the\nspecification does not define. What dex accepts, what it checks, and what it\ndeclines to claim is written out row by row in\n[`references/ossie-compatibility.md`](references/ossie-compatibility.md), and\n[`references/ossie-walkthrough.md`](references/ossie-walkthrough.md) runs one\ndocument through every command on a local warehouse.\n\n### Upcoming Semantic Layers\n- Cube\n\n## The `exmergo-dex-core` package\n\n`dex` also bundles the `exmergo-dex-core` Python package.  \nThis is the reusable and agent-friendly package that contains all the core\nexplore, transform, and maintain logic. This also holds connectors and the\nwrite logic for .dex/ which stores cache, snapshots, and query billing logs. \n\nYou can install it yourself in your projects:\n\n```\npip install exmergo-dex-core\n```\n\nor\n\n```\nuv add exmergo-dex-core\n```\n\n### Use it as a library\n\nThe engine has a programmatic API, so you can drive the same loop from Python\ninstead of shelling out to the CLI and parsing JSON:\n\n```python\nfrom exmergo_dex_core import DexEngine\n\nwith DexEngine(connector=\"duckdb\", path=\"shop.duckdb\") as eng:\n    mapped = eng.map()                  # a DexCache, not a JSON blob\n    rows = eng.query(\"select status, count(*) from orders group by status\")\n\nprint(mapped.relationship_count, rows.cells)\n```\n\nMethods return domain objects and result records, never the CLI's stdout\nenvelope. Nothing above writes to disk: the default store keeps state in the\nprocess, so importing the package cannot leave a `.dex/` directory in your repo.\n`DexEngine.from_repo(\"path/to/repo\")` opts in to a project on disk, which is exactly\nwhat the CLI itself does.\n\nEvery guarantee the CLI makes holds here too, because it is the same code: reads\nare read-only, cost is surfaced before any spend (an unconfirmed billed call\nraises `ConfirmationRequiredError` carrying the estimate), and PII stays flagged\nrather than surfaced.\n\nA process serving more than one end user can pass a `ConnectionSource` so each\nrequest reaches the warehouse as its own principal rather than as the container,\nand a `SemanticSource` to do the same for a hosted dbt Cloud Semantic Layer\ntoken. `SemanticSource` is a credential and nothing more; the reader that decides\nwhich semantic layer answers is a separate seam, resolved from config, and the\ntwo share a word rather than a job.\nThe host owns authentication; dex still builds the cost gate from your store, so\nthe session budget binds either way.\n\nAn application that splits the loop across processes has its own seam,\n`exmergo_dex_core.host`: a stored plan exports as a document a second process can\nverify and apply with no plan store and no network, that plan's dependencies and\nits edits' contents come back as typed evidence, and a build reports what it\nactually established rather than only whether dbt exited zero. Conformance\nvectors ship in the wheel so a consumer can prove its own reader against the\nengine's. See [`references/host-integration.md`](references/host-integration.md).\n\nMore info in the package's [`README.md`](packages/dex-core/README.md)\n\n## Agent References\n\n- Cross-agent contract: [`AGENTS.md`](AGENTS.md).\n- References: [`references/`](references/), covering the per-connector notes, the\n  command contract, the source of truth and the `.dex/` cache, the semantic layer\n  and Ossie compatibility, the project, storage and host-integration seams,\n  methodology, and evaluation.\n- The two guardrails that cut across all of it:\n  [`references/pii-policy.md`](references/pii-policy.md) and\n  [`references/cost-controls.md`](references/cost-controls.md).\n\n## Dex Enterprise\n\nDex Enterprise runs `dex` as automated workflows in your own CI. It turns tickets\ninto draft pull requests using `explore` and `transform`, and runs `maintain` on a\nschedule to turn detected drift into draft pull requests. Your engineers review\neach one. The workflows run in your repository's CI under your team's access\ncontrols, and no Exmergo service sits in the request path.\n\nEverything in this repository stays Apache-2.0. Dex Enterprise is built on the\npublished `exmergo-dex-core` package and these skills.\n\n[Learn more about Dex Enterprise](https://www.exmergo.com/dex/enterprise).\n\n## Contributing\n\nSee [`CONTRIBUTING.md`](CONTRIBUTING.md) for local setup, the Ruff lint and\nformat workflow, and the pre-commit hook. Every pull request into `main` must\npass the Lint workflow and CI before it can merge.\n\n## Community\n\n### Community Integrations\n\n#### **[dagster-dex](https://github.com/catincloud-labs/dagster-dex)**\nA rigorously-tested project format that allows `dex` to read a Dagster asset graph, maintained by CatInCloud Labs.  \nInstead of requiring a dbt project, `dagster-dex` maps your Dagster definitions directly into `dex`, allowing you to \nrun schema-drift maintenance and exploration natively against your orchestrated assets. `maintain verify` uses those\ndefinitions for relation-existence and grain checks and reports the dbt artifact-dependent checks as suppressed.\n\n### Connect with the Community\n\nConnect with the Analytics Engineering Community (Data Engineers welcome as well!) \nand discover how Exmergo brings AI Agents to Your Data Stack.\n\n- 🌟 [Star Us on GitHub](https://github.com/exmergo/dex/)\n- 👾 [Join Our Discord Community](https://www.exmergo.com/discord)\n- 🔗 [Follow Us on LinkedIn](https://www.linkedin.com/company/exmergo/)\n- 🐦 [Follow Us on X](https://x.com/exmergo)\n- 🔨 [Follow Us on GitHub](https://github.com/exmergo/)\n\n## License\n\nApache-2.0.\n"}