v0.2.3
v0.2.3 — status page, ARM64 images, and a Docker image that actually boots
A packaging release: three changes, all for self-hosters — the last one because the first multi-arch images would have shipped dead.
Docker images were dead on arrival — fixed (b642f3b)
The new verify job executes the merged multi-arch image on a real arm64 runner before a release is called done, and its very first run caught this: every image published before now exited 127 at boot — error while loading shared libraries: libfontconfig.so.1. The screenshot feature's font enumeration links fontconfig/freetype dynamically and debian:bookworm-slim ships neither. Nobody had ever run a pushed image (the hosted instance runs the bare binary), so it had never surfaced. The runtime stage now installs libfontconfig1, and ldd in CI confirms every dynamic library resolves.
Status page at / and /status (03d5602)
Opening http://<host>:8089/ in a browser now serves a real page instead of a 404: version, uptime, live session count, capability chips, and the endpoint table — server-rendered, no client JS, no external assets, works on an offline LAN box. Agents keep using /health and /doctor; /status is the canonical alias.
This is what Umbrel's app store requires of an install ("must open to a web UI / status page"), and honestly it was overdue for plain self-hosting too. Uptime and the session readout are pinned by a smoke test.
Multi-arch Docker images: amd64 + arm64 (9e0dfbf + d6fbda3)
Docker images now ship as multi-arch manifest lists for linux/amd64 and linux/arm64 — Raspberry Pi 4/5 and ARM NAS boxes can pull and run them directly. Each architecture builds natively on GitHub's free arm64 runners (cross-compiling the V8 + BoringSSL stack under QEMU costs an hour; native builds take ~12 min), a merge job stitches the per-arch tags into one manifest per release tag, and the verify job then boots the merged image on arm64 as user 1000 with the cookie store bind-mounted — the exact runtime shape Umbrel installs use — checking /health, the status page, and that the cookie store is written under the mounted data dir.
ghcr.io/yinnho/aginxbrowser and docker.io/yinnho/aginxbrowser, tags 0.2.3 / 0.2 / latest.
Smaller notes
SessionManager::session_count()— live session readout for the page (afterevict_expired)- Smoke test for the status page (
status_page_serves_html_at_root) - CI fix en route: the manifest-merge job was missing its registry login (401 from GHCR on first dry-run)