Reading the plan
- API:
GET /api/v1/apps/{name}/template-upgrade(read permission on the app). - CLI:
levelrail-cli apps upgrade-plan <app>. - Dashboard: the app Overview shows “Template update available” when the plan has changes.
What the planner compares
The deployed compose revision is compared with the current catalog template. The first template revision of the app, when it exists, is the baseline: a value that differs from the baseline is a user edit and is kept (keep_user). Without a baseline every differing value is treated as a user
edit, so nothing is ever overwritten.
Domains, resources and bind mounts are user-owned and never part of a plan.
Risk
none: nothing to do.low: patch or minor image moves only.medium: also env additions or updates, volume additions, port or healthcheck changes.high: a major or unclassifiable image change, a downgrade, removed env vars, a new or removed service, or any blocker.
automatic is true only when there are changes, no blockers and the risk is not high.
Applying an upgrade
- API:
POST /api/v1/apps/{name}/template-upgradewith{"accept_risk": true}(deploy permission), thenGET /api/v1/apps/{name}/template-upgrade/runfor progress. - CLI:
levelrail-cli apps upgrade <app> --yes(without--yesit only prints the plan). It follows the run;--no-waitreturns at once. - Dashboard: the Upgrade button next to the badge on the app Overview opens the risk diff and shows progress.
- MCP:
get_template_upgrade_planreads the plan; it never applies one.
- the plan has blockers (
upgrade_blocked), - the plan is high risk and
accept_riskis not set (upgrade_risk_unacknowledged), - a named volume of the app has no successful backup newer than the allowed age (
upgrade_backup_required, lists the volumes), - the app has services the template does not know (
upgrade_user_services), - another upgrade of the app is running (
upgrade_in_progress).