The no-migration model
IMP does not use Knex migrations, Flyway, Liquibase, or any versioned migration tool for its application schema. Instead,npm run utils:initdb runs on every backend and worker boot.
The routine:
- Attempts to auto-create the database if it does not exist (requires
CREATEDBprivilege). - Creates the
vectorextension if absent. - Iterates over every known table schema and either creates the table (if missing) or adds any missing columns with
ALTER TABLE … ADD COLUMN IF NOT EXISTS. - Runs any one-time data migrations, each gated behind a column-existence check so they are no-ops after their first successful run.
- Creates the
adminanddefaultroles if they do not exist. - Creates the default admin user (
admin@exulu.com) if it does not exist. - Generates and logs a one-time API key.
First-boot bootstrap
On first boot, initdb creates:- An
adminrole with full write access to all permission keys. - A
defaultrole with limited read access. - A default admin user with email
admin@exulu.comand passwordadmin. - One API key scoped to
api@exulu.com.
admin password is written in plain text in this documentation and in the source code.
One-time data migrations
Old installs may have data in columns that have been superseded. These migrations are embedded directly ininitdb and run exactly once, gated on a column-existence check:
LiteLLM database
The LiteLLM proxy maintains its own schema in a separate Postgres database (set viaLITELLM_DATABASE_URL in config.litellm.yaml). On every boot, IMP runs a guarded prisma db push against that database to keep the LiteLLM schema up to date.
The push is skipped with a loud warning banner if:
LITELLM_DATABASE_URLpoints at the same host, port, and database name as the IMP application database.- The target database contains tables that do not start with
LiteLLM_(indicating it is not a dedicated LiteLLM database).
Per-context tables
IMP creates additional tables for each knowledge context (e.g.,projects_items, projects_chunks). These tables include a vector(N) column whose dimensionality comes from the dimensionality field of the configured embedding model in config.litellm.yaml.
Changing the embedding model after context tables exist requires migrating or recreating those tables — pgvector column dimensionality is fixed at creation time. There is no automated path for this today; back up and plan the migration manually.
Backup
IMP data lives in two places: the Postgres databases and the S3 bucket. Both require regular backups.Postgres
Back up both the IMP application database and the LiteLLM database:S3 bucket
All uploaded files — session attachments, knowledge documents, and audio recordings — live in theCOMPANION_S3_BUCKET. Back it up using your S3-compatible provider’s tooling. For MinIO: