CLI REFERENCE

dvt run

Extract sources, transform models, load to targets.

dvt run                          # Run all models (incremental)
dvt run --full-refresh           # Rebuild everything from scratch
dvt run --select model_name      # Run specific model
dvt run --select tag:finance     # Run models with tag
dvt run --target prod            # Run against production target

dvt build

Seeds + models + snapshots + tests in DAG order.

dvt build                        # Full build
dvt build --full-refresh         # Clean rebuild
dvt build --select +model_name+  # Model with upstream/downstream

dvt seed

Bulk-load seed files via Sling (10-100x faster than dbt). Reads every Sling-supported format — CSV, TSV, Parquet, JSON/JSONL, Avro, Arrow, XLSX — and --target lands them on ANY output in profiles.yml: databases get tables, bucket outputs (S3/GCS/Azure) get Parquet objects. Column names are normalized to snake_case by default ('SKU Code' → sku_code) — the one casing every engine accepts — so reference seed columns in snake_case in your models, or override with --column-casing {source,snake,upper,lower}.

dvt seed                         # Load all seeds (any format)
dvt seed --select seed_name      # Load specific seed
dvt seed --full-refresh          # Drop and recreate tables
dvt seed --target snowflake_prod # Seed a different engine
dvt seed --target data_lake      # Seed a bucket (lands as Parquet)

dvt test

Run data tests on target.

dvt test                         # All tests
dvt test --select model_name     # Tests for specific model

dvt show

Preview a model or inline query against the default target (dbt passthrough — the query executes on the engine, not locally).

dvt show --select model_name     # Preview model output
dvt show --inline "SELECT 1"     # Ad-hoc query
dvt show --limit 100             # Limit rows

dvt sync

Self-healing environment bootstrap. Installs drivers, DuckDB extensions, Sling — and manages adapter environments: the default target's dbt adapter lives in your environment; every other adapter gets its own isolated environment under .dvt/ (its own dbt-core, zero version conflicts). Switch the default target and sync reshuffles everything automatically. Requires uv — and installs it for you if missing, so you never have to think about it.

dvt sync                         # Bootstrap + reconcile everything

dvt debug

Test connections on both layers: the dbt adapter and Sling.

dvt debug                        # Test the default target
dvt debug --target snowflake_dev # Test a specific target
dvt debug --all                  # Full matrix: every output, both layers

dvt init

Scaffold a DVT project that builds in seconds — no warehouse, no prompts. Bare dvt init turns the CURRENT folder into the project, named after the folder; dvt init <name> creates the folder first. Either way you get a DuckDB default target out of the box: an entry under the project name is merged into dbt's own profiles.yml (~/.dbt, $DBT_PROFILES_DIR honored — never clobbered, timestamped .bak), pointing at a visible <name>.duckdb file at the project root. A starter seed, model, and doctrine-ready sources.yml mean dvt build is green immediately — and because DuckDB is the default, everything you write is one dialect, federated models included. When you outgrow the laptop, dvt flip-target-to migrates you.

dvt init                         # this folder becomes the project
dvt init sales_dwh               # create sales_dwh/ and scaffold it
cd sales_dwh && dvt build        # green in seconds, no warehouse

dvt flip-target-to

Change the default target without abandoning your models. Runs config-checkup FIRST (scope decisions are only as good as the configs), then makes <target> the new default and transpiles every default-target model to the new engine's dialect — deterministically, via the same SQLGlot machinery federation trusts on every run, no AI tokens spent. Jinja survives byte-for-byte; federated models (always DuckDB by doctrine) and target-pinned models are never touched. Anything the deterministic pass refuses gets ONE AI rescue attempt through your gateway (validated before it touches disk), or an interactive prompt: open it in your editor, or skip. The default target only flips when every model made it — the run ends by asking, not by demanding --force. --silent restores the plain ledger (automatic off-TTY). Also Martin's /flip-target-to: pick a target, read the dry-run card, APPLY.

dvt flip-target-to databricks_prod --dry-run   # the ledger, nothing written
dvt flip-target-to databricks_prod             # checkup → flip → aftercare
dvt flip-target-to pg_dev -s 'staging/*'       # scope with patterns
dvt flip-target-to pg_dev --no-ai --silent     # deterministic, no prompts

dvt config-checkup

Make model configs tell the truth — zero AI. Applies the engine's own federation classification (foreign sources + the ref cascade) to your FILES: a standard materialization whose dependencies are federated in fact becomes f_table/f_incremental automatically (the engine was already coercing it at runtime — now the config says so), materialization typos snap to their one legal neighbour, and everything ambiguous becomes an interactive CHOICE — target= on a standard model offers federate-or-drop, a source missing meta.connection offers your profile's actual connections, needless federation offers convert-in-place (SQL transpiled to the default's dialect) or keep. Enter always means skip; every write keeps a .bak; --silent (or any non-TTY run) gives the plain report. flip-target-to runs this automatically. Also /config-checkup in Chat with Martin — each suggestion is a card with one button per resolution.

dvt config-checkup --dry-run     # the ledger, nothing written
dvt config-checkup               # fix the provable, ask about the rest
dvt config-checkup --silent      # no prompts (cron/CI behavior)
dvt config-checkup -s 'silver_*' # scope with patterns

dvt clean-bak-files

When you trust the fixes and the flips: remove the timestamped .bak files DVT's fixers left in your model folders (config-checkup, flip-target-to, applied Martin proposals). Only DVT's own <name>.YYYYmmdd-HHMMSS.bak pattern is touched — a hand-made .bak survives. Also /clean-bak-files in Chat with Martin, behind APPLY.

dvt clean-bak-files --dry-run    # list what would go
dvt clean-bak-files              # remove them

dvt docs

Generate and serve the data catalog with cross-engine metadata.

dvt docs generate                # Generate catalog
dvt docs serve                   # Serve UI on localhost
dvt docs serve --port 9090       # Custom port

dvt martin

Martin in your terminal — the same agent as Chat with Martin (:46104), because it is the same agent: tools, streaming MARTIN'S WORK, plan/execute modes, and every proposal gated behind an [a]pply / [d]ismiss prompt through the same file jail and verb whitelist. /model picks from your gateway's live catalog; /sql runs the guarded no-AI lane; @file mentions are read by Martin's own project-jailed reader.

dvt martin                       # the agent, in this terminal
dvt martin --plan                # start in plan mode
dvt martin --model claude-sonnet-5   # pin a gateway model

dvt generate-sources

The project kick-start, straight from the terminal — no UI, no AI tokens. Databases are introspected live (engine-correct metadata query per adapter) and every schema and table lands in <model-root>/<connection>_sources.yml, meta.connection on each source. Bucket connections (S3/MinIO, GCS, Azure, SFTP, local files) are first-class too: their objects are listed recursively and every data file — CSV, Parquet, JSON/JSONL, XLSX, Avro, compressed variants — becomes a source table named by its object path, exactly the shape federation streams. -s/--select and -x/--exclude narrow by schema.table patterns on databases and by object path on buckets; --print previews; --all sweeps the whole profile, buckets included. Timestamped .bak when the file exists. The same paths power Martin's /generate-sources.

dvt generate-sources pg_prod             # every schema and table
dvt generate-sources s3_lake             # every data file in the bucket
dvt generate-sources --all               # the whole profile, one yml each
dvt generate-sources sf_dev -s sales '*.orders' -x '*.tmp_*'
dvt generate-sources s3_lake -s 'raw/*.parquet'
dvt generate-sources                     # list connections

dvt serve

Start the whole DVT app suite on DVT's own port range: the hub (46100 — license, links, running apps), the data catalog (46101), the api-portal (46102), Chat with Martin (46104), Data Profiling (46105), the scheduler (46106) and Dashboards (46108). Each app runs detached and registers itself; dvt kill is the off switch. All apps bind to localhost unless --host says otherwise.

dvt serve                        # the whole suite, hub opens
dvt serve -s api-portal          # just one app (mirror of dvt kill -s)
dvt serve --no-browser           # start without opening the hub
dvt api-portal                   # just the portal (46102)
dvt hub                          # just the hub (46100)
dvt chat                         # just Chat with Martin (46104)
dvt profiling                    # just Data Profiling (46105)
dvt scheduler                    # just the scheduler (46106)
dvt dashboards                   # just Dashboards (46108)

dvt dashboards

The saved answers, on a wall (:46108). Every asset saved in Chat with Martin appears as a card; RERUN LIVE executes its SQL through the same guarded virtualization path the chat uses and renders the saved chart or a table — never a stale number. Deliberately basic v1: assets are born in the chat, they live here. Rerun and remove answer loopback-only.

dvt dashboards                   # dashboards on :46108
dvt kill -s dashboards           # stop just this app

dvt api-portal

Denodo-style REST exposure over your models. A themed portal lists every model with an exposure switch and per-column access control; enabled models serve GET /api/v1/models/<name> with equality filters and limit/offset pagination — live-executed against the model's sources through the federation engine on every call, so responses reflect the sources right now, not the last materialization. Optional bearer API key (generated in the portal, stored hashed).

dvt api-portal                   # portal + REST API on :46102
curl localhost:46102/api/v1/models
curl 'localhost:46102/api/v1/models/orders?limit=5&region=EMEA'

dvt kill

The emergency brake. Stops every hosted DVT app (hub, catalog, api-portal, scheduler), reaps SUSPENDED dvt processes (a Ctrl-Z'd run stays frozen holding the federation cache lock — dvt kill frees it), and lists running dvt work; --force terminates that too. -s takes down exactly one app; --exclude takes down everything BUT one. When things feel stuck, this is the one thing to type.

dvt kill                         # all apps down + suspended runs reaped
dvt kill -s api-portal           # stop only the api-portal
dvt kill --exclude scheduler     # everything down EXCEPT the scheduler (jobs keep firing)
dvt kill --force                 # also terminate RUNNING dvt work

dvt retract

The mirror image of dvt build: removes everything the project materialized — models, seeds, snapshots, and stored test failures (store_failures audit tables) — in REVERSE dependency order, across every engine involved. Database relations are dropped (dialect-correct, cascade where the engine needs it); object-store outputs are deleted (the model.parquet/csv the loader wrote, on S3/GCS/Azure/local files); each retracted model's local incremental bookkeeping is cleared too, so its next run behaves like a first run. Sources are never touched. Asks for confirmation unless --yes.

dvt retract                      # remove the whole DAG (confirm first)
dvt retract --select my_model    # remove specific models
dvt retract --target sf_dev      # resolve default-target models like dvt run --target
dvt retract --yes                # no prompt (CI / teardown scripts)

dvt clean

Remove project assets: dbt's target/ and dbt_packages/, plus tmp staging and all isolated adapter environments (dvt sync brings them back). Never touches data — the incremental cache belongs to dvt run/build --full-refresh.

dvt clean                        # Clean everything

PASSTHROUGH COMMANDS

These work identically to dbt:

  • dvt compileCompile models without executing
  • dvt parseParse project and build manifest
  • dvt list / dvt lsList resources
  • dvt snapshotRun snapshot models
  • dvt depsInstall dbt packages
  • dvt source freshnessCheck source freshness
  • dvt run-operationRun a macro