Step 0 — Load configuration
Check if /tmp/ops-suite-session/config.json exists:
- If yes, read it (pre-parsed by session-start hook).
- If no, read
${XDG_CONFIG_HOME:-$HOME/.config}/ops-suite/config.yaml(preferred) or the plugin'sconfig.yaml(legacy), parse it, and write to/tmp/ops-suite-session/config.jsonfor other skills to reuse. If neither exists, tell the user to run/ops-suite:configure(or copyconfig.example.yamlto~/.config/ops-suite/config.yamland fill in their values). Stop here.
Extract:
deploy.migration_tool— determines which adapter to loaddeploy.migration_command— the command to run migrationsdeploy.local_ports— local ports for port-forwarding to databasesorchestrator— for port-forward commandsenvironments— connection details for each environment
Also read the reference at references/commands.md (in this skill's directory).
Step 1 — Load adapter
Read the adapter file at adapters/{deploy.migration_tool}.md (in this skill's directory).
If the adapter does not exist, tell the user that the migration tool {deploy.migration_tool} is not yet supported and stop.
Step 2 — Determine target environment
If $ARGUMENTS contains an environment name, use it. Otherwise ask the user.
IMPORTANT: Always recommend running migrations on dev first before prod.
Step 3 — Identify pending migrations
Use the adapter's "list pending" command to check what migrations need to run. If there are no pending migrations, inform the user and stop.
Show the user:
- Migration file names
- What each migration does (read the migration files if accessible)
Step 4 — Establish database connection
The migration tool needs a database connection. This typically requires:
Port-forward to the database using the orchestrator:
kubectl --context={env.context} port-forward svc/{env.services.database.name} {deploy.local_ports.{env_name}}:{env.services.database.port} -n {env.services.database.namespace || env.namespaces.infra} &Note: Use
env.services.database.namespaceif defined — the database/pgbouncer may live in a different namespace thanenv.namespaces.infra.Credentials: First check if
env.services.database.credentials_fromis defined in config:- If
pod_env:<VAR_NAME>: retrieve from a running app pod:kubectl --context={env.context} exec {any_app_pod} -n {env.namespaces.apps} -- printenv <VAR_NAME> - Otherwise, use the adapter's "retrieve secret" command or ask the user. Never hardcode or display credentials in plain text.
- If
Set environment variables as required by the migration tool (from adapter).
Determine database name: If
service_databasesis defined in config, use it to resolve the correct database name for the target service and environment. Otherwise fall back toenv.services.database.default_db.
Step 5 — Confirm migration
ALWAYS ask for explicit confirmation before running migrations.
Display:
Ready to migrate:
Environment: {env_name}
Database: {env.services.database.default_db}
Pending: {count} migration(s)
Files: {migration_file_list}
This will modify the database schema. Proceed? (yes/no)
Step 6 — Run migrations
Execute the migration command from deploy.migration_command or the adapter's default command.
Capture both stdout and stderr.
Step 7 — Verify
After migration completes:
- Use the adapter's "check status" command to verify all migrations are applied
- Run a quick sanity query to confirm the database is accessible
- Check for any error output
Step 8 — Cleanup
- Kill any port-forward processes
- Unset any temporary environment variables
- Report the result
Output format
Migration Summary:
Environment: {env_name}
Database: {database}
Migrations: {count} applied
Status: {success/failed}
Applied:
- {migration_name_1}
- {migration_name_2}
Cleanup:
- Port-forward killed (PID {pid})