schemactl
framework‑agnostic database schema evolution tool for Python
schemactl is a next‑generation database migration tool built on top of SQLAlchemy metadata and Alembic autogeneration.
Unlike traditional migration tools, schemactl is designed as a schema evolution engine, not just a migration runner. It is architecture‑first, deterministic, and ready to integrate with LLMs, agents, and autonomous workflows.
Why schemactl?
Most migration tools are:
- framework‑coupled
- imperative and manual
- hard to reason about at scale
- unfriendly to AI‑assisted workflows
schemactl takes a different approach:
- Framework‑agnostic – works with pure SQLAlchemy
- Metadata‑driven – schema is the single source of truth
- Diff‑based – migrations are generated from real schema changes
- Deterministic – reproducible and auditable
- AI‑ready – designed for LLM review, risk analysis, and human‑in‑the‑loop control
Core Concepts
Schema as Code
Your SQLAlchemy models (metadata) define the desired state of the database. For example, in app/models.py:
from sqlalchemy import Column, Integer, String, DateTime, Boolean
from sqlalchemy.orm import declarative_base
from datetime import datetime
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
email = Column(String(255), unique=True, nullable=False)
username = Column(String(100), unique=True, nullable=False)
created_at = Column(DateTime, default=datetime.utcnow)
is_active = Column(Boolean, default=True)
schemactl compares this metadata against the actual database schema and generates migrations automatically.
Evolution, Not Just Migration
Instead of thinking in terms of "apply SQL files", schemactl models:
- schema diffs
- schema versions
- schema state
This enables future features like:
- automated rollback planning
- migration safety scoring
- AI‑assisted reviews
- policy enforcement
Installation
pip install schemactl
CLI Overview
schemactl --help
Planned commands:
schemactl new # generate a new migration from metadata diff
schemactl up # create DB (if needed) and apply pending migrations
schemactl create # create the database
schemactl drop # drop the database
schemactl migrate # run pending migrations
schemactl rollback # rollback the last migration
schemactl down # alias for rollback
schemactl status # show migration status
#schemactl dump # dump schema.sql
#schemactl load # load schema.sql
schemactl wait # wait for DB readiness
Usage
1. Generate a Migration
To generate an empty migration file:
schemactl new --message add_users_table
To auto-generate a migration based on model changes, use the --auto flag and specify the path to your models:
schemactl new \
--message create_initial_tables \
--auto \
--models app.models
The command generates a new migration file:
migrations/
└── 20251215_create_initial_tables.sql
The content of the generated file will look like this:
-- migrate:up
-- Auto-generated migration: create_initial_tables
CREATE TABLE users (
id SERIAL NOT NULL,
email VARCHAR(255) NOT NULL,
username VARCHAR(100) NOT NULL,
created_at TIMESTAMP WITHOUT TIME ZONE,
is_active BOOLEAN,
PRIMARY KEY (id),
UNIQUE (email),
UNIQUE (username)
);
-- migrate:down
-- Rollback: create_initial_tables
DROP TABLE users;
2. Apply Migrations
schemactl up
What happens:
- Creates the database if it does not exist
- Ensures the
schema_migrationstable exists - Applies all pending migrations in order
- Records applied revisions deterministically
Project Structure
.
├── schemactl/ # Main package source
│ ├── cli.py # CLI commands
│ ├── services/ # Business logic and services
│ │ └── migration.py
│ │ └── model_loader.py
│ ├── adapters/ # Database and Alembic adapters
│ │ ├── alembic.py
│ │ └── database.py
├── migrations/ # Generated migration files
├── tests/ # Unit and integration tests
├── pyproject.toml # Project configuration (Poetry)
└── poetry.lock # Poetry lock file
This structure follows Clean Architecture and keeps infrastructure concerns isolated.
Design Principles
- Architecture first, code second
- Prefer declarative over imperative
- Explicit state tracking
- Simple core, extensible edges
Status
⚠️ Early development / experimental
APIs may change. Migration format is not yet stable.
License
MIT
Contributing
Contributions are welcome, especially in:
- migration safety
- rollback logic
- Async / cloud databases
Design discussions > code dumps.
Metadata
Release files for schemactl 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| schemactl-0.2.1.tar.gz | 18.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| schemactl-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 38.0 kB
Release files / schemactl-0.2.1.tar.gz
| Download URL | schemactl-0.2.1.tar.gz |
|---|---|
| Size | 18.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9577aec627269ddaf2c9b61f3e0122f8db792fcaa55996080ffe8ade4aa1f921
|
|
BLAKE2b-256 checksum How to use checksums |
2f3884d94a62c47eea64b97f7538ec89245c6639c451f4803b82d629a19cd290
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|
Release files / schemactl-0.2.1-py3-none-any.whl
| Download URL | schemactl-0.2.1-py3-none-any.whl |
|---|---|
| Size | 19.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ae7b69f72ce9b3df41c84e7b1d41558b0cb6a4fed82b692a91159c1af4067194
|
|
BLAKE2b-256 checksum How to use checksums |
ca6c4f31a141f7f6f4a3c65ac356cb0698209fbfe19b18c5eb42a2f8caa778f4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|