bigquery-sql
BigQuery-specific SQL patterns: UNNEST for array expansion, STRUCT, ARRAY_AGG,…
Load when task involves dbt snapshots, SCD Type 2, or tracking data changes over time. Covers strategy selection, column casing, verification, and common pitfalls.
$ npx -y skills add signalpilot-labs/signalpilot --skill dbt-snapshots --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/dbt-snapshotsContext preview
The summary Claude sees to decide when to auto-load this skill.
Load when task involves dbt snapshots, SCD Type 2, or tracking data changes over time. Covers strategy selection, column casing, verification, and common pitfalls.
name: dbt-snapshots description: "Load when task involves dbt snapshots, SCD Type 2, or tracking data changes over time. Covers strategy selection, column casing, verification, and common pitfalls." disable-model-invocation: false allowed-tools: Bash(dbt *)
Place snapshot files in `snapshots/`, NOT `models/`. Verify `snapshot-paths: ["snapshots"]` exists in `dbt_project.yml`.
**Choose the strategy BEFORE writing the snapshot file.**
Query the candidate timestamp column first:
SELECT COUNT(DISTINCT updated_at), MIN(updated_at), MAX(updated_at) FROM my_source_table
| Condition | Strategy | |-----------|----------| | `updated_at` has changing, meaningful values | `strategy='timestamp'`, `updated_at='UPDATED_AT'` | | `updated_at` frozen at a single constant value (COUNT(DISTINCT)=1) | `strategy='check'`, `check_cols='all'` - a column stuck at one value will never detect changes | | No `updated_at` column at all | `strategy='check'`, `check_cols='all'` |
Default to `strategy='check'` with `check_cols='all'` when uncertain - it always works.
Do NOT rationalize a frozen timestamp as valid business data. `1980-01-01` on every row is a data quality artifact, not a real date.
Snapshot `unique_key`, `updated_at`, and `check_cols` must match the EXACT case of the source columns.
Query column names before writing the config:
DESCRIBE my_source_table
Wrong: `unique_key='id'` when the source column is `ID`. Right: `unique_key='ID'`.
DuckDB and Snowflake snapshot configs are case-sensitive. A casing mismatch silently produces zero change detection.
SELECT explicit columns - not `SELECT *`. Include only business columns. Use raw source column names - do NOT alias them (e.g., `SELECT ID`, not `SELECT ID AS HOST_ID`). The snapshot output columns must match the source for `unique_key` and `check_cols` to work.
{% snapshot snap__employees %}
{{
config(
target_schema='main',
unique_key='EMPLOYEE_ID',
strategy='check',
check_cols='all'
)
}}
SELECT EMPLOYEE_ID, DEPARTMENT, TITLE, SALARY
FROM {{ source('hr', 'employees') }}
{% endsnapshot %}Set `target_schema` to the project's default schema (`'main'` for DuckDB).
Query actual column values before writing predicates:
SELECT DISTINCT IS_ACTIVE FROM my_source_table LIMIT 10
Getting this wrong silently filters to zero rows.
Run `dbt snapshot` - not `dbt run`. `dbt run` ignores snapshot files.
If the task involves tracking changes over time, run `dbt snapshot` once per mutation phase. A single run captures only the initial state.
After `dbt snapshot`, verify history was captured:
SELECT COUNT(*) AS total, COUNT(DISTINCT EMPLOYEE_ID) AS distinct_keys FROM main.snap__employees
Also verify SCD2 columns exist: `dbt_valid_from`, `dbt_valid_to`, `dbt_scd_id`, `dbt_updated_at`.
Reference snapshots like any model: `{{ ref('snap__employees') }}`.
Repo: signalpilot-labs/signalpilot
BigQuery-specific SQL patterns: UNNEST for array expansion, STRUCT, ARRAY_AGG,…
Load when dbt run or dbt parse fails. Covers YML duplicate patches, ref errors, passthrough…
Populate the knowledge base from dbt project research. Proposes entries across all 6…
Load when task involves adding, writing, or fixing dbt unit tests. Covers unit_tests YAML…
Load when task involves dbt model versioning, creating v2 of a model, or backward-compatible…
Load at Step 1 before exploring the project. Covers output shape inference, incremental model…