A curated collection of Agent Skills for working with dbt, to help AI agents understand and execute dbt workflows more effectively.
70
88%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Mechanics for running upgrading-dbt inside a Studio develop session. The
rules, the phase order, and when to do each of these live in SKILL.md; this file
only says how. If you have a shell, you want exec-local.md instead.
There is no shell. The skill's scripts/tools.py cannot run, and neither can
anything else you might be tempted to shell out to. Every step the script does
locally is done with a Studio tool below.
Three consequences worth stating plainly:
dbt_command accepts exactly two binaries: dbt and dbt-autofix. Nothing
else is on the allowlist — notably not dbt-migrate-1x (see autofix below),
which is why this migration's deterministic fixes are applied by hand here.edit_file. No script validates them,
so the schemas in SKILL.md are the contract — never invent a field, a status
value, or a phase id.write_file. edit_file creates the file when the path does
not exist, so it is also how you create an artifact for the first time.Never install anything, and treat environment_change issues as advisory edits
only — same rule as local, but here there is not even a mechanism to break it.
All migration state lives in a single file, target/dbt_migration.json:
{
"version": 1,
"updated_at": "2026-08-13T09:15:00+00:00",
"steps": [
{ "id": "preflight", "label": "Git preflight",
"status": "complete", "note": "On branch upgrade/dbt-1.12, clean tree" },
{ "id": "detect", "label": "Detection sweep",
"status": "in_progress", "note": "12 of 41 issues checked" }
],
"issues": {
"1_7_003": {
"automation_type": "agentic",
"out_of_repo_risk": false,
"environment_change": false,
"status": "fixed",
"files_changed": ["models/marts/customers.sql"],
"notes": "renamed + rewrote ref"
}
},
"outcome": {
"outcome": "completed_partial",
"reason": null,
"gate": { "parse": "passed", "compile": "passed", "test": "failed", "build": "not_run" },
"repair_attempts": 2,
"files_changed_count": 12,
"flags_pinned_count": 2,
"manual_actions_count": 3,
"jobs_to_flip_count": 1
}
}steps and issues carry exactly the records SKILL.md's Migration state
section defines — same phase ids, same status values, same fields. Only the
packaging differs: locally these are two script-written files, here they are two
keys in one file you write with edit_file.
outcome is absent until Step 7 exits. Write gate and repair_attempts then, and
the remaining fields in Step 9 (or just before stopping, if the run ends early). SKILL.md's Run outcome defines its fields
and values. The gate_result and outcome telemetry events are filled from it.
One file, because you are writing it by hand and nothing checks your work.
Two files can disagree — a phase marked complete while its issues still read
pending — and reconciling them costs edits you would rather spend on the
migration. This file is also what you read at the end to write the report, so
keeping it whole and current is what makes Step 9 possible.
Refresh updated_at on every write. Never rewrite the document wholesale from
memory: read it, change the one record you mean to change, write it back.
| Tool | Use |
|---|---|
load_skill_resource_file | Read this skill's own files — the issue bundle, this profile |
read_file, list_directory, find_files, grep | Read the project; run detection |
edit_file | Every file change, including creating the artifacts |
delete_file | Remove a file a fix retires |
git (status, branches, diff, checkout, commit, push, pull, revert, merge) | Preflight, diffs for approval, undo. No stash |
dbt_command, dbt_command_status, dbt_command_cancel | The whole verification gate — dbt parse → dbt compile → dbt test → dbt build. Not the deterministic 1.x → 1.x fixes — dbt-migrate-1x is not on this tool's allowlist; see autofix below |
request_user_input | Every question you put to the user |
get_job_details | Read one job by id — its execute_steps and pinned dbt_version. This is how you build migration_jobs.json (jobs-file) |
list_jobs | Discover this project's jobs, scoped by the project_id in your context. This is the first step of jobs-file |
record_migration_event | Optional telemetry. Only if present in your tool list; see Telemetry |
You do not trigger jobs. trigger_job_run is not part of this skill. A job
run executes on the deployment environment's own credentials and its own target
schema, which is very often production — the migration has no business writing
there, and a schema_override is a flag you can forget. Verification stays in
this session, on this session's development credentials. See
verify-commands.
$PROJECT = the project's root. $ADAPTER = the adapter type. $FROM = the
starting version. <id> = an issue_id from the bundle.
The adapter needs no lookup — it is already in your system prompt as
dialect.
status-initedit_file on target/dbt_migration.json, creating it with all ten phases
present and pending, in execution order, and an empty issues map. Use the
exact phase ids and status values from SKILL.md's Migration state section.
status-setedit_file the same file, changing that one phase's status and note, and
refreshing updated_at. Change one row at a time — do not rewrite the whole
document from memory, or you will drop state you have already recorded.
preflightgit status and git branches. If the session is on main/master or the tree
is dirty, request_user_input before going further. Create the migration branch
with git checkout and create_if_missing. If the run stops here, send
gave_up first: reason preflight_blocked if git stayed unsafe, user_aborted
if the user said not to continue.
Studio also refuses commits to protected branches, so this is guarded twice — but do the check anyway; the point is to tell the user before doing work, not to be caught later.
load-bundleload_skill_resource_file → references/kb_<FROM>_<ADAPTER>.jsone.g. references/kb_1_5_snowflake.json. Versions are dotless (1.5 → 1_5) and
the adapter is core when there is none.
This is the whole corpus for this migration — self-contained, with every issue's
action, automation_type, and context.detection / context.fixing. The
kb/ YAML corpus these are compiled from does not ship in the package; do
not try to read it.
init-resultsedit_file the same target/dbt_migration.json, filling its issues map
with one record per issue in the bundle at status: "pending", copying
automation_type, out_of_repo_risk and environment_change straight from the
bundle.
If records are already there, keep the statuses they carry — that is what makes a run resumable.
set-statusedit_file that same file, updating one issue's status, files_changed, and
notes under issues. One record at a time, for the same reason as
status-set.
list-issuesread_file on target/dbt_migration.json and filter the issues map yourself.
There is no query tool; the file is small enough to read whole.
autofixdbt-autofix migrate-1x is Not available here.
So there is no separate autofix pass in this profile. Treat every
detected issue with automation_type: deterministic exactly like an
agentic one in Step 5: apply the fix yourself per context.fixing, git diff to see what changed, then set-status fixed — never
handled-by-autofix, which claims a tool did it and nothing did here. Skip
Step 4 as its own pass (there is nothing for it to do); fold its issues into
Step 5's work instead, and status-set autofix = complete immediately
with a note saying why ("no dbt-migrate-1x tool in Studio; N deterministic issues folded into Step 5").
set-flagedit_file on dbt_project.yml, adding the flag named in that issue's
behavior_flag.name under flags: set to false.
Add the key if flags: already exists rather than replacing the block, and pin
only flags for behaviors detection actually found.
parsedbt_command with dbt parse. Poll with dbt_command_status. When the
5-attempt repair cap in SKILL.md Step 7 is reached, send gave_up (scope gate,
reason parse_cap_reached) before you revert anything.
This session already runs on the target release track. The platform sets your personal version override to the target, and Studio starts or restarts the development session before handing off to you. Assume the override is applied. You do not need to check the running version, and you must not try to change it.
What the gate is: the cheap check. Run it before verify-commands, because it
catches the small mistakes — a bad ref, malformed YAML, a config that moved — in
seconds instead of in a dbt build that spends warehouse compute to tell you the
same thing. It proves the project parses. It cannot prove behaviour; that is
verify-commands.
jobs-fileYou create this file here. No extension ran before you, so unlike the local profile there is nothing on disk to read — you discover the jobs yourself, then record your verdicts in it.
list_jobs for this project. project_id is in your context; the account is
supplied by the tool and is never yours to pass.get_job_details → its execute_steps.edit_file on migration_jobs.json at the project root (not under
target/), creating it with one entry per job and one step entry per command,
every step status: "pending" and updated: null.edit_file the same file as you work through the issues, setting each step
to ok / needs_change / manual.Set "source": "platform". Do not list an account's other projects, and never
edit or run a job.
If list_jobs or get_job_details fails, do not stop the migration. Write
the file with whatever jobs you could read (an empty jobs list if none), carry
on, and list "review job commands by hand: the job list could not be read" in the
report as a manual action.
The schema is fixed and shared with the VS Code extension, which writes the same file deterministically on the local path: see Job commands and match it exactly. Nothing validates it for you here, so that section is the contract — do not add fields, rename them, or invent status values.
Write it in Step 2, before detection, not when the first job-command issue turns up. Later steps record verdicts against it, so it has to exist whether or not any out-of-repo issue was found.
This file is for tracking and reporting only. verify-commands does not read
it — that gate runs a fixed set of commands, listed below. What this file is for
is telling the customer which of their job commands they have to change after
merging. Nothing in this skill edits a job, and nothing in this skill runs one.
revertgit revert with a files list. That undoes those uncommitted changes, which
is what git restore does locally. There is no stash.
reportread_file on target/dbt_migration.json and edit_file to write
migration_report.md from its issues map, grouped by outcome, then show it in
chat. Locally a script renders this; here you render it yourself, which is the
reason the state file has to have been kept accurate all the way through. Then
write the state file's outcome object and send the outcome event, both before
status-set → report = complete.
Cover what changed, which behavior flags were pinned and why, anything left
manual-required or failed, and — for this environment specifically — every
environment and job the user still has to flip, listed together. A partial flip
leaves the project split across release tracks.
For job commands, give the count and link migration_jobs.json rather than
restating them; that file is the actionable list and a prose copy will drift from
it. Flipping a job's version and fixing its commands are two different jobs of
work — say both.
askrequest_user_input. Always status-set the current phase to waiting_input
before asking, with a note saying what you asked, and set it back to
in_progress the moment they answer.
verify-commands — the command checksPlatform only. These are the checks above parse in SKILL.md's Step 7. dbt parse
cannot catch behavior-only changes — connector swaps, quoting, timeout defaults, a
changed materialization default — and those are exactly what breaks after a
version bump. Commands that compile and build can.
Same tool as the parse check: dbt_command, polled with dbt_command_status.
The commands are fixed. Run these four, in this order:
dbt parse — check 1, already run. Do not repeat it here.dbt compiledbt testdbt buildStop at the first red. Do not substitute, add or reorder them, and do not take
commands from migration_jobs.json.
dbt deps first if the project needs its packages. That is setup, not
verification, and it is the one extra command you may run.
Never pass --target, --profile, or --profiles-dir. The session already runs on the signed-in user's own development
credential and schema, which is where these commands are meant to build.
The loop. ask for approval once, up front, saying that dbt build will
materialize the project into the development schema. Then for each command in
order:
dbt_command with the command, no extra selectors.dbt_command_status. Green → next command.gave_up (scope gate, reason
warehouse_error).When all four are green, go on to Step 8. Whenever the gate exits, green or not,
send gate_result once.
Guardrails:
dbt_command is per-command anyway
and concurrent builds into one schema will collide.gave_up (scope gate, reason
command_cap_reached) before you stop.main/master — always the migration branch, same as everything
else in this skill.If you cannot run it — the user declines, the session has no warehouse
connection, the project's schema generation is not safe to build into — that is a
normal outcome. Report verification as incomplete, retain any parse result, and
make sure the report names every command left unverified so the user knows
exactly what was and was not proven. Send gave_up (scope gate) first, with
reason no_warehouse_connection when there is no connection and
verification_declined otherwise. Those unrun commands are declined in
gate_result.
record_migration_event is a server tool. It records how the run went so the dbt
platform can measure migrations. Call it only if it is in your tool list. It
is telemetry only:
Every call passes kind plus that kind's fields:
kind | When | Fields |
|---|---|---|
gave_up | Before you stop retrying, or stop the run, on every stop path | scope ∈ gate · run, reason, last_command ∈ deps · parse · compile · test · build · none, attempts_used, error_category, unresolved_issue_ids |
gate_result | Exactly once, when Step 7 exits (pass or not), after writing gate and repair_attempts to the state file's outcome | final (that outcome.gate) and repair_attempts |
outcome | Exactly once, at the end of Step 9, or just before stopping if the run ends early | The state file's outcome object, minus gate and repair_attempts |
error_category ∈ syntax · deprecated_config · macro · adapter ·
warehouse_auth · warehouse_timeout · test_failure · other.
gave_up reason, one per stop path:
| Stop path | scope | reason | Final outcome |
|---|---|---|---|
| Git still unsafe after preflight | run | preflight_blocked | gave_up |
| User declines to continue, at any point | run | user_aborted | gave_up |
| Parse repair cap (5) reached | gate | parse_cap_reached | completed_partial, or failed if parse still fails after the revert |
| Command-loop cap (3) reached | gate | command_cap_reached | completed_partial |
| User declines the command checks, or the schema is not safe to build into | gate | verification_declined | completed_partial |
| Session has no warehouse connection | gate | no_warehouse_connection | completed_partial |
| Warehouse auth or timeout failure that no issue explains | gate | warehouse_error | completed_partial |
outcome values are defined in SKILL.md, Run outcome.
.changes
.claude
skills
auditing-skills
.claude-plugin
.cursor-plugin
.github
ISSUE_TEMPLATE
scripts
skills
dbt
.claude-plugin
.cursor-plugin
skills
adding-dbt-unit-test
references
answering-natural-language-questions-with-dbt
building-dbt-semantic-layer
configuring-dbt-mcp-server
fetching-dbt-docs
scripts
maintaining-dbt-documentation
querying-the-dbt-information-schema
references
running-dbt-commands
troubleshooting-dbt-job-errors
references
using-dbt-for-analytics-engineering
using-dbt-state
working-with-dbt-mesh
dbt-extras
.claude-plugin
skills
creating-mermaid-dbt-dag
dbt-migration
.claude-plugin
skills
migrating-dbt-core-to-v2
migrating-dbt-project-across-platforms
upgrading-dbt
references
scripts