Skip to Content

Migrations

AEGIS uses Alembic for database schema migrations, managed per-service.

Approach

Each service that owns database tables manages its own Alembic migration history. The base schema is defined in SQL files mounted into the PostgreSQL container and executed at startup.

The SQL init files create the foundational schema including Apache AGE setup, pgvector extension, and core tables. Alembic migrations handle incremental changes after initial setup.

Initial Schema

The Docker PostgreSQL container automatically runs the following SQL files on first boot:

FilePurpose
00-create-extension-age.sqlCreate the AGE extension
infrastructure/docker/postgres/init.sqlCore tables: audit logs, users, episodic memories, agents, skills, approvals, conversations, budget
infrastructure/docker/postgres/002_checklist_compliance_tables.sqlChecklist templates, filing checklists, compliance status, rule versions, filing rule snapshots
infrastructure/docker/postgres/007_entity_type_definitions.sqlEntity type system: type definitions, field definitions, relationship rules, RRC mappings

These scripts collectively:

  1. Create the aegis database and user
  2. Enable extensions: age, pgvector, uuid-ossp
  3. Create the oilgas graph in Apache AGE
  4. Create all base tables with indexes and constraints
  5. Set up audit trail triggers (prevent UPDATE/DELETE on audit_logs)

Standalone Deploy Migrations

For databases that already exist (and therefore won’t re-run init.sql), standalone idempotent SQL migrations live under infrastructure/deploy/migrations/ and are applied directly with psql:

FilePurpose
infrastructure/deploy/migrations/001_users.sqlCreate the users table (auth accounts) with the idx_users_email_lower case-insensitive unique index. Idempotent — safe to re-run.
psql "$DATABASE_URL" -f infrastructure/deploy/migrations/001_users.sql

Fresh databases get the users table from init.sql, so this migration is only needed to bring existing databases up to date.

Running Migrations

For services with Alembic configured:

# Navigate to the service directory cd services/{service-name} # Create a new migration poetry run alembic revision --autogenerate -m "description of change" # Run pending migrations poetry run alembic upgrade head # Check current migration status poetry run alembic current # Roll back one migration poetry run alembic downgrade -1 # View migration history poetry run alembic history

Migration Workflow

Creating a New Migration

  1. Make your model or schema changes in the service code.
  2. Run the autogenerate command to create a migration file:
cd services/{service-name} poetry run alembic revision --autogenerate -m "add compliance_status table"
  1. Review the generated migration in alembic/versions/. Autogenerate is not perfect — verify that the upgrade() and downgrade() functions are correct.
  2. Test the migration in both directions:
# Apply poetry run alembic upgrade head # Verify poetry run alembic current # Roll back poetry run alembic downgrade -1 # Re-apply poetry run alembic upgrade head
  1. Commit the migration file alongside the code changes.

Checking Migration Status

# Show current revision poetry run alembic current # Show all pending migrations poetry run alembic history --indicate-current # Show the SQL that would be run (without executing) poetry run alembic upgrade head --sql

Conventions

  • One migration per logical change — don’t bundle unrelated schema changes into a single revision
  • Descriptive revision messages — e.g., add compliance_status table not update schema
  • Always test migrations — run upgrade and downgrade before committing
  • Never modify existing migrations — if a migration has been applied by other developers, create a new corrective migration instead
  • Schema ownership — only the owning service should create migrations for its tables
  • Idempotent where possible — use IF NOT EXISTS guards in raw SQL within migrations

Adding Alembic to a New Service

If a service needs to manage its own tables, set up Alembic:

cd services/{service-name} poetry add alembic asyncpg sqlalchemy poetry run alembic init alembic

Configure alembic.ini with the database URL:

sqlalchemy.url = postgresql://aegis:aegis_local@localhost:5432/aegis

Update alembic/env.py to import your models for autogenerate support:

from your_service.models import Base target_metadata = Base.metadata

If using async database connections (which all AEGIS services do), you will need to configure Alembic’s env.py to use an async engine. See the SQLAlchemy docs on async migrations .

Resetting the Database

During development, you may need to start fresh. The most reliable way is to remove the Docker volume and recreate:

# Stop containers and remove volumes docker compose down -v # Recreate containers (init.sql runs automatically) docker compose up -d # Re-run seed scripts curl -X POST http://localhost:8003/seed cd services/orchestration-engine poetry run python -m orchestration.seed_skills poetry run python -m orchestration.seed_checklists poetry run python -m orchestration.seed_rules poetry run python -m orchestration.seed_demo_data

Running docker compose down -v destroys all data in PostgreSQL and Redis. Only use this in local development. Never run this against a shared or production database.

Troubleshooting

ProblemCauseSolution
alembic.util.exc.CommandError: Can't locate revisionMigration file deleted or corruptedReset Alembic version table: DELETE FROM alembic_version then re-run
relation already existsSchema was created by init.sql before AlembicMark migration as applied: poetry run alembic stamp head
target database is not up to datePending migrations existRun poetry run alembic upgrade head first
No changes detected during autogenerateModels not imported in env.pyVerify target_metadata is set correctly
Last updated on