Treat the schema like code
Production SQLite schemas evolve over time. The two questions you must answer up-front:
- How does a fresh install bring the database to the current version?
- How does an existing install upgrade safely from version N to N+1?
SQLite ships PRAGMA user_version — a 32-bit integer stored in the database header. Use it as your migration cursor. The pattern (used by Pippa's backend/store/conversations.py and a thousand others):
- On startup, read
PRAGMA user_version. - Apply each migration step from current to target inside a transaction.
- Bump
user_versionas the last statement of each migration.
Self-reference: Pippa's own SQLite store uses exactly this pattern — see
_init_db() in backend/store/conversations.py. The user_version increments every time we add a column or table; healing logic on every conversation GET ensures the schema and the JSONL ground truth stay aligned.