Skip to content

Changelog

All notable changes to Scherlok are documented here.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Unreleased

[1.0.2] — 2026-09-18

Fixed

  • MCP server reported an empty versionserverInfo.version was blank in every initialize reply because the package version was never passed to the server class, so clients and registries listed the server without a version. It now reports __version__ (mcp 2.x; mcp 1.x FastMCP takes no version parameter and is unaffected).
  • Misleading error when an unsupported mcp is installed — a release exposing neither MCPServer (mcp 2.x) nor FastMCP (mcp 1.x) produced "requires the 'mcp' package … re-install scherlok", which sends the operator down the wrong path. The message now names the installed version and the supported range. The mcp dependency is pinned to >=1.2,<3 to match what is actually tested.

Added

  • stdio handshake testtests/test_mcp_server.py now spawns the installed scherlok-mcp entry point and speaks JSON-RPC over stdio (initialize + tools/list), the way an MCP client or a registry health check does. This is the layer where the two fixes above failed while every in-process test passed.
  • glama.json — declares repository maintainers for the Glama MCP listing.
  • Documentation site at https://rbmuller.github.io/scherlok/ (MkDocs Material, deployed from main by .github/workflows/docs.yml, strict build checked in CI). Includes a sourced comparison with Elementary, Soda, Great Expectations and Monte Carlo; the README table now links to it and no longer quotes unpublished competitor prices.
  • scherlok demo — a self-contained walkthrough that needs no database: seeds a sample DuckDB warehouse (3 tables, 22,500 rows), learns a baseline, ships a "bad deploy" (60% of orders gone, e-mails nulled, free-text plans, a dropped column) and catches it with the real detectors, in about a second. Runs entirely inside one temporary directory and never touches ~/.scherlok; --keep/--dir preserve the files, --output json emits the result for scripts. Requires the duckdb extra: uvx --from "scherlok[duckdb]" scherlok demo.
  • DuckDBConnector.close() — releases the file handle so another writer can open the database.
  • MCP Registry publishing workflow.github/workflows/publish-mcp.yml publishes server.json to the official MCP Registry after each successful Release run (GitHub OIDC, no stored token), so the io.github.rbmuller/scherlok listing no longer lags behind PyPI.

[1.0.1] — 2026-09-17

Fixed

  • PyPI release — v1.0.0 was tagged and released on GitHub but never reached PyPI: the tag still carried version = "0.9.0" in pyproject.toml, so the publish job tried to re-upload 0.9.0 and PyPI rejected it with HTTP 400. 1.0.1 ships the 1.0.0 changes below with the version metadata (pyproject.toml, dbt_project.yml, server.json, __version__) corrected and aligned.

[1.0.0] — 2026-09-03

Added

  • Adaptive historical baselines — after enough valid history, volume and column metric detectors learn per-metric variability with robust median/MAD bands; cold-start and unusable histories retain the existing fixed behavior. (#62)
  • scherlok status --output json — emits a JSON array of table health objects (table, rows, columns, status, last_profiled) for CI parsers. Rich output is routed to stderr in JSON mode so stdout stays machine-readable. (#14)
  • scherlok history --output json — emits a JSON array of anomaly records (detected_at, severity, table, type, message). Empty history returns [] instead of a text message. (#15)
  • scherlok dbt-run-and-watch --output json — the wrapper now accepts the same --output json flag as scherlok dbt, so CI users get the wrapper's convenience and a machine-readable stdout payload in one step. dbt run's own stdout is rerouted to stderr in JSON mode so it never mixes with the payload; if dbt run fails, stdout gets a small JSON error document (project_dir, error, returncode) instead of plain text. (#47)
  • Targeted dbt-run-and-watch profiling — after a successful dbt run, the wrapper reads target/run_results.json and profiles only successful model nodes from that invocation. Missing or malformed artifacts fail clearly rather than falling back to the full manifest. (#69)
  • dbt build support in dbt-run-and-watch — pass --build to run dbt build; on dbt's handled failure path (exit 1), successful model nodes from run_results.json are profiled even when tests fail and downstream models are skipped, while unhandled failures fail fast and preserve dbt's exit code. (#76)
  • Exposure-aware dbt lineage in anomaly alerts — downstream models remain identified separately from dbt exposures, whose labels and owner information are surfaced in the existing alert message without changing notification routing. (#70)
  • Selective column profiling in dbt package — the scherlok_column_metrics model now scans graph.nodes for null_anomaly test nodes and profiles only the columns that have tests attached, reducing warehouse queries on wide tables. (#71)

Fixed

  • Clean JSON stdout on dbt early exitsconsole.print calls that leaked Rich markup to stdout on connection failures and missing manifests now use out_error so they route to stderr in --output json mode. (#67)

[0.9.0] — 2026-08-10

Added

  • dbt package — Scherlok is now installable as a native dbt package (git: install from this repo; the dbt Package Hub listing is pending in dbt-labs/hubcap#456). Includes 4 instant tests (not_null_proportion, row_count_between, recency, unique_proportion) and 2 auto-learning anomaly detection tests (volume_anomaly, null_anomaly) backed by Shewhart control limits. Incremental scherlok_metrics and scherlok_column_metrics models auto-discover and profile all materialized models. One repo, two distribution channels (PyPI + dbt Hub). (#64)

Fixed

  • mcp 2.0 compatibilityFastMCP was renamed to MCPServer in mcp 2.0. Import now tries v2 first, falls back to v1. (#64)
  • MySQL/DuckDB view discoverylist_tables() now includes views alongside base tables, matching the behavior of Postgres, BigQuery, and Snowflake connectors. (#63)

[0.8.0] — 2026-07-10

Added

  • --explain — Claude-augmented alerts on watch, ci, check, dbt, and dbt-run-and-watch. When anomalies fire, one Anthropic API call per run (Claude Haiku 4.5 by default, SCHERLOK_EXPLAIN_MODEL to override) turns the batch into a root-cause hypothesis — summary, likely cause, up to three diagnostic steps — injected into the Slack (attachment), Discord/Teams (text), generic-JSON (explanation field), email, and console alerts, plus an explanation key on dbt --output json. dbt runs feed upstream lineage from manifest.json into the prompt so cascading failures trace to the source model. Aggregate data only (anomaly strings, model names, timestamps — never warehouse rows); fail-open by contract: any API failure delivers the unaugmented alert with a one-line (--explain unavailable: …) note, injected text is escaped and truncated per platform so an oversized hypothesis can never get an alert payload rejected, and the alert path is capped at ~30s worst case. Opt-in via pip install scherlok[explain] + ANTHROPIC_API_KEY. See src/scherlok/explainer/README.md. (#58, #59)
  • --explain demo recordingexamples/demo-explain.svg (asciinema-style cast of a real run), embedded in the README section.

0.7.0 — 2026-05-28

Added

  • MCP serverpip install scherlok now ships a scherlok-mcp stdio server that exposes Scherlok to AI coding agents (Claude Code, Claude Desktop, …) as MCP tools: list_tables, investigate, watch, status, history, check. The connection is resolved server-side (SCHERLOK_CONNECTION / scherlok config) and never passed by the model; every operation is read-only on the warehouse with no arbitrary-SQL tool, and output is bounded. See src/scherlok/mcp/README.md. (#54, #55)
  • server.json + PyPI ownership marker — repo-root server.json and an mcp-name: io.github.rbmuller/scherlok marker in the README so Scherlok can be published to the official MCP Registry (registry.modelcontextprotocol.io). (#56)

Changed

  • mcp is now a core dependency (moved out of the [mcp] extra) so the registry's pip install scherlok install path produces a working scherlok-mcp without an extra step. The [mcp] extra is kept as a back-compat alias and still resolves cleanly. This adds ~15 transitive packages (anyio, pydantic, httpx, starlette, uvicorn family) to the base install; the trade was deliberate — first-class agent integration over a lean install.
  • Extracted the per-table profile-and-detect orchestration into scherlok.service so the CLI and the MCP server share one transport-agnostic core (no behavior change).

0.6.0 — 2026-05-20

Added

Connectors

  • MySQL connectorpip install scherlok[mysql], scherlok connect mysql://user:pass@host:3306/db. Works with MariaDB and other compatible forks. (#45, closes #18)
  • DuckDB connectorpip install scherlok[duckdb], scherlok connect duckdb:///path/to/file.db (or duckdb:///:memory:). For local-first analytics workflows. (#50, closes #19)

dbt integration

  • scherlok dbt-run-and-watch — wraps the typical CI sequence (dbt run -> scherlok dbt) into one invocation. Streams dbt run output live; if dbt run fails, exits with the same code WITHOUT running scherlok against a stale or partial manifest. Passes --target, --profiles-dir, and --select through to dbt run. Requires the dbt binary on PATH (dbt-core remains an opt-in dependency). (#40, closes #34)
  • scherlok dbt --output json — emits a single JSON document on stdout (status + per-model anomalies) for CI parsers, with Rich chatter rerouted to stderr so stdout stays machine-readable. (#41, closes #33)
  • scherlok dbt --include-snapshots — opt-in flag to also profile dbt snapshot nodes. Snapshots are SCD Type 2 tables that physically exist in the warehouse and are profilable like any other materialized model. When the flag is unset, behavior is unchanged. (#26, closes #22)
  • dbt lineage from manifest.json — new scherlok.dbt.lineage module reads the manifest's parent_map. Two surfaces consume it: scherlok dbt --show-lineage (also on dbt-run-and-watch) prints an ASCII upstream/downstream tree (├── / └── style) under each profiled model; and every anomaly message is suffixed with · Affects N downstream models: a, b, c when descendants exist, so webhook and email payloads tell on-call who's about to be paged downstream. Leaf marts get no suffix. (#49, closes #36)

Dashboard

  • 14-day anomaly trend barchart — per-day severity bars in the HTML report. (#28, closes #20)
  • Stale tables panel — surfaces tables whose last profile is older than the freshness threshold, to catch silent ETL failures. (#30, closes #21)

CLI

  • scherlok check — alias for scherlok ci --fail-on critical, the one-liner CI gate. (#44, closes #32)
  • scherlok connect with no args prints example connection strings for every supported adapter instead of erroring. (#24, closes #23)

Distribution

  • Docker image — multi-stage Dockerfile published to GHCR. (#38, closes #35)

Changed

  • Release workflow fails if the linux/amd64 image exceeds 100 MiB, so the published image can't silently bloat. (#43)

0.5.0 — 2026-04-30

Added

  • dbt integration v0 — new scherlok dbt command. Reads target/manifest.json, discovers materialized models (table/incremental/view/materialized_view), auto-resolves the connection from profiles.yml (postgres / bigquery / snowflake), and runs investigate + watch per model with dbt-style ✓/✗ output.
  • Optional dependency: pip install scherlok[dbt] (adds PyYAML)
  • Flags: --project-dir, --profiles-dir, --target, --connection-string, --select, --include-sources, --fail-on, --webhook, --email
  • Supports {{ env_var('NAME', 'default') }} rendering in profiles.yml
  • Requires dbt 1.6+ (manifest schema v10+)
  • HTML dashboard — new scherlok dashboard command. Generates a self-contained HTML report (~28 KB) from the local profile store: KPIs, per-table incidents grouped with summary/threshold/first-seen, schema-drift +//~ diff, sparklines, and history. Auto dark/light theme via prefers-color-scheme (--theme dark|light to override). Adds jinja2>=3.0 to core dependencies.
  • examples/dbt_smoke/ — runnable mini dbt project (3 models on top of the existing seeded Postgres in examples/docker-compose.yml) for contributors to reproduce the dbt + dashboard flow end-to-end.

Changed

  • --verbose / -v and --quiet / -q global flags added to all commands. --quiet silences progress chatter while keeping anomaly results and errors (CI-friendly). --verbose adds per-table profiling timings and column counts.
  • Connector error messages now include actionable hints. Failed to connect. is followed by a one-line explanation of what went wrong, plus a hint when applicable.
  • Postgres: classifies "connection refused" / "auth failed" / "database does not exist" / "SSL required" / timeout / unknown host
  • Snowflake: detects missing SNOWFLAKE_USER / SNOWFLAKE_PASSWORD, missing python connector, auth failures, account/warehouse/database not found
  • BigQuery: detects missing google-cloud-bigquery, missing Application Default Credentials, permission denied, project/dataset not found, billing not enabled

Fixed

  • Views were silently skipped by scherlok investigate/watch/dbt on Postgres and Snowflake (list_tables filtered to BASE TABLE only). Materialized dbt views (materialized: view, the default for staging/ models in layered dbt projects) are now discovered. (#7)
  • Release notes extraction in CI — the awk in release.yml was using regex match against ## [version], where [...] is interpreted as a character class. Switched to literal-substring match so v0.5.0 release notes are properly extracted from CHANGELOG.md instead of falling back to the generic placeholder.

0.4.0 — 2026-04-27

Added

  • Snowflake connector (pip install scherlok[snowflake])
  • scherlok ci command — all-in-one CI/CD (connect + watch + exit code) in one line
  • Email alerter — scherlok watch --email user@company.com (configure via SCHERLOK_SMTP_* env vars)
  • Multi-recipient support: --email is repeatable
  • Issue templates (bug, feature, new connector)
  • CHANGELOG.md
  • Automatic GitHub Release notes on tag push

0.3.0 — 2026-04-22

Added

  • Generic webhook alerter — auto-detects Slack, Discord, Microsoft Teams, or generic JSON endpoints
  • --webhook / -w flag in the watch command

Removed

  • Removed legacy Slack-only path; replaced by the generic webhook

0.2.2 — 2026-04-22

Fixed

  • Sync __version__ between pyproject.toml and src/scherlok/__init__.py

0.2.0 — 2026-04-22

Added

  • BigQuery connector (pip install scherlok[bigquery])
  • Detective logo (AI-generated illustration)
  • Animated SVG demo in README
  • Examples folder with Docker + PostgreSQL quick start
  • 34 new tests across store, alerter, config, BigQuery (93 total)
  • PyPI release workflow with trusted publishing
  • Redesigned README

0.1.0 — 2026-04-15

Added

  • Initial release
  • PostgreSQL connector
  • 6 anomaly detectors: volume, schema drift, freshness, nullability, distribution, cardinality
  • CLI with Typer (connect, investigate, watch, report, status, history, version)
  • Local SQLite storage + remote storage (S3, GCS, Azure Blob)
  • Slack webhook integration
  • 59 unit tests