Add dbt model
A Claude Code harness that turns a session into an agentic data engineer for SMBs — packaged as an installable plugin, built from a skillpack of skills that stand up a cheap, self-hostable Modern Data Stack (Tailscale + dlt + BigQuery + dbt + optional MCP), end-to-end and headless.
npx -y skills add pol-cc/agentic-data-engineer --skill add-dbt-modelAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Add a new dbt model (staging, intermediate, or marts) to an existing MDS deployment. Invoke when the user wants to transform raw data, build an analytics table, or expose a new metric in BigQuery.
SKILL.md
5.0 KB, as published. Nobody here has run it
add-dbt-model
Status: v0.10.0 (pre-test) — conventions + templates complete, with incremental-by-default for fact/event marts on BigQuery (cost control). Conventions and decision-tree references written; copy-paste templates (staging, marts dimension, marts incremental fact, schema, sources) included plus the
incremental-and-cost.mdreference; the Phase A–D playbook (classify → write → run/verify → commit) is in place.
What this skill does
Adds a new dbt model to the client's dbt project. Decides where the model belongs (staging / intermediate / marts) based on what the user describes, writes the SQL, adds tests, and runs it once to verify before committing.
Preflight
if [ ! -f .agentic-data-engineer.json ]; then
echo "[abort] not a managed MDS deployment"
exit 1
fi
# Confirm dbt is configured in this stack
jq -e '.stack.transform == "dbt_vps"' .agentic-data-engineer.json > /dev/null || {
echo "[abort] this MDS doesn't have dbt configured"
echo "Phase 2 of create-mds adds dbt — run that first"
exit 1
}
Playbook outline
Phase A — Classify the model
Ask the user what they want to compute. Then decide:
| Layer | When |
|---|---|
staging (stg_<source>_<table>) | One-to-one with a raw source table, applies cleanup (rename columns, cast types, filter junk rows). One staging model per raw table. |
intermediate (int_<concept>) | Reusable logic that several marts will consume (e.g. int_orders_with_customer). Not exposed to end users. |
marts (analytics-ready, plain names like orders, revenue_monthly) | The deliverable. End users and BI tools query these. |
See references/staging-vs-marts.md and references/dbt-naming-conventions.md.
Materialization is a cost decision on BigQuery (bills by bytes scanned). Default by layer: staging = view; dimensions / small reports = table; fact/event marts = incremental (partitioned + clustered, insert_overwrite). A full-refresh table on a growing fact re-scans all history every run — the surprise-bill risk this default prevents. See references/incremental-and-cost.md.
Phase B — Write the model
- SSH to the VPS, locate the dbt project.
- Create the SQL file in the right folder.
- Write the
SELECTwith explicit column lists (neverSELECT *in marts). - Add a
schema.ymlentry with tests (not_null,uniquewhere applicable,accepted_valuesfor known categories).
Phase C — Run and verify
dbt run --select <model>in the venv on the VPS.dbt test --select <model>.- Spot-check the resulting table in BigQuery (
bq queryorSELECT * LIMIT 10).
Phase D — Commit
- Push to the client repo.
- Update marker history.
References
Conventions (complete):
references/dbt-naming-conventions.md— file/model/column naming, SQL style, tests pattern, canonical model shapesreferences/staging-vs-marts.md— decision tree for which layer a model belongs inreferences/incremental-and-cost.md— BigQuery cost control: when to go incremental, partition/cluster choice,maximum_bytes_billed, the GCP budget alert backstop, and the light cross-db convention (prefer dbt macros, flatten structs early — noadapter.dispatchframework)
Templates (complete) — copy into the client's dbt project and fill the <PLACEHOLDER> markers:
templates/staging.sql.template— canonical staging model:viewmaterialization,source+renamedCTEs, explicit casts, ingest-tool-agnostic load metadata (dlt's_dlt_load_id→load_id, join_dlt_loadsfor the timestamp; Airbyte legacy_airbyte_extracted_at→loaded_at),where <pk> is not nulltemplates/marts.sql.template— DIMENSION / small-report mart:tablematerialization, one CTE perref()input, ajoinedCTE, explicit final select. Heavily commented on when to usetable(dim) vsincremental(fact)templates/marts_incremental.sql.template— FACT / event mart (BigQuery default):incremental+insert_overwrite+partition_by+cluster_by+on_schema_change, with theis_incremental()look-back guardtemplates/schema.yml.template— model docs + tests (not_null/uniquePK,not_nullFK,accepted_valuesenum, optional monetary check) plus optional incremental-fact guards (partitionnot_null, recency, row-count)templates/sources.yml.template— rawsources:declaration (database<project>, schemaraw_<source>, freshness warn 26h / error 50h,loaded_at_field)