Interface for defining, testing, and applying data models and pipelines using SQLMesh.
Install
mkdir -p .claude/skills/sqlmesh && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/9544" && unzip -o skill.zip -d .claude/skills/sqlmesh && rm skill.zipInstalls to .claude/skills/sqlmesh
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Use when working with SQLMesh — writing or editing MODEL blocks, Python @model decorators, Python @macros, audits, unit tests, external_models.yaml, or seeds; running `sqlmesh plan/apply/audit/render/evaluate/test`; debugging plans, snapshots, virtual environments, or state issues; configuring `config.py`, gateways, or `before_all`/`after_all` hooks; choosing a model kind (FULL, INCREMENTAL_BY_TIME_RANGE, INCREMENTAL_BY_UNIQUE_KEY, VIEW, SEED, EMBEDDED, SCD_TYPE_2, EXTERNAL, MANAGED); migrating a project from dbt; or asking whether SQLMesh is still maintained. Trigger on these terms even when the user does not name the tool. SQLMesh changes quickly and the model's prior knowledge is often wrong — fetch the canonical docs at https://sqlmesh.readthedocs.io/en/stable/ before answering anything non-trivial.Key capabilities
- →Write models and macros
- →Run sqlmesh plans
- →Execute audits
- →Test data pipelines
How it works
Uses SQLMesh to manage data transformations, snapshots, and virtual environments.
Inputs & outputs
When to use sqlmesh
- →Defining data models
- →Running sqlmesh plans
- →Testing data pipeline logic
- →Migrating from dbt
About this skill
SQLMesh
Open-source data-transformation framework. Apache 2.0 license; governed by
the Linux Foundation since 2026-03-25 (see LF announcement).
Active development continues. Verify the installed version with pip show sqlmesh and check GitHub releases
for the changelog.
This skill is OSS-only. Anything labeled "Tobiko Cloud" is out of scope. Examples assume DuckDB as the warehouse engine; other engines work the same way at the model level — the engine integration index covers the small differences.
When to use this skill
Activate as soon as any of these come up:
- A
MODEL (...)block,@modeldecorator,@macro,audit, orexternal_models.yamlis being read or edited. - The user runs (or asks about)
sqlmesh plan,apply,run,audit,render,evaluate,test,table_diff,lineage, ormigrate. - Anything about virtual environments, snapshots, fingerprints, state, or
promoting
dev→prod. - Choosing or switching a model kind.
- Configuring
config.py, gateways,before_all/after_all, vars, signals. - Migrating a dbt project.
- Doubt about whether the project is still alive.
Always start here
SQLMesh ships fast. The model's training cutoff is usually behind a stable release or two, and behavior around plans, state, and incremental kinds has changed several times. Before answering anything more than trivia:
- WebFetch the relevant page from
https://sqlmesh.readthedocs.io/en/stable/. The full URL map is inreferences/links.md. - If the user reports an error, search GitHub issues before guessing.
- Trust the live docs over your prior knowledge when they conflict.
Skip the fetch only for stable basics already covered in this file.
Mental model — this is not dbt
Five concepts carry most of SQLMesh's behavior. Internalize them before answering design questions.
Snapshots and fingerprints. Every model version is a snapshot identified
by a fingerprint over its rendered SQL plus its kind and properties. Two
models with the same fingerprint share the same physical table. Renaming a
column, changing a WHERE clause, or editing a macro a model uses changes
the fingerprint. See snapshots.
Virtual data environments. dev, prod, and any feature-branch
environment are views over the snapshot store. Promoting dev to prod
swaps view targets — it does not rebuild data. See
environments.
Plans. A plan is the diff between code and what is already materialized, classified as breaking (downstream models must rebuild), non-breaking (only the changed model rebuilds), or forward-only (no backfill; new data only). The plan output lists each affected snapshot and asks for confirmation before mutating state. See plans.
State. SQLMesh stores snapshot and environment metadata in a separate state backend (default: a file alongside the warehouse, or a Postgres database you point it at). State is the source of truth — losing it loses all snapshot history. See state. For production with DuckDB warehouses, put state in Postgres rather than in the warehouse file (DuckDB is single-writer).
Macros run at parse time. Python @macro functions and built-ins like
@EACH, @IF, @VAR rewrite the SQL AST before plan time. They have
SQLGlot semantics — they manipulate columns and tables, not text. Jinja
macros also exist but are pure string substitution and have several known
footguns (see references/gotchas.md).
Canonical workflow
sqlmesh info # sanity-check config and connections
sqlmesh plan dev --auto-apply # diff, build, materialize into dev env
sqlmesh audit dev # run audits against the dev env
sqlmesh test # run YAML unit tests
sqlmesh plan # promote dev → prod (no env arg = prod)
plan dev shows a categorized summary of changes (added / modified /
removed; breaking / non-breaking / forward-only) and a backfill window. With
--auto-apply the user accepts the plan inline; without it they review
interactively.
plan (no environment) targets prod. By default it is virtual-only —
it re-points prod views at snapshots already built in dev, so promotion
is fast and reversible. New physical builds happen only if prod sees a
snapshot it has never materialized.
To re-materialize data without a code change, use
sqlmesh plan dev --restate-model <name>. See
plans.
Model authoring
A model is a MODEL (...) block followed by exactly one query. Minimal
DuckDB example:
MODEL (
name analytics.daily_orders,
kind INCREMENTAL_BY_TIME_RANGE (
time_column order_date
),
cron '@daily',
grain (order_date, order_id),
audits (
not_null(columns := (order_id, order_date)),
unique_values(columns := (order_id))
)
);
SELECT
order_id,
order_date,
customer_id,
amount
FROM raw.orders
WHERE order_date BETWEEN @start_date AND @end_date;
@start_date and @end_date are macro variables SQLMesh injects per
interval for incremental kinds. For TIMESTAMP time columns, use the
@start_ts / @end_ts pair instead. See
macro variables.
Properties worth knowing: name, kind, cron, owner, grain,
audits, columns, tags, depends_on, description. Full reference:
model_configuration.
Picking a kind. Quick guide:
FULL— small lookup tables; rebuilt every run.INCREMENTAL_BY_TIME_RANGE— append-mostly fact tables with a clear time column.INCREMENTAL_BY_UNIQUE_KEY— upserts keyed by a unique column (CDC-shaped).VIEW— pure SQL view, no materialization.SEED— static CSV underseeds/.SCD_TYPE_2— slowly-changing dimensions with valid-from / valid-to.EXTERNAL— data SQLMesh reads but does not own (declared inexternal_models.yaml).EMBEDDED— inlined into downstream models, not materialized.MANAGED— engine-managed (e.g. dynamic tables).CUSTOM— user-defined materialization strategy.
Full matrix with required props and DuckDB examples:
references/model-kinds.md. Canonical doc:
model kinds.
Python models. Use the @model decorator and return a pandas,
pyarrow, or ibis table from execute(context, ...). The
ExecutionContext exposes fetchdf(), resolve_table(), var(), and
engine_adapter. See python_models.
from sqlmesh import ExecutionContext, model
import pandas as pd
@model(
"analytics.summary",
columns={"day": "DATE", "n": "BIGINT"},
kind="FULL",
)
def execute(context: ExecutionContext, **kwargs) -> pd.DataFrame:
upstream = context.resolve_table("analytics.daily_orders")
return context.fetchdf(
f"SELECT order_date AS day, COUNT(*) AS n FROM {upstream} GROUP BY 1"
)
Macros
Prefer Python @macro for anything beyond trivial substitution. They
are parsed against SQLGlot, so they manipulate real SQL nodes and the plan
can reason about lineage.
# macros/_my_macros.py
from sqlmesh import macro
@macro()
def add_audit_columns(evaluator, table_alias):
return [f"{table_alias}.created_at", f"{table_alias}.updated_at"]
Used as @add_audit_columns('o') inside a model query.
Built-ins worth knowing:
@EACH(items, x -> expr)— generates a list of expressions.@IF(cond, then, else)— conditional SQL.@VAR('name', default)— read a config var.@SQL(template)— paste raw SQL safely.- Predicate macros (
@AND,@OR) and blueprinting for templated model families.
Reference: SQLMesh macros.
Avoid jinja macros. They predate the Python macro system and exist mostly for dbt-import compatibility. They are pure string substitution: no SQL awareness, brittle whitespace, no lineage. The only good reason to write one is if you're inside a dbt-imported project and need to keep parity.
Audits and tests
Audits are queries that must return zero rows. Attach inline:
MODEL (
name analytics.daily_orders,
audits (
not_null(columns := (order_id, order_date)),
unique_values(columns := (order_id)),
accepted_range(column := amount, min_v := 0)
)
);
40+ built-ins ship with SQLMesh: not_null, unique_values,
accepted_values, accepted_range, valid_email, valid_url,
forall, mutually_exclusive_ranges, etc. Full list:
audits.
Custom audits live in audits/<name>.sql:
AUDIT (
name only_recent_orders,
defaults (max_age_days = 30)
);
SELECT * FROM @this_model
WHERE order_date < CURRENT_DATE - INTERVAL @max_age_days DAY;
Audits are blocking by default — a failed audit aborts the run. Pass
blocking := false to demote to a warning.
Unit tests live in tests/<model>.yaml. They run a model against
fixed input rows and assert on output rows. Run with sqlmesh test. See
[t
Content truncated.
When not to use it
- →Using Tobiko Cloud features
- →Directly porting dbt incremental models
Prerequisites
Limitations
- →State backend requires Postgres for concurrency
- →Jinja macros have known footguns
How it compares
Uses a snapshot-based virtual environment approach rather than dbt's direct materialization.
Compared to similar skills
sqlmesh side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| sqlmesh (this skill) | 0 | 3mo | Review | Advanced |
| data-quality-frameworks | 0 | 3mo | No flags | Intermediate |
| soda-core | 0 | 2mo | Review | Intermediate |
| data-dbt-guide | 0 | 1mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
data-quality-frameworks
Anhvu1107
ALWAYS use this when the request matches Data Quality Frameworks: Implement data quality validation with Great Expectations, dbt tests, and data contracts.
soda-core
ivanshamaev
Soda Core data quality — SodaCL checks (row_count, missing, invalid, duplicate, freshness, schema, reference, custom SQL), configuration.yml for PostgreSQL/Spark/ClickHouse/BigQuery, soda scan CLI, Airflow integration, dbt integration, alerting
data-dbt-guide
khalilbenaz
Transformation de données avec dbt — models, tests, sources, macros et documentation automatisée. Se déclenche avec "dbt", "data build tool", "dbt model", "dbt test", "transformation de données dbt".
find-hypertable-candidates
timescale
Use this skill to analyze an existing PostgreSQL database and identify which tables should be converted to Timescale/TimescaleDB hypertables. **Trigger when user asks to:** - Analyze database tables for hypertable conversion potential - Identify time-series or event tables in an existing schema - Evaluate if a table would benefit from Timescale/TimescaleDB - Audit PostgreSQL tables for migration to Timescale/TimescaleDB/TigerData - Score or rank tables for hypertable candidacy **Keywords:** hypertable candidate, table analysis, migration assessment, Timescale, TimescaleDB, time-series detection, insert-heavy tables, event logs, audit tables Provides SQL queries to analyze table statistics, index patterns, and query patterns. Includes scoring criteria (8+ points = good candidate) and pattern recognition for IoT, events, transactions, and sequential data.
h3-pg
postgis
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
supabase
alinaqi
Core Supabase CLI, migrations, RLS, Edge Functions