feat: add .skills/db-migrations-schema-changes (#6476)
This commit is contained in:
committed by
Caren Thomas
parent
cf30e8f910
commit
9cbb8fa42a
111
.skills/db-migrations-schema-changes/SKILL.md
Normal file
111
.skills/db-migrations-schema-changes/SKILL.md
Normal file
@@ -0,0 +1,111 @@
|
||||
---
|
||||
name: DB migrations and schema changes
|
||||
description: >-
|
||||
Workflows and commands for managing Alembic database migrations and schema changes
|
||||
in the letta-cloud core app, including using uv, just, LETTA_PG_URI, and
|
||||
switching between SQLite and Postgres.
|
||||
---
|
||||
|
||||
# DB migrations and schema changes (letta-cloud core)
|
||||
|
||||
Use this skill whenever you need to change the database schema or debug Alembic
|
||||
migrations in `apps/core` of the letta-cloud repo.
|
||||
|
||||
This skill assumes:
|
||||
- Working directory: `apps/core`
|
||||
- Migrations: Alembic in `apps/core/alembic`
|
||||
- Python runner: `uv`
|
||||
- Helper: `just ready` for environment + DB setup
|
||||
|
||||
## Quick start
|
||||
|
||||
1. Ensure environment is ready:
|
||||
- `just ready`
|
||||
2. For Postgres migrations, set:
|
||||
- `export LETTA_PG_URI=postgresql+pg8000://postgres:postgres@localhost:5432/letta-core`
|
||||
3. Make your ORM/schema change.
|
||||
4. Autogenerate migration:
|
||||
- `uv run alembic revision --autogenerate -m "<short_message>"`
|
||||
5. Apply migration:
|
||||
- `uv run alembic upgrade head`
|
||||
|
||||
See `references/migration-commands.md` for exact commands and variants.
|
||||
|
||||
## Standard workflows
|
||||
|
||||
### 1. Add or modify a column (ORM-first)
|
||||
|
||||
1. Identify the ORM model and table.
|
||||
2. Update the SQLAlchemy model in `letta/orm/...`:
|
||||
- Prefer using mixins (e.g. `ProjectMixin`) when available instead of
|
||||
duplicating columns.
|
||||
3. Run `just ready` if dependencies or environment may have changed.
|
||||
4. Ensure `LETTA_PG_URI` is set if you want the migration to target Postgres.
|
||||
5. Autogenerate Alembic revision with `uv`.
|
||||
6. Inspect the generated file under `alembic/versions/`:
|
||||
- Confirm `op.add_column` / `op.alter_column` match expectations.
|
||||
7. Apply migrations with `uv run alembic upgrade head`.
|
||||
|
||||
Use this pattern for changes like adding `project_id` columns via `ProjectMixin`.
|
||||
|
||||
### 2. Data backfill / one-off data migration
|
||||
|
||||
1. Make sure the schema change (if any) is already represented in ORM + Alembic.
|
||||
2. Create a new Alembic revision **without** autogenerate (or edit an
|
||||
autogen file) and add Python logic in `upgrade()` that:
|
||||
- Uses `op.get_bind()` and SQLAlchemy Core/SQL to backfill data.
|
||||
3. Keep `downgrade()` simple and safe (ideally reversible).
|
||||
4. Run against Postgres with `LETTA_PG_URI` set, using `uv run alembic upgrade head`.
|
||||
|
||||
### 3. Fixing a bad migration
|
||||
|
||||
Typical cases:
|
||||
- Migration fails only on SQLite (ALTER constraint limitations).
|
||||
- Migration was generated while pointing at SQLite instead of Postgres.
|
||||
|
||||
Workflow:
|
||||
1. Identify the failing revision in `alembic/versions/`.
|
||||
2. If failure is SQLite-specific, prefer running migrations against Postgres by
|
||||
exporting `LETTA_PG_URI` and re-running upgrade.
|
||||
3. If logic is wrong, create a **new** migration that fixes the problem rather
|
||||
than editing an applied revision (especially in shared environments).
|
||||
4. For purely local/dev history, you can delete and regenerate migrations but
|
||||
only if no one else depends on them.
|
||||
|
||||
See `references/sqlite-vs-postgres-gotchas.md` for SQLite-specific issues.
|
||||
|
||||
### 4. Switching between SQLite and Postgres
|
||||
|
||||
Alembic picks the engine based on `letta.settings.DatabaseChoice` and
|
||||
environment variables.
|
||||
|
||||
General rules:
|
||||
- For local dev stateful runs, `just ready` handles baseline migrations.
|
||||
- For schema design and production-like migrations, prefer Postgres and set
|
||||
`LETTA_PG_URI`.
|
||||
|
||||
Workflow for Postgres-targeted migration:
|
||||
1. `export LETTA_PG_URI=postgresql+pg8000://postgres:postgres@localhost:5432/letta-core`
|
||||
2. From `apps/core`:
|
||||
- `uv run alembic upgrade head`
|
||||
- `uv run alembic revision --autogenerate -m "..."`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **"Target database is not up to date" when autogenerating**
|
||||
- First run `uv run alembic upgrade head` (with appropriate engine/URI).
|
||||
- **SQLite NotImplementedError about ALTER CONSTRAINT**
|
||||
- Switch to Postgres by setting `LETTA_PG_URI` and rerun.
|
||||
- **Autogenerated migration missing expected changes**
|
||||
- Ensure ORM imports and metadata (`Base.metadata`) are correct and that the
|
||||
changed model is imported in Alembic env context.
|
||||
- **Autogenerated migration has unexpected drops/renames**
|
||||
- Review model changes; consider explicit operations instead of relying on
|
||||
autogenerate.
|
||||
|
||||
## References
|
||||
|
||||
- `references/migration-commands.md` — canonical commands for `uv`, Alembic,
|
||||
and `just`.
|
||||
- `references/sqlite-vs-postgres-gotchas.md` — engine-specific pitfalls and
|
||||
how to avoid them.
|
||||
@@ -0,0 +1,72 @@
|
||||
# Migration commands (letta-cloud core)
|
||||
|
||||
Working directory for all commands: `apps/core`.
|
||||
|
||||
## Environment setup
|
||||
|
||||
- One-shot environment + DB setup:
|
||||
- `just ready`
|
||||
|
||||
## Postgres connection
|
||||
|
||||
Set the Postgres URI (adjust as needed for your env):
|
||||
|
||||
```bash
|
||||
export LETTA_PG_URI=postgresql+pg8000://postgres:postgres@localhost:5432/letta-core
|
||||
```
|
||||
|
||||
Alembic will log the effective URL (e.g. `Using database: postgresql+pg8000://...`).
|
||||
|
||||
## Alembic basics (with uv)
|
||||
|
||||
- Upgrade to latest:
|
||||
|
||||
```bash
|
||||
uv run alembic upgrade head
|
||||
```
|
||||
|
||||
- Downgrade one step:
|
||||
|
||||
```bash
|
||||
uv run alembic downgrade -1
|
||||
```
|
||||
|
||||
- Downgrade to a specific revision:
|
||||
|
||||
```bash
|
||||
uv run alembic downgrade <revision_id>
|
||||
```
|
||||
|
||||
- Generate new revision (autogenerate):
|
||||
|
||||
```bash
|
||||
uv run alembic revision --autogenerate -m "short_message"
|
||||
```
|
||||
|
||||
- Generate empty revision (manual operations):
|
||||
|
||||
```bash
|
||||
uv run alembic revision -m "manual_migration"
|
||||
```
|
||||
|
||||
## Typical workflow snippets
|
||||
|
||||
### Add/modify column
|
||||
|
||||
```bash
|
||||
cd apps/core
|
||||
just ready # optional but recommended
|
||||
export LETTA_PG_URI=postgresql+pg8000://postgres:postgres@localhost:5432/letta-core
|
||||
uv run alembic upgrade head # ensure DB is up to date
|
||||
uv run alembic revision --autogenerate -m "add_<column>_to_<table>"
|
||||
uv run alembic upgrade head
|
||||
```
|
||||
|
||||
### Re-run last migration after edit (local only)
|
||||
|
||||
```bash
|
||||
cd apps/core
|
||||
export LETTA_PG_URI=postgresql+pg8000://postgres:postgres@localhost:5432/letta-core
|
||||
uv run alembic downgrade -1
|
||||
uv run alembic upgrade head
|
||||
```
|
||||
@@ -0,0 +1,41 @@
|
||||
# SQLite vs Postgres gotchas (letta-cloud core)
|
||||
|
||||
## SQLite limitations
|
||||
|
||||
SQLite has limited support for `ALTER TABLE`, especially around constraints and
|
||||
foreign keys. In Alembic this often shows up as:
|
||||
|
||||
- `NotImplementedError: No support for ALTER of constraints in SQLite dialect...`
|
||||
|
||||
In `apps/core`, you may hit this when running migrations against SQLite that
|
||||
drop or change foreign keys or constraints.
|
||||
|
||||
### How to handle
|
||||
|
||||
- Prefer running schema-changing migrations against Postgres by setting
|
||||
`LETTA_PG_URI` and using:
|
||||
|
||||
```bash
|
||||
uv run alembic upgrade head
|
||||
```
|
||||
|
||||
- If you must support SQLite, use Alembic batch mode patterns, but for this
|
||||
project most complex migrations should target Postgres.
|
||||
|
||||
## Autogenerate differences
|
||||
|
||||
Running `alembic revision --autogenerate` against SQLite vs Postgres can
|
||||
produce different diffs (especially around indexes and constraints).
|
||||
|
||||
Recommendations:
|
||||
|
||||
- For production/real migrations, always autogenerate against Postgres.
|
||||
- If you see lots of unexpected index drops/adds, confirm which engine the
|
||||
migration is inspecting and rerun with Postgres.
|
||||
|
||||
## Engine selection reminder
|
||||
|
||||
- Engine is controlled by `letta.settings.DatabaseChoice` and environment
|
||||
(notably `LETTA_PG_URI`).
|
||||
- `just ready` will also run migrations; ensure your desired engine is set
|
||||
before relying on its database steps.
|
||||
Reference in New Issue
Block a user