ADR 0023 — Update by installation type
- Status: Amended
- Date: 2026-10-23
- Amended by:
- Related: ADR 0002, ADR 0012, ADR 0014
- Restructured: 2026-10-25
Context
Section titled “Context”The dashboard had no way to update Imprint, and the sidebar showed Imprint unknown on Windows installs: the API looked for the CLI only on PATH or under a make all name, and the Inno installer leaves PATH unchanged by default.
imprint update overlaid the release archive onto the install directory. That suits install.sh / install.ps1 trees but not the other distributions:
- The Windows installer copies launcher scripts that the archive omits and records the installed version in the registry. Overwriting a running
imprint-ui.exefails midway. - The macOS
.pkginstalls into the root-owned/Applications/Imprint.app. - A container’s
/appis read-only for the service user, and a recreated container would discard any change. - Source checkouts with
make allbinaries passed the layout check. - Nothing restarted the dashboard server, so it kept serving the old code.
- The terminal prompt opened
/dev/tty, which does not exist on Windows.
Decision
Section titled “Decision”The CLI remains the single implementation of release resolution and installation. It classifies the running installation by layout: an Inno uninstaller in the install directory, the app bundle path on macOS, or an install script tree. Each type updates its own way, always after verifying the download against SHA256SUMS:
- Install script: overlay the archive as before, after moving each
bin/file to<name>.prev. This keeps a rollback copy and frees the names of running executables on Windows. Then re-run setup and restart a dashboard server started byimprint ui start. - Windows installer: stop the dashboard server, then start the release’s
setup.exedetached with/VERYSILENT /CLOSEAPPLICATIONS /RELAUNCH=1and a log indata/, and exit. The installer closes Imprint, replaces its files and provisions. Because/RELAUNCH=1was passed, it reopens Imprint. A silent update keeps the persisted install profile; a silent first install keeps ADR 0012’s CPU/no-LLM defaults. - macOS package: open the
.pkgin Installer, wait for it, confirm the installed version and restart the dashboard server. - Containers and source checkouts: these are reported as unable to update themselves, with the reason.
The CLI takes the queue lock, so an update never interrupts a running job.
imprint update --check --json reports current and latest versions, the update method or the reason none applies. The API caches that report for six hours. POST /api/update starts imprint update -y outside the server’s process group with its output in data/update.log. The dashboard shows an update notice in the top bar, explains the steps for the installation type, tails the log and waits until /api/version reports the new release.
The API resolves the CLI from its own installation first: bin/imprint[.exe], then a checkout build, then PATH. It caches the version only after a successful call.
Rejected alternatives
Section titled “Rejected alternatives”- The bare overlay for every installation. It breaks on the installer-managed layouts above.
- An Electron auto-updater. It would update the desktop shell but not the CLI, Python package or browser-only installs. Every desktop package wraps the same release tree, so one CLI path covers all of them.
- Running the update as a queue job. A job’s lifetime is tied to the server the update stops or restarts.
- Querying GitHub from Python. That would duplicate the Go release logic.
Consequences
Section titled “Consequences”- Installations older than this release must update once by the old route: the installer, the install script or
imprint update. - The dashboard contacts the GitHub releases API at most every six hours while it is open.
- A server not started by
imprint ui start, such as a foregroundimprint ui, is not restarted; the log asks for a restart. - On Windows the app window closes during an update and reopens when provisioning ends.
- On macOS the update needs the administrator prompt.
- Container users are told to pull a new image.
Invalidation conditions
Section titled “Invalidation conditions”- If a new distribution type appears, classification must give it an update method or report that it cannot update itself.
- If a self-updating desktop shell could also update the CLI, the Python runtime and browser-only installs, the Electron auto-updater rejected here could be reconsidered.
Validation
Section titled “Validation”- Go: unit tests cover version comparison including
git describebuilds, installation classification, the binary backup and flag parsing.imprint update --check --jsonwas run against the live releases API. - Python: tests cover the cached check, failure reporting, detached start in its own session, job and duplicate conflicts, and the endpoint’s refusals.
- Browser: tests cover the notice, the installer handover, the stopped updater with retry and the container explanation.
- Not yet observed: the Inno relaunch and profile-preserving provisioning need a native Windows update from one release to the next. The macOS
.pkghandover needs a native macOS run.