upgrade-stack
Upgrade assistant for ALL manually-managed Docker containers with dependency checking, shared infrastructure awareness, and breaking change analysis
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Upgrade assistant for ALL manually-managed Docker containers with dependency checking, shared infrastructure awareness, and breaking change analysis
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
| name | upgrade-stack |
| description | Upgrade assistant for ALL manually-managed Docker containers with dependency checking, shared infrastructure awareness, and breaking change analysis |
| context | fork |
When to use:
com.centurylinklabs.watchtower.enable: "false" (manually-managed)What this skill does:
What this skill does NOT do:
com.centurylinklabs.watchtower.enable: "false")Two stacks pin images and opt out of Watchtower (com.centurylinklabs.watchtower.enable: "false"):
the four Immich-stack services and the two Karakeep sidecars (karakeep-chrome,
karakeep-meili). Everything else — including Caddy (caddybuilds/caddy-cloudflare:latest)
and the Karakeep web app itself (karakeep:release, a floating tag that Watchtower
updates) — is Watchtower-managed and out of scope for this skill.
docker.io/valkey/valkey:9 (SHA-pinned)ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0 (SHA-pinned)immich database)ghcr.io/immich-app/immich-server:v3.0.3 / immich-machine-learning:v3.0.3-openvinomake immich-upgrade only pulls whatever the
compose file names, so upgrading means editing both tags in docker-compose.yml
first (server + ML must match), then running the target. This is deliberate: the
old release tag would have jumped 2.7.5 → 3.0.3 silently, and the compose now
records the running version.Bilder/immich/postgres, bring up a clean stack on the
old tag, restore a dump (see CLAUDE.md → "Immich database"). Take a verified dump
before every major bump.UPLOAD_LOCATION — Immich reads an empty
dir as a fresh install. We run the legacy /usr/src/app/upload container path while
upstream uses /data; that difference is fine and must be left alone. After any
upgrade, confirm the log line Successfully verified system mount folder checks.immich/releases/download/<tag>/docker-compose.yml for the old and new version is the
fastest way to see real structural changes (v2.7.5 → v3.0.3 turned out to be a valkey
digest bump and nothing else). Also grep our compose for a custom command/healthcheck
on immich_postgres — leftovers there break v3.0.1+, since both are now baked into
the image.Karakeep is a three-container stack. Only the two sidecars are pinned and
Watchtower-excluded — the web app floats on release and Watchtower updates it.
ghcr.io/karakeep-app/karakeep:release (floating tag, auto-updated 04:00)getmeili/meilisearch:v1.41.0/mnt/hdd/karakeep/meili) is a derived index
over Karakeep's source-of-truth SQLite DB — intentionally NOT restic-backed-up. The safe
upgrade path is usually stop → wipe the meili volume → start the new version → trigger a
Karakeep re-index, rather than fighting an in-place Meili migration.gcr.io/zenika-hub/alpine-chrome:124How to investigate a Karakeep bump (before changing pins):
docker/docker-compose.yml
at that git tag — it pins the exact Meili + Chrome versions that release was tested
against. Match our two pins to those values.Rollback:
release is floating — to roll back, pin karakeep to the prior image digest./mnt/hdd/karakeep/data) are restic-backed-up.# Check all manually-managed containers
/upgrade-stack --check-all
# Upgrade specific database (checks all dependents)
/upgrade-stack postgres # Checks Immich compatibility
/upgrade-stack redis # Checks Immich compatibility
# Upgrade specific application stack
/upgrade-stack immich # Checks Immich components + Postgres + Redis
/upgrade-stack karakeep # Reconciles pinned Meili/Chrome sidecars to the app release
# Check single container
/upgrade-stack immich_redis
/upgrade-stack immich_postgres
DATABASE TIER APPLICATION TIER
immich_redis ◄────────── Immich (Server + ML)
immich_postgres ◄────────── Immich (Server + ML)
karakeep-meili ◄────────── Karakeep (web app — Watchtower-managed)
karakeep-chrome ◄────────── Karakeep (web app — Watchtower-managed)
Key insight: Upgrading Postgres affects Immich; the Karakeep coupling runs the other way — the app auto-updates and you reconcile its pinned sidecars to match. Always verify before upgrading.
Never upgrade in this order:
ALTER EXTENSION vchord UPDATE; REINDEX INDEX face_index; REINDEX INDEX clip_index;release tag: Immich uses a rolling release tag, so check release notes before any pullcom.centurylinklabs.watchtower.enable: "false"Check for an app's own built-in backup before claiming a backup gap. Many apps
(Immich, Karakeep) dump their own DB on a schedule into a directory that is already a
restic source. Immich writes upload/backups/immich-db-backup-*.sql.gz nightly and keeps
14 — that, not the PGDATA dir, is the real backup. Seeing a live data directory inside a
restic source proves nothing either way: a raw copy of a running PGDATA is never
restorable, and its presence says nothing about whether a proper dump exists one
directory over. Look for the dumps before reporting on backup posture.
Verify a backup, never infer one. A file existing is not a backup. Confirm: it
decompresses (gzip -t), it is complete (pg_dump's trailing "dump complete" marker),
it is offsite (restic ls latest <path>), and its contents match the live DB (row counts
per table). Take a fresh verified dump immediately before any major bump — and state
plainly what was checked versus what is assumed.
docker-compose.yml (server + ML must match), commit and push, then make immich-upgrade — git pull + docker compose pull + recreate. The target pulls only what the compose names, so without the tag edit it is a no-op. Raw docker is hook-blocked; always go through the make target.# {Container/Stack} Upgrade Analysis
## Current State
- Container: [name]
- Image: [image:tag@sha256 or "custom local build"]
- Version: [extracted version]
- Watchtower: Excluded (com.centurylinklabs.watchtower.enable: "false")
## Latest Stable Version
- Version: [latest] (released [date])
- LTS: [version] (if applicable)
## Update Available
✅ Yes / ⏸️ Already latest / ⚠️ Custom version ahead
## Breaking Changes ([current] → [latest])
1. [description] — Migration required: Yes/No
## Shared Infrastructure Impact (if database)
Upgrading [database] affects:
├── [App 1] (requires [version range]) ✅/⚠️/❌
└── [App 2] (requires [version range]) ✅/⚠️/❌
## Upgrade Complexity
🟢 Low / 🟡 Medium / 🔴 High
## Recommended Action
- **Upgrade to [version]** / **Stay on current** / **Monitor [issue]**
## Pre-Upgrade Checklist
- [ ] Backup [database/volume]: `[command]`
- [ ] Read release notes: [URL]
## Upgrade Steps
[numbered steps]
## Rollback Plan
[steps]
## Verification Commands
[commands]
When containers with com.centurylinklabs.watchtower.enable: "false" are added or removed: