HydraIssues

Auto-update Qt app on darwin via agent's existing 6h loop
done improvement Project: hydraheadflatscreen Reporter: cederik 29 Apr 2026 18:50

Description

HydraExperienceNet.app is currently installed only at enrollment time (via the install-hydra-experiencenet step in recipes/hydraheadflatscreen-macos.yaml). Unlike the agent itself, which auto-updates every 6h via hydrarelease/pkg/updater, the Qt app drifts and needs manual reprovision to get new versions. Today turbo-pancake-76 is on a pre-v6.1.4 build while peppy-dumpling-32 is on v6.1.25 — exactly because peppy was hand-installed.

Proposed: have the agent (cross-platform) own ongoing Qt-app updates on darwin via build-tag-gated files, mirroring the existing moonlight_<os>.go pattern.

Files

pkg/qtapp/qtapp.go         // public API: CheckAndUpdate(ctx) error
pkg/qtapp/qtapp_darwin.go  // real implementation
pkg/qtapp/qtapp_windows.go // no-op stub
pkg/qtapp/qtapp_linux.go   // no-op stub

qtapp_darwin.go responsibilities

  • latestVersion() — GET https://releases.experiencenet.com/hydraexperiencenet/production/latest.json
  • installedVersion() — read agent-managed state file ~/.hydraheadflatscreen/qt_app_version. Not CFBundleShortVersionString; we observed peppy reads 6.1.0 from plist despite running v6.1.25, so the plist isn't a reliable source of truth on this codebase.
  • install(version) — download HydraExperienceNet-v<ver>.dmg, mount, cp -R over /Applications/HydraExperienceNet.app, xattr -cr, unmount, write state file. macOS allows hot-swap over a running bundle (inode replacement); the running process keeps old code until next launch.
  • coordinateRestart(ctx) — only pkill -f HydraExperienceNet when /api/v1/stream/status == idle. Defer to next idle window if streaming. Cap deferral at e.g. 24h to avoid stuck-on-old-version on always-streaming kiosks.

Wiring

Hook qtapp.CheckAndUpdate(ctx) into the same 6h tick that already drives the agent's self-update. No-op on Windows/Linux.

Recipe relationship

  • Recipe step install-hydra-experiencenet stays for first-time enrollment (initial bundle + state file seed).
  • After first run, agent owns the update lifecycle.
  • Cleanup follow-up: optionally remove the recipe step entirely once the agent's first-run path can install when bundle is missing.

Out of scope for this issue (file separately if useful)

  • Same auto-update treatment for Moonlight (also recipe-installed only today).
  • Surfacing Qt-app version into hydracluster's service_versions heartbeat so the central API doesn't need exec to learn it (see also: empty service_versions for Mac Minis today).

Why now

Today's task — bringing turbo + cheeky-cactus to peppy's v6.1.25 — has to be done via reprovision/exec because the loop doesn't exist. Once this lands, drift between heads becomes self-healing.