From dbt-pipeline-toolkit
Analyze dbt test coverage across all models and identify gaps. Calculate coverage percentages, find untested models, identify missing primary key and foreign key tests. Use when validating test coverage, ensuring data quality standards, or preparing for production deployment. Reports coverage by layer (staging, marts) and model type.
How this skill is triggered — by the user, by Claude, or both
Slash command
/dbt-pipeline-toolkit:dbt-test-coverage-analyzerThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Analyze test coverage across all dbt models to ensure data quality standards are met.
Analyze test coverage across all dbt models to ensure data quality standards are met.
This skill scans your dbt project to:
python "${CLAUDE_PLUGIN_ROOT}/skills/dbt-test-coverage-analyzer/scripts/analyze_coverage.py"
Outputs:
python "${CLAUDE_PLUGIN_ROOT}/skills/dbt-test-coverage-analyzer/scripts/analyze_coverage.py" --detailed
Includes:
python "${CLAUDE_PLUGIN_ROOT}/skills/dbt-test-coverage-analyzer/scripts/analyze_coverage.py" --format json
Returns structured JSON for CI/CD integration or further processing.
# Analyze only staging models
python "${CLAUDE_PLUGIN_ROOT}/skills/dbt-test-coverage-analyzer/scripts/analyze_coverage.py" --layer staging
# Analyze only marts (facts + dimensions)
python "${CLAUDE_PLUGIN_ROOT}/skills/dbt-test-coverage-analyzer/scripts/analyze_coverage.py" --layer marts
Overall Target: 80% of models have tests
By Layer:
Critical Tests (Must have):
unique + not_nullnot_null + relationships=== dbt Test Coverage Report ===
Overall Coverage: 75.0% (45/60 models)
Target: 80% ⚠️ BELOW TARGET
Coverage by Layer:
├─ staging/ : 100.0% (15/15) ✓
├─ marts/ : 66.7% (30/45) ⚠️
│ ├─ facts : 80.0% (12/15)
│ └─ dims : 60.0% (18/30)
└─ intermediate: 0.0% (0/0) N/A
UNTESTED MODELS (15):
Critical (5):
⚠️ fct_sales - Missing: PK tests, FK tests
⚠️ dim_customer - Missing: PK tests
⚠️ dim_product - Missing: PK tests
⚠️ fct_orders - Missing: PK tests, FK tests
⚠️ dim_date - Missing: PK tests
High Priority (10):
⚠️ fct_revenue - Missing: FK tests to dim_customer
⚠️ dim_location - Missing: natural key tests
... (8 more)
RECOMMENDATIONS:
1. Add primary key tests (unique + not_null) to 5 models
2. Add foreign key tests (relationships) to 8 models
3. Add critical measure tests (not_null) to 3 fact tables
4. Current coverage: 75% → Target: 80% (Need 3 more models tested)
Coverage % = (Models with Tests / Total Models) × 100
Model "has tests" if:
- Has at least 1 generic test (unique, not_null, relationships, accepted_values)
- OR has at least 1 custom test (singular or generic)
Every model should have a primary key with:
unique testnot_null testFor fact tables and models with foreign keys:
not_null test on FK columnrelationships test linking to dimensionFor important columns:
not_null on required measuresaccepted_values on categorical columnsChecks if models have:
The analyzer script uses its existing --target <percentage> flag as both the reporting target AND the enforcement threshold. When coverage is below target, the script exits with code 1 automatically. Enforcement is therefore a single atomic Bash call — no shell variables, command substitution, or conditional blocks required. Consistent with this plugin's atomic-commands rule and works identically inside Claude Code and inside CI runners.
# .git/hooks/pre-commit
python "${CLAUDE_PLUGIN_ROOT}/skills/dbt-test-coverage-analyzer/scripts/analyze_coverage.py" --target 80
If the analyzer exits with code 1, the pre-commit hook fails the commit. The script prints the report to stdout so the user can see what's missing — no further scripting needed.
A single atomic step handles both reporting and enforcement, because --target 80 makes the script exit 1 when coverage drops below 80%:
- name: Check dbt Test Coverage
run: python "${CLAUDE_PLUGIN_ROOT}/skills/dbt-test-coverage-analyzer/scripts/analyze_coverage.py" --detailed --target 80
GitHub Actions surfaces the non-zero exit as a step failure and shows the detailed report in the step log. No need for shell variables, jq, bc, separate enforcement steps, or conditional blocks in the workflow YAML. One atomic command does the whole job.
Note on the
--targetflag: the flag is already part of the script —--target <percentage>serves as both the coverage target shown in the report and the threshold for exit-code enforcement. The default is 80%. Pass a different number to enforce a different target. The legacy shell-pipeline pattern (usingjqto parse JSON output andbcto compare thresholds) is intentionally not shown as an example in this SKILL.md because it violates the plugin's atomic-commands rule and teaches users a pattern that breaks in Claude Code background subagents. Write enforcement logic in the Python script, not in shell.Caveat for interactive use: the script's exit-1-on-below-target behavior is unconditional — even a one-off interactive invocation like
python analyze_coverage.py --format jsonwill exit 1 if coverage is below the default target of 80%. This is the desired behavior for CI but can be surprising in interactive contexts. If you want exit-0 inspection without enforcement, pass a permissive target like--target 0, which always passes. A future enhancement could add an explicit--no-failflag to separate report-only from enforcement semantics — see the open follow-ups in_Documentation/plugin_learnings.mdFinding 9.
{
"overall_percentage": 75.0,
"target_percentage": 80.0,
"total_models": 60,
"tested_models": 45,
"untested_models": 15,
"by_layer": {
"staging": {"percentage": 100.0, "tested": 15, "total": 15},
"marts": {"percentage": 66.7, "tested": 30, "total": 45}
},
"critical_gaps": [
{
"model": "fct_sales",
"missing": ["pk_unique", "pk_not_null", "fk_customer", "fk_product"],
"priority": "critical"
}
],
"recommendations": [
"Add primary key tests to 5 models",
"Add foreign key tests to 8 models"
]
}
python "${CLAUDE_PLUGIN_ROOT}/skills/dbt-test-coverage-analyzer/scripts/analyze_coverage.py" --format markdown --target 0
Prints a markdown-formatted report to stdout (the --target 0 keeps the command exit-0 so it does not fail when only inspecting). Capture the output with your tooling and save it to a file for:
Use this skill when:
Typical workflow:
dbt-test-coverage-analyzer to check coverageThis skill does NOT:
dbt test for that)This skill DOES:
Python Dependencies:
pyyaml - Parse schema.yml filespathlib - File system navigationdbt Project Requirements:
models/ directory# In PR workflow
python "${CLAUDE_PLUGIN_ROOT}/skills/dbt-test-coverage-analyzer/scripts/analyze_coverage.py" --detailed
# Output shows gaps
# Add missing tests
# Re-check
python "${CLAUDE_PLUGIN_ROOT}/skills/dbt-test-coverage-analyzer/scripts/analyze_coverage.py"
# Coverage now 85% ✓
# Proceed with PR
# Check only marts coverage
python "${CLAUDE_PLUGIN_ROOT}/skills/dbt-test-coverage-analyzer/scripts/analyze_coverage.py" --layer marts
# Shows facts at 80%, dims at 60%
# Focus on dimension tests
# Re-check marts
python "${CLAUDE_PLUGIN_ROOT}/skills/dbt-test-coverage-analyzer/scripts/analyze_coverage.py" --layer marts
# All marts now at 90%+ ✓
Enforcement is a single atomic command — --target makes the script exit 1 when coverage is below the threshold, so no JSON parsing or shell pipelines are needed:
# Run in CI pipeline — exits non-zero (fails the build) if coverage < 80%
python "${CLAUDE_PLUGIN_ROOT}/skills/dbt-test-coverage-analyzer/scripts/analyze_coverage.py" --detailed --target 80
To inspect coverage without failing the build, disable enforcement with a permissive target:
python "${CLAUDE_PLUGIN_ROOT}/skills/dbt-test-coverage-analyzer/scripts/analyze_coverage.py" --detailed --target 0
Target: 80% overall coverage Priority: Critical for production deployments Frequency: Run before every PR merge
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub kavasimihaly/ai-plugins --plugin dbt-pipeline-toolkit