/maintain
Use this to find out whether an existing dbt project or semantic layer (dbt, Ossie, SLayer or Cube) is correct against its warehouse, and if not, why. `maintain verify` checks the project as it stands; against a .dex/ snapshot, `maintain check` finds schema, volume, grain, and
Claude Code
$ npx -y skills add exmergo/dex --skill maintain --agent claude-code
Codex
$ npx skills add exmergo/dex --skill maintain -a codex -y
Cursor
$ npx skills add exmergo/dex --skill maintain -a cursor -y
Gemini CLI
$ npx skills add exmergo/dex --skill maintain -a gemini-cli -y
GitHub Copilot
$ npx skills add exmergo/dex --skill maintain -a github-copilot -y
OpenCode
$ npx skills add exmergo/dex --skill maintain -a opencode -y
Windsurf
$ npx skills add exmergo/dex --skill maintain -a windsurf -y
SKILL.md
maintain.SKILL.mdname: maintain
description: 'Use this to find out whether an existing dbt project or semantic layer (dbt, Ossie, SLayer or Cube) is correct against its warehouse, and if not, why. `maintain verify` checks the project as it stands; against a .dex/ snapshot, `maintain check` finds schema, volume, grain, and semantic drift and `maintain reconcile` proposes the fix. Reach for it whenever an existing project is suspected wrong, whether or not anything is known to have changed: "this model is wrong, work out why", "the numbers look too high", "some rows are missing", "this column is empty", "duplicates in my fact table", "the project is broken", "diagnose why this test fails", "a test fails and nobody changed the model", "the dashboard moved but the code did not", "did anything drift", "the row count dropped", "the metric definition changed". Read-only; fixes come back as reviewable diffs and never overwrite hand-written work. Writing the fix, or repairing a model you just edited, is transform''s; a data question with no project is explore''s.'
compatibility: 'Needs a local shell and uv. On first use, uv builds the exmergo-dex-core engine from the source bundled with the plugin, or installs it from PyPI at the version scripts/run.py pins when no source is bundled. Runs in Claude Code or another agent that loads Agent Skills and has a shell, not in claude.ai chat.'
Maintain
Keep the repository correct as the world underneath it moves, on both of its axes: the dbt project and the semantic layer. Drift is measured against a **baseline**, the `.dex/snapshot.json` fingerprint of the warehouse map and of each project layer. Detection is read-only; only `reconcile` proposes edits, and `transform apply` is the one door that writes them.
<!-- dex:procedure:begin -->
Procedure
Dex works in one loop: explore, transform, maintain. `dex <command>` below is the `dex` CLI; where it is not installed, run the same command through the skill's `scripts/run.py` wrapper. Each command prints one JSON envelope: read it and decide the next step from it. Step 1 only reads. Steps 2 to 5 change the project, so take them only when the task asks for a change; a question about the data stops after step 1 and reports what it found. Explore and maintain report findings and hand repair work to transform; only the transform workflow performs the project edits, migrations and dev builds described below.
1. **Profile what the change reads.** Before writing or fixing SQL against a table whose columns, types, grain or join keys you have not verified in this session, run `dex explore profile <tables>` on every relation the change reads (`dex explore map` when you do not yet know which), and `dex explore relationships --verify` for the joins it will make. Answer data questions with `dex explore query`, never with a raw database client. 2. **Plan with a declaration.** Hand the SQL to `dex transform plan "<intent>" --edits-file <file>` with a declaration for every model you create or change, beside the edits:
{"edits": [{"path": "models/marts/fct_orders.sql", "kind": "model_sql", "content": "..."}],
"declarations": [{"model": "fct_orders", "description": "One row per order.",
"grain": ["order_id"],
"population": {"rule": "Placed orders; cancelled ones are excluded.",
"filters": [{"column": "status", "excludes": ["cancelled"]}]},
"columns": {"order_id": {"role": "key"},
"amount": {"role": "measure", "aggregation": "sum",
"additivity": "additive", "unit": "currency:USD"}},
"assumptions": [{"decision": "Which statuses count", "chosen": "all but cancelled",
"evidence": "precedent", "detail": "every sibling excludes cancelled"}]}]}Use the conventional values, so tools can read them: `role` is `key`, `foreign_key`, `dimension`, `time`, `measure` or `attribute`; `additivity` is `additive`, `semi_additive` (a balance or a running total) or `non_additive` (a ratio, a share, a distinct count); `unit` is `currency:<ISO code>`, `fraction` (0 to 1), `percent` (0 to 100), `count` (any count of things), or a plain unit such as `days`; `aggregation` is how the column rolls up (a count rolls up with `sum`, a running total with `max`). A model that holds one row per entity of another model declares that parent too, `"population": {"parent": {"model": "stg_subscriptions", "key": {"subscription_id": "subscription_id"}}}`, so verification counts the parents missing from it. A model derived from a dbt snapshot's status history declares a `history` block (`skills/transform/references/declarations.md`): whether the first observation is a baseline or a transition, the NULL-status policy, the entities it holds, and whether its timestamp is business or capture time. A declaration is JSON in the payload, rendered into the model's YAML: it never adds, drops or renames an output column. 3. **Read the draft, supply the intent, plan again.** `data.declarations.<model>` holds `drafted` (what Dex measured: keys, running totals, units, value domains, and `precedent`, what sibling models do with the same columns), `missing` (the intent still owed) and `contradictions`. Read them with the `warnings` and, on an existing model, `data.row_attribution`. Correct the SQL or the declaration until both say what the request asks, then plan again. When the change should keep an existing model's results (a refactor, an extraction, a cleanup), run each `data.refactor_comparison_offer.per_model` command before applying, above all where `static_attribution` is not `attributed`. `equivalent` holds for its `input_scope` at `compared_at`: relay both. `different` is a defect to fix in the SQL, unless the request asked for that difference: state an intended rename with `--map` or type change with `--accept-type`, and never loose
Read more
name: maintain description: 'Use this to find out whether an existing dbt project or semantic layer (dbt, Ossie, SLayer or Cube) is correct against its warehouse, and if not, why. `maintain verify` checks the project as it stands; against a .dex/ snapshot, `maintain check` finds schema, volume, grain, and semantic drift and `maintain reconcile` proposes the fix. Reach for it whenever an existing project is suspected wrong, whether or not anything is known to have changed: "this model is wrong, work out why", "the numbers look too high", "some rows are missing", "this column is empty", "duplicates in my fact table", "the project is broken", "diagnose why this test fails", "a test fails and nobody changed the model", "the dashboard moved but the code did not", "did anything drift", "the row count dropped", "the metric definition changed". Read-only; fixes come back as reviewable diffs and never overwrite hand-written work. Writing the fix, or repairing a model you just edited, is transform''s; a data question with no project is explore''s.' compatibility: 'Needs a local shell and uv. On first use, uv builds the exmergo-dex-core engine from the source bundled with the plugin, or installs it from PyPI at the version scripts/run.py pins when no source is bundled. Runs in Claude Code or another agent that loads Agent Skills and has a shell, not in claude.ai chat.'
Maintain
Keep the repository correct as the world underneath it moves, on both of its axes: the dbt project and the semantic layer. Drift is measured against a **baseline**, the `.dex/snapshot.json` fingerprint of the warehouse map and of each project layer. Detection is read-only; only `reconcile` proposes edits, and `transform apply` is the one door that writes them.
<!-- dex:procedure:begin -->
Procedure
Dex works in one loop: explore, transform, maintain. `dex <command>` below is the `dex` CLI; where it is not installed, run the same command through the skill's `scripts/run.py` wrapper. Each command prints one JSON envelope: read it and decide the next step from it. Step 1 only reads. Steps 2 to 5 change the project, so take them only when the task asks for a change; a question about the data stops after step 1 and reports what it found. Explore and maintain report findings and hand repair work to transform; only the transform workflow performs the project edits, migrations and dev builds described below.
1. **Profile what the change reads.** Before writing or fixing SQL against a table whose columns, types, grain or join keys you have not verified in this session, run `dex explore profile <tables>` on every relation the change reads (`dex explore map` when you do not yet know which), and `dex explore relationships --verify` for the joins it will make. Answer data questions with `dex explore query`, never with a raw database client. 2. **Plan with a declaration.** Hand the SQL to `dex transform plan "<intent>" --edits-file <file>` with a declaration for every model you create or change, beside the edits:
{"edits": [{"path": "models/marts/fct_orders.sql", "kind": "model_sql", "content": "..."}],
"declarations": [{"model": "fct_orders", "description": "One row per order.",
"grain": ["order_id"],
"population": {"rule": "Placed orders; cancelled ones are excluded.",
"filters": [{"column": "status", "excludes": ["cancelled"]}]},
"columns": {"order_id": {"role": "key"},
"amount": {"role": "measure", "aggregation": "sum",
"additivity": "additive", "unit": "currency:USD"}},
"assumptions": [{"decision": "Which statuses count", "chosen": "all but cancelled",
"evidence": "precedent", "detail": "every sibling excludes cancelled"}]}]}Use the conventional values, so tools can read them: `role` is `key`, `foreign_key`, `dimension`, `time`, `measure` or `attribute`; `additivity` is `additive`, `semi_additive` (a balance or a running total) or `non_additive` (a ratio, a share, a distinct count); `unit` is `currency:<ISO code>`, `fraction` (0 to 1), `percent` (0 to 100), `count` (any count of things), or a plain unit such as `days`; `aggregation` is how the column rolls up (a count rolls up with `sum`, a running total with `max`). A model that holds one row per entity of another model declares that parent too, `"population": {"parent": {"model": "stg_subscriptions", "key": {"subscription_id": "subscription_id"}}}`, so verification counts the parents missing from it. A model derived from a dbt snapshot's status history declares a `history` block (`skills/transform/references/declarations.md`): whether the first observation is a baseline or a transition, the NULL-status policy, the entities it holds, and whether its timestamp is business or capture time. A declaration is JSON in the payload, rendered into the model's YAML: it never adds, drops or renames an output column. 3. **Read the draft, supply the intent, plan again.** `data.declarations.<model>` holds `drafted` (what Dex measured: keys, running totals, units, value domains, and `precedent`, what sibling models do with the same columns), `missing` (the intent still owed) and `contradictions`. Read them with the `warnings` and, on an existing model, `data.row_attribution`. Correct the SQL or the declaration until both say what the request asks, then plan again. When the change should keep an existing model's results (a refactor, an extraction, a cleanup), run each `data.refactor_comparison_offer.per_model` command before applying, above all where `static_attribution` is not `attributed`. `equivalent` holds for its `input_scope` at `compared_at`: relay both. `different` is a defect to fix in the SQL, unless the request asked for that difference: state an intended rename with `--map` or type change with `--accept-type`, and never loose
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
More skills from other plugins.
paddleocr-doc-parsing
Use this skill to extract structured Markdown/JSON from PDFs and document images—tables with cell-level precision, formulas as…
13c-metabolic-flux
Estimates intracellular metabolic fluxes from steady-state carbon-13 isotope-tracing measurements using validated atom maps,…
Questions about maintain.
- Which coding agents can use maintain?
- maintain installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

