Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Manage database migrations with Alembic. Use when a user asks to version database schemas, create migration scripts, handle schema changes in production, or manage SQLAlchemy model migrations.
.claude/skills/terminalskills-alembic/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 4% | 0% |
| case-01 | ✗→✓ | ▲ Improved | -12% | 0% |
| case-19 | ✓→✗ | ▼ Worse | 68% | 0% |
| case-16 | ✓→✓ | = Same ✓ | 9% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 60% | 0% |
Alembic is the migration tool for SQLAlchemy. It tracks database schema changes as versioned Python scripts — like Git for your database. Supports autogeneration from model changes, branching, and data migrations.
bashpip install alembic alembic init alembic
python# alembic/env.py — Configure with async SQLAlchemy from alembic import context from sqlalchemy.ext.asyncio import create_async_engine from models import Base import asyncio config = context.config target_metadata = Base.metadata def run_migrations_online(): connectable = create_async_engine(config.get_main_option("sqlalchemy.url")) async def do_run(): async with connectable.connect() as connection: await connection.run_sync(do_migrations) def do_migrations(connection): context.configure(connection=connection, target_metadata=target_metadata) with context.begin_transaction(): context.run_migrations() asyncio.run(do_run()) run_migrations_online()
bash# Auto-generate from model changes alembic revision --autogenerate -m "add projects table" # Create empty migration (for data migrations) alembic revision -m "backfill user roles"
python# alembic/versions/001_add_projects.py — Generated migration def upgrade(): op.create_table('projects', sa.Column('id', sa.String(36), primary_key=True), sa.Column('name', sa.String(100), nullable=False), sa.Column('owner_id', sa.String(36), sa.ForeignKey('users.id')), sa.Column('created_at', sa.DateTime, server_default=sa.func.now()), ) op.create_index('ix_projects_owner_id', 'projects', ['owner_id']) def downgrade(): op.drop_index('ix_projects_owner_id') op.drop_table('projects')
python# alembic/versions/002_backfill_roles.py — Data migration from alembic import op import sqlalchemy as sa def upgrade(): # Add column op.add_column('users', sa.Column('role', sa.String(20), server_default='member')) # Backfill existing rows conn = op.get_bind() conn.execute(sa.text("UPDATE users SET role = 'admin' WHERE email LIKE '%@mycompany.com'")) def downgrade(): op.drop_column('users', 'role')
bashalembic upgrade head # apply all pending migrations alembic downgrade -1 # rollback one migration alembic history # show migration history alembic current # show current revision alembic upgrade +1 # apply next migration only
op.batch_alter_table() for SQLite (which doesn't support ALTER TABLE well).| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-02 | fail→pass | 10,036 | 7,084 | -29% | 1 | 1 | 0% | 2,225 | 2,320 | +4% | 0 | 0 | — |
case-16 | pass→pass | 7,571 | 3,596 | -53% | 1 | 1 | 0% | 1,280 | 1,395 | +9% | 0 | 0 | — |
case-01 | fail→pass | 10,931 | 5,851 | -46% | 1 | 1 | 0% | 2,301 | 2,023 | -12% | 0 | 0 | — |
case-03 | pass→pass | 4,860 | 4,125 | -15% | 1 | 1 | 0% | 1,104 | 1,764 | +60% | 0 | 0 | — |
case-04 | pass→pass | 5,984 | 4,047 | -32% | 1 | 1 | 0% | 1,216 | 1,596 | +31% | 0 | 0 | — |
case-05 | pass→pass | 2,892 | 1,987 | -31% | 1 | 1 | 0% | 414 | 1,085 | +162% | 0 | 0 | — |
case-06 | pass→pass | 3,166 | 1,792 | -43% | 1 | 1 | 0% | 526 | 1,051 | +100% | 0 | 0 | — |
case-22 | pass→pass | 11,070 | 5,259 | -52% | 1 | 1 | 0% | 2,157 | 1,907 | -12% | 0 | 0 | — |
case-07 | pass→pass | 3,751 | 2,203 | -41% | 1 | 1 | 0% | 655 | 1,189 | +82% | 0 | 0 | — |
case-08 | pass→pass | 8,458 | 5,120 | -39% | 1 | 1 | 0% | 1,530 | 1,805 | +18% | 0 | 0 | — |
case-09 | pass→pass | 7,994 | 2,055 | -74% | 1 | 1 | 0% | 1,558 | 1,155 | -26% | 0 | 0 | — |
case-10 | pass→pass | 4,645 | 1,745 | -62% | 1 | 1 | 0% | 879 | 1,090 | +24% | 0 | 0 | — |
case-11 | pass→pass | 3,058 | 1,723 | -44% | 1 | 1 | 0% | 555 | 1,073 | +93% | 0 | 0 | — |
case-12 | pass→pass | 9,840 | 8,843 | -10% | 1 | 1 | 0% | 2,030 | 2,747 | +35% | 0 | 0 | — |
case-13 | pass→pass | 8,550 | 8,365 | -2% | 1 | 1 | 0% | 1,503 | 2,537 | +69% | 0 | 0 | — |
case-14 | pass→pass | 5,948 | 5,373 | -10% | 1 | 1 | 0% | 1,179 | 1,774 | +50% | 0 | 0 | — |
case-15 | pass→pass | 10,964 | 8,976 | -18% | 1 | 1 | 0% | 2,001 | 2,413 | +21% | 0 | 0 | — |
case-17 | pass→pass | 2,168 | 1,435 | -34% | 1 | 1 | 0% | 357 | 991 | +178% | 0 | 0 | — |
case-18 | pass→pass | 7,089 | 3,934 | -45% | 1 | 1 | 0% | 1,452 | 1,591 | +10% | 0 | 0 | — |
case-19 | pass→fail | 4,261 | 2,061 | -52% | 1 | 1 | 0% | 708 | 1,188 | +68% | 0 | 0 | — |
case-20 | pass→pass | 10,130 | 7,086 | -30% | 1 | 1 | 0% | 2,045 | 2,208 | +8% | 0 | 0 | — |
case-21 | pass→pass | 7,220 | 6,787 | -6% | 1 | 1 | 0% | 1,240 | 2,065 | +67% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +5 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.