OpenRiot v6.5 — Ghost in the Shell
“The installer is a tool. The first boot is a promise. The login message is a dare.” — Ancient OpenBSD proverb, probably written on a sticky note inside a ThinkPad battery compartment
Release Overview
OpenRiot v6.5 rebuilds the installer image from first principles after discovering that the previous approach was, technically speaking, a lie.
v6.4’s image appeared to work — it burned, it booted, it installed — but the
tarball it injected was empty. The updateCache() function moved (not copied)
the repository to a cache directory with os.Rename(), leaving workDir/repo
stripped bare before copyDir() could ship it into the installer. The resulting
image installed packages and set passwords, then handed the user a shell with
no OpenRiot code on the disk. It was OpenBSD in a costume.
v6.5 fixes this by removing the repository from the installer entirely. It
ships offline package installation and a first-login welcome message that
dares the user to run curl setup.sh. The math finally adds up.
Total changes: image builder re-architected, lock screens refreshed, lock screens refreshed again, polybar cleaned, power management made intelligent.
💾 Image Builder Re-Architected (make image)
The Problem: install.conf on the install media filesystem is dead code.
autoinstall(8) only reads response files from bsd.rd’s built-in RAM disk or
via HTTP fetch during netboot. A file named install.conf on the ISO root is
never scanned. We were cargo-culting a mechanism that does not exist.
Meanwhile, updateCache() used os.Rename() instead of copyDir(), silently
destroying the repository before packaging. The tarball contained 800MB of
packages and nothing else. It “fit under 2GB” because it was hollow.
The Fix:
site79.tgz as Custom Install Set
OpenBSD’s install.site(5) documents the only reliable mechanism for running
custom code during installation: ship a tarball named site79.tgz alongside the
standard sets in 7.9/amd64/, append it to index.txt, and let the installer
extract it automatically. This is what we now do.
The tarball contains:
openriot/packages/snapshots/amd64/*.tgz— all 68 packages, offline-readyinstall.site— post-install script (runs in chroot of the target system)etc/motd— custom MOTD
Notably absent: the OpenRiot Git repository. Including .git/, Locked/,
backgrounds/, and assets/ pushed the tarball past 1.3GB, which with the base
image exceeded the 2GB practical limit. The repository is fetched after first
login instead.
No Autoinstall, No Lies
install.conf has been removed entirely. The user answers the standard OpenBSD
prompts: disk, hostname, root password, user account, timezone. The only
manual steps.
First-Login Welcome
After installation, the user logs in and sees:
Welcome to OpenRiot!
All required packages have been pre-installed.
To complete setup and download the latest OpenRiot repository, run:
curl -fsSL https://OpenRiot.org/setup.sh | sh
This requires a working network or WiFi connection.
setup.sh clones the repo to ~/.local/share/openriot/, copies configs to
~/.config/, and runs openriot --install.
X11 Does Not Start on First Boot
xenodm is deliberately NOT enabled by install.site. The user sees a
console login. After running setup.sh, they can startx or let
OpenRiot enable xenodm.
This avoids the classic OpenRiot problem of X starting before configs exist and presenting a broken black screen that looks like a crash.
Stale Artifact Cleanup
make image now removes Build/Images/openriot.img, openriot.sha256, and
Build/work/site79.tgz before building. No more “wait, is this from yesterday
or did it actually work?”
Buffer Math That Finally Adds Up
| Component | Size |
|---|---|
Base install79.img |
~801MB |
| 68 packages in tarball | ~793MB |
install.site + motd |
~5KB |
| FFS minfree (5%) + metadata | ~100MB |
| Image buffer | ~350MB |
| Final image | ~1.97GB |
Previous buffer values (50MB, 100MB) were repeatedly insufficient because FFS
reserves 5% of capacity for minfree, cylinder group overhead is non-trivial,
and the base image partition already contains standard OpenBSD sets. 350MB is
the number that works.
🔒 Lock Screens Refreshed
The Problem: Lock screen images (Locked/ directory) needed more art.
The Fix: New lock screen collection: “Cleaner. Smaller. More Riot-y.”
The lock screen is the first thing you see when you return to your machine. It should not look like default wallpaper with a password box stapled onto it. The new collection is darker, sharper, and distinctly OpenRiot.
🖥️ Polybar Cleanup
The Problem: Polybar startup was inconsistent, workspace icons sometimes blank on first boot until manual restart.
The Fix: Delay bumped (3s to 5s, 8s to 10s). Workspaces populate correctly on first boot. The bar starts fully armed.
🔋 Runtime Power Management
The Problem: install.site hardcoded hw.perfpolicy=high and
hw.allowpowerdown=0 — desktop assumptions that destroyed laptop battery life and
broke the power button.
The Fix: Removed from install. Now runtime-managed in
source/display/hdmi.go:
- Docked + AC power:
perfpolicy=high, lid/power button disabled - Mobile / battery:
perfpolicy=auto, lid/power button enabled
Intelligent power management. Not desktop dogma.
🧮 Calculator Fix
The Problem: SUPER+= (calculator shortcut) had a path error that caused
intermittent failures.
The Fix: Finally fixed. SUPER+= opens the calculator every time.
🐟 Fish History Sanitizer
The Problem: Null bytes in fish history could corrupt the history file, causing the shell to truncate or misread entries.
The Fix: NULL byte sanitizer added. History survives.
🖼️ PNG Optimization
All PNGs in assets/, Locked/, and backgrounds/ crushed for size via
pngcrush. Smaller installer, faster boot, no visual degradation.
🧾 Files Changed
| File | Nature of Change |
|---|---|
source/imaging/build.go |
350MB buffer, df -h logging, stale comment fix |
source/imaging/site.go |
Removed repo copy, removed setupRepo()/updateCache() dead code, rewritten install.site |
source/imaging/runner.go |
Removed repo-cache cleanup |
source/imaging/site_test.go |
Updated assertions: curl setup.sh present, xenodm absent, openriot --install absent |
Makefile |
Stale artifact cleanup before make image |
docs/Image-Builder-Spec.md |
Rewritten: site79.tgz architecture, install.conf abandoned, under-2GB math |
docs/v6.5-Release-Notes.md |
This file |
Locked/ |
New lock screen collection |
🗣️ Final Words
“v6.0 was beauty. v6.1 was correctness. v6.2 was readability. v6.3 was choice. v6.4 was independence. v6.5 is honesty.”
v6.4 claimed to ship a complete OpenRiot installer. What it actually shipped was an OpenBSD installer with packages and a prayer. The repository was missing. The autoinstall mechanism we trusted does not exist on media filesystems. The buffer calculations were guesses.
v6.5 rips all of that out and replaces it with documented mechanisms only:
install.site(5) for post-install hooks, index.txt for set discovery,
pkg_add with full .tgz paths for offline package installation. No
cargo-culting. No guessing. No 1.3GB Git repositories in the tarball.
The result is an installer image that is under 2GB, actually installs
packages, sets up doas, configures fish, and then hands the user a console
with a dare: run curl setup.sh and finish the job.
It is not fully automatic. It is honest. It fits on a USB stick. It works in a cabin with no cell service. That is the point.
— The OpenRiot Crew
“An installer that lies is worse than no installer at all.”