Inspiration

Every developer has a migration horror story. A column dropped in production. A NOT NULL added to a table with a million rows. A "harmless" rename that silently broke half the ORM code.

Tools like Flyway and Liquibase prove teams want schema version control, but they treat your schema like a flat text file. Your schema isn't text. It's a graph of tables, columns, and relationships. And the real danger is never the SQL itself. It's the code that depends on it. I wanted a tool that understands both.

What it does

SchemaSync is GitHub for your database.

  • Every schema change is a commit. Branch, commit, and merge your schema exactly like code.
  • Every diff is a live ER diagram. New tables glow green, dropped columns go red, changed types pulse yellow.
  • Every merge request gets an AI review board. Five agents collaborate to review the migration before it ships:
    • The Schema Analyst computes the semantic diff and detects renames
    • The Impact Scout searches your actual codebase for everything the change will break
    • The Migration Engineer generates the SQL, dry-runs it against real Postgres, and revises its plan based on what the Scout finds
    • The Leader weighs the evidence against lessons from past migrations
    • The Release Agent opens the PR, files tickets for affected code, and notifies the team, but only after a human approves

In my demo, dropping orders.total looks safe in isolation. The Scout finds it referenced in 4 files, and the Engineer rewrites its own plan into a safe expand/contract migration. That's the moment I built this for.

How I built it

SchemaSync is a polyglot system where every language has a job:

Layer Tech Role
Parser + diff Rust + libpg_query (C) Uses Postgres's own parser, then runs a deterministic semantic diff
Version control Python / FastAPI Commits, branches, three-way merge, conflict detection
Migration CI Go Generates ALTER SQL and dry-runs it on real Postgres with seeded data
Gateway Node.js REST, WebSockets, GitHub webhooks
Frontend React + TypeScript + React Flow Animated ER diff and live agent review panel
Agents openJiuwen JiuwenSwarm Leader-led multi-agent workflow with a human approval gate
Agent brain Backboard Model routing and per-repo memory of team lessons
Agent hands Composio GitHub code search, pull requests, Linear, Slack
Data MongoDB Atlas, PostgreSQL, Redis Snapshots and agent messages, commit graph, diff cache

Commits are content-addressed, just like Git. Each schema snapshot is hashed and stored in MongoDB Atlas, and commits point to snapshots.

The agents never talk to each other directly. Every message goes onto a shared board in Atlas, and Atlas change streams push each one to the UI the instant it's written. The whole review is auditable and replayable.

Rename detection combines embedding similarity with type compatibility. For a dropped column $a$ and an added column $b$ in the same table:

$$ \text{score}(a, b) = \alpha \cdot \cos\big(e(a), e(b)\big) + (1 - \alpha) \cdot \mathbb{1}[\text{type}(a) \sim \text{type}(b)] $$

where $e(\cdot)$ is a MiniLM embedding of the column name. Pairs above a threshold are suggested as RENAME COLUMN instead of a destructive drop and add. The same embedding model powers Atlas Vector Search over past migrations, so one small CPU model does two jobs.

My correctness test is a round trip. For any two schemas $A$ and $B$:

$$ \text{parse}\Big(\text{dump}\big(\text{apply}(\text{generate}(\Delta(A, B)),\ A)\big)\Big) = B $$

If generating a migration from the diff and applying it to $A$ doesn't produce exactly $B$, the build fails.

Challenges I ran into

  • Building a five-language system alone in 36 hours. I couldn't afford to lose a day to any one piece, so I built in layers: a working version-control demo first, then a fully scripted agent review, then live agents swapped in one at a time. At every stage, I had something I could demo.
  • Parsing SQL is a trap. Writing my own DDL parser would have eaten the whole weekend. Using libpg_query, the parser extracted from Postgres itself, meant correctness came for free and my Rust code could focus on the diff.
  • Docker-in-Docker is fragile. My first plan spun up a fresh Postgres container for every dry run. Instead, I keep one warm container and create a throwaway database per run, which took dry runs from seconds to milliseconds.
  • Empty tables lie. Adding a NOT NULL column passes on an empty table and fails in production. I seed fake rows before every dry run so the CI catches what production would.
  • Agents are unreliable by default. Early on, the Engineer would sometimes ignore the Scout's findings. I made "revise based on impact" an explicit stage in the workflow, so the collaboration happens every time while the content stays fully live.

What I learned

  • The hard part of schema changes isn't the SQL. It's knowing what depends on it.
  • Multi-agent systems work best with structure. A shared message board and explicit stages made my agents far more reliable than free-form chat.
  • Determinism and AI complement each other. The LLMs propose, but Rust, Go, and real Postgres verify.
  • Scoping is a skill. Knowing what to cut, and when, mattered as much as anything I wrote.

What's next

  • Support for MySQL and SQLite
  • A GitHub App that runs the review board on every PR touching a migration file
  • Learning each team's migration habits over time, so reviews get sharper the more you use it

Built With

Share this project:

Updates

Submission history