Schema Alignment Skill
Detect drift between database schemas and code data models. This skill identifies missing columns, type mismatches, orphaned migrations, and naming inconsistencies.
Design Principle
This skill is framework-generic. It works with any ORM or database:
- SQLAlchemy (Python)
- Django ORM (Python)
- Prisma (TypeScript/JavaScript)
- TypeORM (TypeScript)
- Drizzle (TypeScript)
- Alembic migrations
- Prisma migrations
- Django migrations
Variables
| Variable | Default | Description | |----------|---------|-------------| | SCHEMA_SOURCE | auto | Schema source: auto, migrations, live_db, models | | SEVERITY_THRESHOLD | medium | Report issues at this level or higher | | AUTO_FIX | false | Attempt to generate fix suggestions | | INCLUDE_TYPES | true | Include type mismatch detection |
Instructions
MANDATORY - Follow the Workflow steps below in order.
- Detect database technology and ORM in use
- Extract schema from migrations or live database
- Extract data models from code
- Compare and identify drift
- Generate alignment report
Red Flags - STOP and Reconsider
If you're about to:
- Modify the database schema directly without a migration
- Assume a column exists without checking the schema
- Skip type checking because "it works in tests"
- Ignore nullable/not-null mismatches
STOP -> Check schema alignment -> Generate migration if needed -> Then proceed
Workflow
1. Detect Stack
Identify the database and ORM:
Check for these indicators:
| File/Dependency | Technology |
|-----------------|------------|
| alembic.ini, alembic/ | Alembic (SQLAlchemy) |
| prisma/schema.prisma | Prisma |
| manage.py + migrations/ | Django |
| ormconfig.json | TypeORM |
| drizzle.config.ts | Drizzle |
| supabase/migrations/ | Supabase (PostgreSQL) |
2. Extract Database Schema
Option A: From Migrations (Preferred)
Parse migration files to reconstruct current schema:
# Alembic example
from alembic.script import ScriptDirectory
from alembic.config import Config
config = Config("alembic.ini")
scripts = ScriptDirectory.from_config(config)
# Walk revisions to build schema
Option B: From Live Database
Query information_schema (if accessible):
SELECT table_name, column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'public';
Option C: From Model Definitions
Parse ORM model files directly.
3. Extract Code Models
Parse model definitions from code:
SQLAlchemy
# Look for patterns like:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
email = Column(String(255), nullable=False)
Prisma
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}
Pydantic/TypeScript Types
Also extract related types:
- Pydantic models
- TypeScript interfaces
- BAML type definitions
4. Compare and Detect Drift
Run comparisons:
| Check | Source A | Source B | Issue Type | |-------|----------|----------|------------| | Missing column | DB schema | ORM model | MISSING_IN_MODEL | | Missing column | ORM model | DB schema | MISSING_IN_DB | | Type mismatch | DB type | Code type | TYPE_MISMATCH | | Nullable mismatch | DB nullable | Model nullable | NULLABLE_MISMATCH | | Name mismatch | snake_case | camelCase | NAMING_DRIFT | | Missing migration | Model change | Migration files | MISSING_MIGRATION | | FK constraint | DB constraint | ORM relationship | FK_MISMATCH |
5. Generate Report
Output format:
# Schema Alignment Report
**Generated**: 2025-12-24T10:00:00Z
**Database**: PostgreSQL (via Supabase)
**ORM**: SQLAlchemy 2.0
## Summary
| Severity | Count |
|----------|-------|
| HIGH | 2 |
| MEDIUM | 3 |
| LOW | 5 |
## Issues
### 1. MISSING_IN_MODEL (HIGH)
**Table**: `curation_jobs`
**Column**: `retry_count` (INTEGER NOT NULL DEFAULT 0)
**Model**: `src/models/curation_job.py:CurationJob`
The column exists in the database but is not defined in the ORM model.
**Fix**:
```python
retry_count: Mapped[int] = mapped_column(Integer, default=0)
2. TYPE_MISMATCH (MEDIUM)
Table: books
Column: isbn (VARCHAR(13))
Model: src/models/book.py:Book.isbn -> str
Database constrains to 13 characters but model allows unbounded string.
Fix:
isbn: Mapped[str] = mapped_column(String(13))
3. MISSING_MIGRATION (LOW)
Model Change: User.preferences added (JSONB)
Migration: Not found
A new column was added to the model but no migration exists.
Fix:
alembic revision --autogenerate -m "add user preferences"
## Cookbook
### SQLAlchemy Detection
- IF: Parsing SQLAlchemy models
- THEN: Read and execute `./cookbook/sqlalchemy-detection.md`
### Prisma Detection
- IF: Parsing Prisma schema
- THEN: Read and execute `./cookbook/prisma-detection.md`
### Alembic Migrations
- IF: Generating migration fix
- THEN: Read and execute `./cookbook/alembic-migration.md`
## Issue Severity Matrix
| Issue Type | Default Severity | Upgrade If |
|------------|-----------------|------------|
| MISSING_IN_MODEL | HIGH | Column is NOT NULL |
| MISSING_IN_DB | MEDIUM | Model references it |
| TYPE_MISMATCH | MEDIUM | Could cause data loss |
| NULLABLE_MISMATCH | LOW | NOT NULL in code, nullable in DB |
| NAMING_DRIFT | LOW | - |
| MISSING_MIGRATION | LOW | - |
| FK_MISMATCH | MEDIUM | Causes ORM errors |
## Integration
### With /ai-dev-kit:check-schema
Direct invocation:
```bash
# Full check
/ai-dev-kit:check-schema
# Check specific tables
/ai-dev-kit:check-schema --tables=users,orders
# Generate fixes
/ai-dev-kit:check-schema --auto-fix
# Output to file
/ai-dev-kit:check-schema --output=alignment-report.md
With /ai-dev-kit:execute-lane
Runs as pre-flight check for database-related lanes:
Lane: SL-DB (Database Schema)
Pre-flight checks:
1. ✓ Git worktree clean
2. ✗ Schema alignment check failed
- 2 HIGH severity issues found
- See alignment-report.md
Action: Resolve schema issues before proceeding.
With /ai-dev-kit:plan-phase
Runs during phase planning:
Planning Phase P1...
Schema Alignment: ⚠️ 3 issues detected
- 1 missing migration
- 2 type mismatches
Recommendation: Add schema alignment task to SL-DB lane.
Output Schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"generated_at": {"type": "string", "format": "date-time"},
"database": {"type": "string"},
"orm": {"type": "string"},
"summary": {
"type": "object",
"properties": {
"high": {"type": "integer"},
"medium": {"type": "integer"},
"low": {"type": "integer"}
}
},
"issues": {
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {"type": "string"},
"severity": {"enum": ["HIGH", "MEDIUM", "LOW"]},
"table": {"type": "string"},
"column": {"type": "string"},
"model_location": {"type": "string"},
"description": {"type": "string"},
"fix": {"type": "string"}
}
}
}
}
}
Best Practices
- Run regularly: Check schema alignment before each PR
- CI integration: Add to CI pipeline for automatic detection
- Migration hygiene: Always generate migrations for model changes
- Type consistency: Use explicit types in models matching DB constraints
- Document drift: If drift is intentional, document why