soda-core
Automates data quality validation using Soda Core, supporting schema checks, freshness, and custom SQL metrics.
Install
mkdir -p .claude/skills/soda-core && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/11282" && unzip -o skill.zip -d .claude/skills/soda-core && rm skill.zipInstalls to .claude/skills/soda-core
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.
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, alertingKey capabilities
- →Write SodaCL checks for data quality validation
- →Set up Soda Core configuration for various data sources
- →Run `soda scan` from CLI or within Airflow DAGs
- →Design data quality gate patterns
- →Integrate Soda with dbt
- →Write custom SQL metric checks
How it works
This skill configures Soda Core using `configuration.yml` for data source connections and defines data quality checks with SodaCL in `checks.yml`. It then runs `soda scan` to translate SodaCL into SQL and execute checks against the data source.
Inputs & outputs
When to use soda-core
- →Run data quality scans
- →Write SodaCL check for freshness
- →Implement data quality gates in pipeline
- →Validate schema and duplicates
About this skill
Soda Core Data Quality
When to Use
Activate this skill when the task involves:
- Writing SodaCL checks for data quality validation (nulls, ranges, freshness, schema, uniqueness)
- Setting up Soda Core configuration for PostgreSQL, Spark, ClickHouse, Trino, or BigQuery
- Running
soda scanfrom CLI or within Airflow DAGs - Designing a data quality gate pattern: scan → fail pipeline on violation
- Integrating Soda with dbt (supplementing or replacing dbt tests)
- Writing custom SQL metric checks
- Configuring warn vs. fail thresholds
Core Architecture
┌──────────────────────────────────────────────────────────────┐
│ │
│ checks.yml configuration.yml │
│ (SodaCL checks) (data source connection) │
│ ↓ ↓ │
│ ┌─────────────────────────────────┐ │
│ │ soda scan │ │
│ │ translates SodaCL → SQL │ │
│ │ runs against data source │ │
│ │ returns: pass / warn / fail / error │ │
│ └───────────────┬─────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────┐ │
│ │ Results │ │
│ │ • stdout + logs │ │
│ │ • Soda Cloud (optional SaaS) │ │
│ │ • Airflow task state │ │
│ └───────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
Installation
# Core + specific adapter
pip install soda-core-postgres # PostgreSQL
pip install soda-core-spark-df # Spark DataFrames
pip install soda-core-trino # Trino
pip install soda-core-bigquery # BigQuery
pip install soda-core-clickhouse # ClickHouse
pip install soda-core-duckdb # DuckDB (dev/testing)
pip install soda-core-sqlserver # SQL Server
Configuration File (configuration.yml)
PostgreSQL
# soda/configuration.yml
data_source postgres_prod:
type: postgres
host: ${POSTGRES_HOST}
port: "5432"
username: ${POSTGRES_USER}
password: ${POSTGRES_PASSWORD}
database: analytics
schema: silver
Spark (via DataFrame connector)
data_source spark_local:
type: spark_df
# SparkSession is passed programmatically — no host config here
Trino
data_source trino_prod:
type: trino
host: trino.internal
port: 8080
username: ${TRINO_USER}
auth:
type: kerberos
catalog: iceberg
schema: silver
http_scheme: https
ClickHouse
data_source clickhouse_prod:
type: clickhouse
host: clickhouse.internal
port: 8123
username: ${CH_USER}
password: ${CH_PASSWORD}
database: silver
BigQuery
data_source bigquery_prod:
type: bigquery
account_info_json: ${BIGQUERY_CREDENTIALS}
auth_scopes:
- https://www.googleapis.com/auth/bigquery
project_id: my-gcp-project
dataset: silver
Test connection:
soda test-connection -d postgres_prod -c soda/configuration.yml
SodaCL Check Syntax
File Structure
# soda/checks/silver_orders.yml
checks for orders: # "for <table_name>"
- row_count > 0
- missing_count(order_id) = 0
- duplicate_count(order_id) = 0
- missing_percent(customer_id) < 1%
Multiple tables in one file:
checks for orders:
- row_count > 0
checks for customers:
- missing_count(email) = 0
Row Count
checks for orders:
- row_count > 0 # at least 1 row
- row_count > 1000 # volume check
- row_count between 10000 and 10000000 # range
Missing Values
checks for orders:
- missing_count(order_id) = 0 # no nulls
- missing_count(customer_id) = 0
- missing_percent(discount) < 5% # allow up to 5% null discounts
- missing_count(notes): # custom missing definition
missing values: ["N/A", "n/a", ""]
fail: when > 0
Duplicate / Uniqueness
checks for orders:
- duplicate_count(order_id) = 0 # strict uniqueness
- duplicate_count(order_id, order_date) = 0 # composite key
Numeric Range / Statistics
checks for order_items:
- min(quantity) >= 1 # no zero or negative quantities
- max(price) <= 99999.99
- avg(discount_percent) between 0 and 50
- sum(total_amount) > 0
- stddev(price) < 1000 # sanity check on variance
- invalid_percent(price): # custom invalid definition
valid min: 0
valid max: 999999
fail: when > 1%
Invalid Values
checks for orders:
- invalid_count(status):
valid values: [pending, processing, shipped, delivered, cancelled]
fail: when > 0
- invalid_count(country_code):
valid format: ISO 3166 alpha-2 # built-in format validator
fail: when > 0
- invalid_count(email):
valid regex: ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
fail: when > 0
- invalid_percent(order_date):
valid min: 2020-01-01
valid max: today
fail: when > 0
Freshness
checks for orders:
- freshness(created_at) < 24h # most recent row is < 24h old
- freshness(created_at) < 1d # synonym
- freshness(updated_at) < 2h:
warn: when > 1h
fail: when > 2h
Schema
checks for orders:
- schema:
fail:
when required column missing:
- order_id
- customer_id
- total
- created_at
when wrong column type:
order_id: bigint
total: numeric
created_at: timestamp
when wrong index: # column order in result set
order_id: 0
warn:
when forbidden column present:
- password
- ssn
Referential Integrity
# Ensure every order has a valid customer
checks for orders:
- values in (customer_id) must exist in customers (customer_id)
Custom SQL Metric
checks for orders:
- order_date_after_ship_date = 0:
order_date_after_ship_date query: |
SELECT COUNT(*)
FROM orders
WHERE order_date > ship_date
- negative_total_count = 0:
negative_total_count query: |
SELECT COUNT(*)
FROM orders
WHERE total < 0
- distinct_statuses > 0:
distinct_statuses query: |
SELECT COUNT(DISTINCT status) FROM orders
Warn vs. Fail Thresholds
checks for orders:
- row_count:
warn: when < 5000 # warn only
fail: when < 1000 # fail the scan
- missing_percent(email):
warn: when between 1% and 5%
fail: when > 5%
- freshness(created_at):
warn: when > 1h
fail: when > 24h
Variables and Filters
filter orders [daily]:
where: created_at >= CURRENT_DATE - INTERVAL '1 day'
AND created_at < CURRENT_DATE
checks for orders [daily]:
- row_count > 500
- missing_count(order_id) = 0
Filters allow running the same checks on subsets (e.g., yesterday's partition).
Running Scans
# Basic scan
soda scan -d postgres_prod -c soda/configuration.yml soda/checks/
# Scan single checks file
soda scan -d postgres_prod -c soda/configuration.yml soda/checks/silver_orders.yml
# Scan with variable
soda scan -d postgres_prod -c soda/configuration.yml \
soda/checks/daily_orders.yml \
-V batch_date=2024-03-15
# Verbose output
soda scan -d postgres_prod -c soda/configuration.yml soda/checks/ -v
# Send results to Soda Cloud
soda scan -d postgres_prod -c soda/configuration.yml soda/checks/ \
--cloud-api-key-id $SODA_API_KEY_ID \
--cloud-api-key-secret $SODA_API_KEY_SECRET
Exit codes:
| Code | Meaning |
|---|---|
0 | All checks passed |
2 | One or more checks warned |
3 | One or more checks failed |
4 | Scan error (connection failure, SQL error) |
Python Programmatic API
import logging
from soda.scan import Scan
def run_soda_scan(
data_source_name: str,
table_name: str,
checks_yaml: str,
variables: dict | None = None,
) -> bool:
"""Run a Soda scan programmatically. Returns True if all checks passed."""
scan = Scan()
scan.set_verbose(True)
scan.set_scan_definition_name(f"soda_{table_name}")
scan.set_data_source_name(data_source_name)
scan.add_configuration_yaml_file("soda/configuration.yml")
scan.add_sodacl_yaml_str(checks_yaml)
if variables:
for key, value in variables.items():
scan.add_variables({key: value})
exit_code = scan.execute()
# Log all check results
for check_result in scan.get_scan_results()["checks"]:
status = check_result["outcome"]
name = check_result["name"]
logging.info(f"[{status.upper()}] {name}")
if exit_code == 0:
return True
elif exit_code == 2:
logging.warning("Soda scan completed with warnings")
return True # treat warn as pass (adjust to your policy)
else:
return False # fail = 3, error = 4
# --- Spark DataFrame scanning ---
from pyspark.sql import SparkSession
from soda.core.scan import Scan as SparkScan
def scan_spark_df(spark: SparkSession, df, table_alias: str, checks_yaml: str) -> bool:
scan = SparkScan()
scan.set_data_source_name("spark_local")
scan.add_spark_session(spark)
# Register the DataFrame as a temp view
df.createOrReplaceTempView(table_alias)
scan.add_sodacl_yaml_str(checks_yaml)
exit_code = scan.execute()
return exit_code i
---
*Content truncated.*
When not to use it
- →When a single rogue null is acceptable to fail the entire pipeline
- →When scanning massive tables without filters
- →When hardcoding credentials in `configuration.yml`
Prerequisites
Limitations
- →Do not use `warn` threshold , only `fail` for non-critical checks
- →Avoid scanning massive tables without filters
- →Do not hardcode credentials in `configuration.yml`
How it compares
This skill provides a structured framework for defining and executing data quality checks across various data sources using SodaCL, offering a standardized approach compared to custom scripts.
Compared to similar skills
soda-core side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| soda-core (this skill) | 0 | 3mo | Review | Intermediate |
| data-quality-frameworks | 0 | 3mo | No flags | Intermediate |
| data-dbt-guide | 0 | 1mo | Review | Intermediate |
| sqlmesh | 0 | 3mo | Review | Advanced |
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.
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".
sqlmesh
droher
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 `conf
snowflake-connections
sfc-gh-dflippo
Configuring Snowflake connections using connections.toml (for Snowflake CLI, Streamlit, Snowpark) or profiles.yml (for dbt) with multiple authentication methods (SSO, key pair, username/password, OAuth), managing multiple environments, and overriding settings with environment variables. Use this skill when setting up Snowflake CLI, Streamlit apps, dbt, or any tool requiring Snowflake authentication and connection management.
sql-queries
anthropics
Write correct, performant SQL across all major data warehouse dialects (Snowflake, BigQuery, Databricks, PostgreSQL, etc.). Use when writing queries, optimizing slow SQL, translating between dialects, or building complex analytical queries with CTEs, window functions, or aggregations.
senior-data-engineer
davila7
World-class data engineering skill for building scalable data pipelines, ETL/ELT systems, and data infrastructure. Expertise in Python, SQL, Spark, Airflow, dbt, Kafka, and modern data stack. Includes data modeling, pipeline orchestration, data quality, and DataOps. Use when designing data architectures, building data pipelines, optimizing data workflows, or implementing data governance.