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-ready
  • install.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.”

← Back to README