Elementary is great. I use it. But after writing YAML for the 200th anomaly test, I asked myself: why am I teaching the tool what "normal" looks like when the data already knows?
So I built Scherlok — a zero-config data quality monitor that learns your data's patterns and detects anomalies automatically. No YAML. No thresholds. No rules to maintain.
It just shipped on the dbt Package Hub, so you can install it as a native dbt package today. Here's what makes it different, and when you should use which.
The core difference
Elementary asks you to define what's normal:
# schema.yml — per model, per test, per column
models:
- name: fct_orders
tests:
- elementary.volume_anomaly:
timestamp_column: created_at
time_bucket:
period: day
sensitivity: 3
You configure the timestamp column, the time bucket, the sensitivity, the training period, the detection method. For every model. For every test. It's powerful, but it's work — and the configurations accumulate.
Scherlok inverts the model:
scherlok connect postgres://user:pass@host/db
scherlok investigate # profiles everything
scherlok watch # detects anomalies
Three commands. Done. No YAML, no per-model configuration, no timestamp columns to specify. Scherlok profiles every table and column automatically, learns the distributions, and flags when something deviates from the learned baseline.
An honest comparison
I'm not going to pretend Scherlok is better at everything. Here's where each tool wins:
| Elementary | Scherlok | |
|---|---|---|
| Setup time | 30-60 min (package + config per model) | 5 min (connect + investigate) |
| Configuration | Granular per-model YAML | Zero (auto-discovers everything) |
| Detection methods | Multiple algorithms, configurable | Shewhart control limits (mean ± kσ) |
| dbt integration depth | Deep (runs inside dbt) | CLI + native dbt package |
| Dashboard | Beautiful hosted UI (Elementary Cloud) | Self-contained HTML file |
| Lineage-aware alerts | Yes | Yes (reads manifest.json) |
| AI explanations | No | Yes (Claude, opt-in) |
| MCP server | No | Yes (AI agents can run checks) |
| Non-dbt usage | Requires dbt | Works with or without dbt |
| Price | Free package, paid Cloud | Free, forever |
| Connectors | dbt adapters | Postgres, BigQuery, Snowflake, MySQL, DuckDB |
Use Elementary when you want fine-grained control over every detection parameter, need the hosted dashboard for non-technical stakeholders, or your team already has the YAML config in place.
Use Scherlok when you want anomaly detection running in minutes without writing configuration, need it outside of dbt, or want AI-powered explanations on your alerts.
The dbt package — best of both worlds
As of v0.9.0, Scherlok ships as a native dbt package. This means you can use Scherlok's tests inside your existing schema.yml without leaving dbt:
# packages.yml
packages:
- package: rbmuller/scherlok
version: [">=0.9.0", "<1.0.0"]
# schema.yml
models:
- name: fct_orders
tests:
- scherlok.volume_anomaly:
sensitivity: 3.0
- scherlok.row_count_between:
min_value: 100
columns:
- name: email
tests:
- scherlok.not_null_proportion:
max_rate: 0.01
- name: updated_at
tests:
- scherlok.recency:
days: 2
Six tests available:
Instant (no setup, works on first dbt test):
-
not_null_proportion— NULL rate exceeds threshold -
row_count_between— row count outside bounds -
recency— data is stale -
unique_proportion— cardinality drops
Auto-learning (builds baseline over time):
-
volume_anomaly— row count outside Shewhart control limits -
null_anomaly— NULL rate spike vs historical
The auto-learning tests use an incremental scherlok_metrics model that runs with dbt run and captures row counts per model. After 5 runs, the anomaly tests activate automatically. Before that, they pass silently — first runs are baseline, not false alarms.
The CLI — where Scherlok really shines
The dbt package is one distribution channel. The CLI is where the "zero-config" promise delivers the most value.
Connect to any warehouse
scherlok connect postgres://user:pass@host/db
scherlok connect bigquery://project-id/dataset
scherlok connect snowflake://account/database/schema
scherlok connect mysql://user:pass@host/db
scherlok connect duckdb:///path/to/file.db
Profile everything in one command
$ scherlok investigate
Profiling 12 tables...
✓ users — 45,231 rows, 8 columns
✓ orders — 1,203,847 rows, 15 columns
✓ products — 892 rows, 12 columns
...
Done. Profiles saved.
Detect and alert
$ scherlok watch --webhook $SLACK_URL --explain
🔴 CRITICAL orders volume_drop Row count dropped 52%
🟡 WARNING users null_increase Column "email": NULL rate 2.1% → 18.7%
💡 Hypothesis: The orders volume drop correlates with stg_orders
upstream. The source table likely stopped receiving data from
the payments API after the 2026-08-09 deploy.
The --explain flag is opt-in. When anomalies fire, Scherlok sends the anomaly batch (not your data — just the anomaly messages) to Claude for a root-cause hypothesis. On dbt projects, it includes upstream lineage so cascading failures get traced to the source model. Costs under $0.003 per run. If the API fails, the alert is delivered unchanged.
CI in one line
- run: scherlok ci $DATABASE_URL --fail-on critical --webhook $SLACK_URL
AI agents can use it directly
Scherlok ships an MCP server since v0.7.0. Claude Code or Claude Desktop can profile tables and detect anomalies without you typing commands:
{
"mcpServers": {
"scherlok": {
"command": "scherlok-mcp",
"env": { "SCHERLOK_CONNECTION": "postgresql://..." }
}
}
}
The agent gets list_tables, investigate, watch, status, history, and check as tools. Credentials stay server-side. Every operation is read-only.
Technical decisions
A few choices that might be interesting if you're building in this space:
Shewhart over ML. I chose Shewhart control limits (mean ± kσ) over fancy ML models. It's boring, debuggable, and transparent. When a test fires, you can explain why in one sentence: "row count was 3.2 standard deviations below the 30-day average." No black box. The tradeoff: no seasonality modeling. If your data has strong weekly patterns, you'll get false positives on Mondays. For most tables, Shewhart catches 90% of real incidents with zero tuning.
SQLite for profiles. Your baseline data lives in ~/.scherlok/profiles.db. You can inspect it with sqlite3, copy it to another machine, or sync it to S3/GCS/Azure for team use. No hosted service required.
Read-only by contract. Scherlok never writes to your warehouse. The test suite enforces this. Your DBA will appreciate it.
One repo, two channels. The same GitHub repo (rbmuller/scherlok) ships as a PyPI package (pip install scherlok) and a dbt package (package: rbmuller/scherlok). pyproject.toml and dbt_project.yml coexist at the root without conflicts.
When NOT to use Scherlok
Being honest about limitations:
-
Strong seasonality patterns — Shewhart control limits don't model day-of-week or seasonal cycles. You'll need to tune
sensitivityhigher or use Elementary's timestamp-aware algorithms. -
Custom business rules — "revenue must match between systems A and B" is a rule, not an anomaly. Use
dbt testor Great Expectations for that. - Non-technical stakeholders — Elementary Cloud's dashboard is built for people who don't live in the terminal. Scherlok's HTML dashboard is useful but developer-oriented.
Try it
pip install scherlok
scherlok connect YOUR_DATABASE_URL
scherlok investigate
scherlok watch
Or as a dbt package:
packages:
- package: rbmuller/scherlok
version: [">=0.9.0", "<1.0.0"]
- Repo: github.com/rbmuller/scherlok
- PyPI: pypi.org/project/scherlok
- dbt Hub: hub.getdbt.com (pending approval)
MIT licensed. 344 tests. 5 connectors. Zero config.
Top comments (0)