A curated collection of Agent Skills for working with dbt, to help AI agents understand and execute dbt workflows more effectively.
65
82%
Does it follow best practices?
Impact
—
No eval scenarios have been run
Risky
Do not use without reviewing
Before writing dbt models, you must make a plan. Start with the desired output and work backwards to identify the necessary inputs.
Use this approach when:
Create a spreadsheet or markdown table with the ideal output you want to produce. Include:
Example: Daily inventory levels
In practice, use dbt_utils.generate_surrogate_key for the surrogate key
| inventory_level_id | date | product_id | product_name | quantity_on_hand | value_on_hand |
|---|---|---|---|---|---|
| 2024-01-01_SKU-001 | 2024-01-01 | SKU-001 | Widget A | 100 | 2500.00 |
| 2024-01-01_SKU-002 | 2024-01-01 | SKU-002 | Widget B | 50 | 1250.00 |
| 2024-01-02_SKU-001 | 2024-01-02 | SKU-001 | Widget A | 95 | 2375.00 |
Write pseudocode or actual SQL that would produce this table, even if you don't know what table you're selecting from yet:
select
{{ dbt_utils.generate_surrogate_key(['date', 'product_id']) }} as inventory_level_id,
date_trunc('day', ????) as date,
product_id,
sum(???) as quantity_on_hand -- Need running total, not daily sum
from ???
group by 1, 2Key insight: If you can't write the query logic, your output table structure needs refinement.
As you write the query, you'll discover what the upstream model needs to provide:
Questions to ask:
Example iteration: Realized we need a running total, not a daily sum. This means we need window functions over transaction history, not a simple GROUP BY.
Based on your query needs, mock each table you're selecting from:
Upstream model: product_transactions (one record per inventory transaction)
| transaction_id | transaction_date | product_id | transaction_type | quantity | unit_cost |
|---|---|---|---|---|---|
| 1 | 2024-01-01 | SKU-001 | purchase | 100 | 25.00 |
| 2 | 2024-01-01 | SKU-001 | sale | -5 | 25.00 |
| 3 | 2024-01-02 | SKU-001 | return | 3 | 25.00 |
| 4 | 2024-01-01 | SKU-002 | purchase | 50 | 25.00 |
Now write the query to produce your final output, selecting from the mocked upstream model:
with running_balance as (
select
transaction_date as date,
product_id,
transaction_type,
quantity,
unit_cost,
sum(quantity) over (
partition by product_id
order by transaction_date, transaction_id
rows between unbounded preceding and current row
) as quantity_on_hand
from product_transactions
),
end_of_day_balance as (
select
date,
product_id,
quantity_on_hand,
unit_cost,
row_number() over (partition by product_id, date order by transaction_id desc) as rn
from running_balance
)
select
date,
product_id,
'Widget ' || right(product_id, 1) as product_name, -- TODO: join to product dimension
quantity_on_hand,
quantity_on_hand * unit_cost as value_on_hand
from end_of_day_balance
where rn = 1This reveals we need:
product_transactions tableNow that you know what inputs you need, look at the actual resources available in your dbt project:
In order of preference, the possible outcomes are:
| Priority | Scenario | Behaviour |
|---|---|---|
| 1 | Exact match exists | Use it directly |
| 2 | Partial match exists | Extend it, plan changes recursively if needed |
| 3 | No match | Create a new model, recursively repeating the planning process |
Don't wait to test edge cases:
Add unit tests for the planned models with mocked inputs from your identified dependencies. These tests should fail until the model has been correctly implemented.
Once you've worked backwards to existing models or source data, you can now implement with real code. Reuse existing models wherever possible.
Run the unit tests to ensure that the model matches the requirements.
When building incrementally, use placeholders to define the interface:
select
transaction_date,
product_id,
quantity,
null::integer as quantity_on_hand -- TODO: implement cumulative sum window function
from {{ ref('stg_inventory_transactions') }}Create a markdown file alongside your models:
## Goal
Calculate daily inventory levels per product
## Final output grain
One row per product per day
## Intermediate model grain
One row per transaction with running balance
## Required transformations
1. Combine purchase, sale, and return transaction types
2. Add window function for cumulative quantity on hand
3. Filter to end-of-day balance per product
## Unit tests
- Running balance correctly accumulates across multiple transactions for same product
- End-of-day quantity reflects the last transaction when multiple occur on the same day
- Value on hand equals quantity on hand multiplied by unit costStarting to code before understanding the output. Leads to multiple refactors and unclear model purposes
Not iterating on the mockup. If you can't write the SQL, revise your output structure
Forgetting about data quality. Consider null handling, duplicates, and edge cases in your planning
evals
skills
adding-dbt-unit-test
references
answering-natural-language-questions-with-dbt
building-dbt-semantic-layer
configuring-dbt-mcp-server
fetching-dbt-docs
scripts
migrating-dbt-core-to-fusion
running-dbt-commands
troubleshooting-dbt-job-errors
using-dbt-for-analytics-engineering