Bluefin Update Pipeline#
The update pipeline chains four layers: ujust update → bctl update → uupd → bootc. Each layer adds orchestration on top of the one below.
ujust update is the user-facing entry point. It:
- Exits if
uupd.serviceorrpm-ostreed-automatic.serviceis already running - Exits if layered packages are detected
exec bctl updatewhenbctlis in PATH — full handoff, no return- Falls back to
sudo bootc upgrade+ manual flatpak/brew steps whenbctlis absent
uupd Orchestration#
bctl update delegates to uupd, a Go daemon whose Update() function runs modules sequentially:
| Order | Module | Driver |
|---|---|---|
| 1 | System image | SystemUpdater → bootc upgrade |
| 2 | Brew | BrewUpdater → brew upgrade |
| 3 | Flatpak | FlatpakUpdater → flatpak update |
| 4 | Distrobox | DistroboxUpdater → per-user container update |
A file lock prevents concurrent runs. Each module's Enabled state is determined at startup — if BootcCompatible() returns false, uupd falls back to the rpm-ostree driver .
Failures from all modules are collected into a failures slice; if any exist, uupd sends a critical desktop notification via session.Notify listing the failed module names . There is no retry logic — a single transient network error fails the system module permanently for that run.
The --apply flag triggers systemctl reboot after a successful system update .
uupd ↔ bootc Integration#
SystemUpdater.Update() runs bootc upgrade --quiet --progress-fd 3 . An OS pipe is passed as fd 3 so bootc writes structured JSON progress there while stdout/stderr are captured separately . A goroutine calls bootcScan() on the pipe, parsing BootcProgress structs in real time.
Progress Stage Mapping#
The PROGRESS_STAGES table maps bootc task names to display labels and percentage ranges:
bootc task | Display label | Progress range |
|---|---|---|
pulling | Downloading | 0 – 80% |
importing | Importing | 80 – 90% |
staging | Deploying | 90 – 100% |
unknown | Loading | 100% |
Two JSON event types drive progress calculation :
ProgressBytes— proportional byte progress within the stage's rangeProgressSteps— proportional step progress within the stage's range
Update Pre-checks#
| Function | Command | Logic |
|---|---|---|
Check() | bootc upgrade --check | Returns true if output does not contain "No changes in:" |
Outdated() | bootc status --format=json | Parses booted image timestamp; true if >1 month old |
BootcCompatible() | bootc status --format=json | Returns false if booted or staged image has incompatible: true → triggers rpm-ostree fallback |
Known Failure Modes#
Transient GHCR Network Errors (no retry)#
bctl update / ujust update can fail immediately with "✗ System Image failed" when bootc encounters a transient EOF from the GitHub Container Registry blob CDN . Because uupd has no retry logic, a single network hiccup fails the entire system module. The progress bar reaches 0% and stops.
Workaround: Run sudo bootc upgrade directly and retry on failure — it works after transient CDN errors resolve.
False negative in --check: bctl update --check has been reported to return "System is up to date" even when bootc upgrade --check correctly reports a pending update . This is because the two tools call bootc upgrade --check via different code paths.
bluefin-lts Tag Mismatch (:lts → :stable)#
The image tag for Bluefin LTS changed from :lts to :stable when the project moved to the projectbluefin organization . Users already on the old image were auto-migrated via a systemd service. However, bctl reads image-info.json (baked at build time) for its channel display, while bootc status reports the live booted image ref. After migration, these can diverge — bctl shows stable/testing from the build-time tag while bootc status shows ghcr.io/projectbluefin/bluefin-lts:stable .
The correct current image references are:
ghcr.io/projectbluefin/bluefin-lts:stableghcr.io/projectbluefin/bluefin-lts-nvidia:stable
To switch manually: sudo bootc switch ghcr.io/projectbluefin/bluefin-lts:stable --enforce-container-sigpolicy
Key Files & Entry Points#
| File | Repo | Purpose |
|---|---|---|
just/update.just | projectbluefin/common | ujust update recipe — entry point, guards, bctl delegation |
cmd/update.go | ublue-os/uupd | Main Update() orchestrator — module init, sequential execution, failure reporting |
drv/system/system.go | ublue-os/uupd | SystemUpdater — bootc invocation, pipe setup, JSON progress parsing, pre-checks |
drv/flatpak/flatpak.go | ublue-os/uupd | Flatpak update driver |
drv/brew/brew.go | ublue-os/uupd | Homebrew update driver |
pkg/config/config.go | ublue-os/uupd | Config struct — BootcBinary defaults to /usr/bin/bootc, overridable via UUPD_BOOTC_BINARY env var |
Upstream References#
- bootc upgrade docs — canonical reference for
--progress-fd,--check, and JSON output format - bluefin-lts README — current image refs and migration guide