Inspiration
Every data team has lived this incident: someone renames or drops a column, CI stays green, and days later a dashboard is silently wrong or an ML feature pipeline breaks. The knowledge to prevent it already exists — it lives in DataHub's lineage graph — but nobody manually walks that graph on every schema PR. We wanted an agent that does the walking for you and hands back a ready-to-merge fix, not just a warning.
What it does
Schema Guardian takes a proposed schema change (rename, drop, or type change) and:
- Reads the real lineage graph from a live DataHub instance through the official DataHub MCP Server — recursively walking every downstream dataset, dbt model, and dashboard that depends on the changing column, along with their owners (from DataHub ownership metadata).
- Produces a structured impact report (
impact_report.md) — severity, every affected asset, and exactly who to notify. - Generates the fix with an LLM, using the actual schemas and view definitions pulled from DataHub as context — not guesses: a
migration.sqlscript with a rollback plan, and a patched version of every affected downstream dbt model, correct on the first try because generation is grounded in real SQL, with a built-in guard that rejects and retries any patch the model tries to leave unchanged. - Writes back to the DataHub graph — tags the changing dataset with
pending_migration, so the next person (or agent) browsing the catalog inherits that knowledge instead of discovering it the hard way.
The output is a set of files a data engineer would actually put in a pull request — not a chat transcript.
How we built it
Python CLI with three interchangeable DataHub clients behind one interface: a mock client for offline development, a DataHub Python SDK client for ownership/schema enrichment and the write-back tag, and — the primary integration — an MCP client that launches the official mcp-server-datahub over stdio and recursively calls its get_lineage tool to walk multi-hop downstream lineage (dataset → dbt model → dbt model → dashboard).
The impact report feeds an LLM (provider-agnostic via an OpenAI-compatible API; we used DeepSeek) with the real downstream view definitions as context, so the generated migration and patches reference actual column names and actual SQL structure instead of hallucinated guesses.
For the demo, we ingested a small but realistic e-commerce lineage scenario into DataHub: a Postgres orders table feeding two dbt models (stg_orders, customer_ltv) feeding a Looker dashboard.
Challenges we ran into
The DataHub MCP Server's get_lineage tool takes a boolean upstream flag rather than a direction string, and by default only returns one hop of lineage — walking a multi-step chain (table → model → model → dashboard) required recursively calling the tool per newly-discovered asset within the same MCP session, while filtering out non-asset URNs (platforms, users, ownership types) that the response also includes.
We also found that a general-purpose LLM prompt tends to take the easy way out on renames — proposing a compatibility view instead of actually rewriting downstream code, even when that code reads the base table directly and would still break. We added an explicit no-op guard that diffs each generated patch against the original definition and forces a corrective retry if nothing actually changed.
Accomplishments that we're proud of
A fully working, end-to-end pipeline against a live DataHub instance: real MCP-based lineage traversal, real ownership-driven notifications, real LLM-generated patches that correctly propagate a rename through dbt {{ source() }} / {{ ref() }} templating, and a real write-back to the DataHub graph — verified from scratch, not mocked.
What we learned
How much of "AI agent reliability" for structured tasks comes down to grounding generation in real data and validating the output rather than trusting the first response — the no-op guard made a measurable difference in output correctness.
What's next for Schema Guardian
- Support additional downstream platforms beyond dbt (Airflow DAGs, dbt Python models).
- Open a PR directly (GitHub API) instead of writing local patch files.
- Extend the write-back to include a structured
SchemaChangeProposalaspect rather than a plain tag, so other agents can query pending migrations programmatically.
Log in or sign up for Devpost to join the conversation.