Multi-distro support: Fedora/RHEL, Arch, and openSUSE are now tier-1 supported alongside Debian/Ubuntu. Until v3.2.0, the install bootstrap and install.sh hardcoded apt-get and Debian-style package names (python3-venv etc.) — they'd hard-refuse on a fresh Fedora or Arch host even though every line of Aerodrome's actual runtime code (collector, server, notifier, classifier, SQLite layer, FastAPI service) is fully distro-agnostic and just runs as a systemd-managed Python process. The Debian assumption was concentrated in the install/uninstall surface only. v3.2.0 fixes that: the bootstrap now detects the host's package-manager family from /etc/os-release, picks the right install command, and translates per-family package names automatically. The four tier-1 families covered with explicit detection rules and verified install paths are Debian (incl. Ubuntu, Raspberry Pi OS, Mint, Pop!_OS, elementary, Neon, Kali, Parrot), Fedora (incl. RHEL, Rocky, AlmaLinux, Amazon Linux, Oracle Linux), Arch (incl. Manjaro, EndeavourOS, Garuda, Artix, CachyOS), and openSUSE (incl. Tumbleweed, Leap, SLES). Each tier-1 family was dogfooded on a fresh VM before this release shipped.
What you see as a non-Debian user: the same one-line curl install you'd use on Ubuntu now works on Fedora, Arch, or openSUSE without any flags. The bootstrap announces "Recognized Fedora/RHEL-family system" (or whichever) and proceeds. Step 1 of install.sh reports "Python3, pip, venv installed (via fedora package manager)" instead of just "installed" so you can see which family was detected. Everything downstream — virtualenv setup, systemd unit creation, sudoers rule, demo-mode synthetic feeder, switch-to-real wizard, in-app updater — works identically across families because all of it is systemd-and-filesystem operations that have always been distro-agnostic.
What you see as an existing Debian-family user: absolutely nothing. The Debian path is byte-equivalent to v3.1.2 — same apt-get update, same apt-get install python3 python3-pip python3-venv curl, same systemd unit, same sudoers rule. The new code branches only activate when the detected family is non-Debian. No behavior change, no surprises, no upgrade gotchas.
The detection logic: uses /etc/os-release's ID field first (specific) and falls back to ID_LIKE (derivative) if ID doesn't match a known value — so most downstream derivatives that set ID_LIKE correctly (e.g. Pop!_OS reports ID_LIKE="ubuntu debian") fall back to their parent family automatically without needing to be enumerated. The case statement covers ~20 distros explicitly across the four families. Anything else with systemctl AND one of apt-get/dnf/pacman/zypper on PATH falls to tier-2 (best-effort: prints a warning, prompts to continue, then uses whichever package manager it found). Tier-3 (hard refuse) only fires if systemd is missing OR no recognized package manager is present — covering Alpine, Void, Gentoo-without-systemd, and similar.
Per-family details (for the curious):
- Debian/Ubuntu —
apt-get update -qqthenapt-get install -y -qq. Packages:python3 python3-pip python3-venv curl unzip. venv is a separate package on Debian-family due to a longstanding split. - Fedora/RHEL —
dnf install -y -q. No explicit refresh step (dnf auto-refreshes on install in normal usage; older yum needed it but RHEL 7's yum is past EOL). Packages:python3 python3-pip curl unzip. The venv module is bundled into the mainpython3RPM, sopython3-venvdoesn't exist and isn't installed. - Arch —
pacman -Sy --noconfirm(refreshes the package index) thenpacman -S --needed --noconfirm(install if not already present). The package ispythonnotpython3on Arch — Arch standardized on Python 3 long enough ago that thepython3alias was dropped. Pip ispython-pip. Packages:python python-pip curl unzip. - openSUSE —
zypper --non-interactive refreshthenzypper --non-interactive install. Packages:python3 python3-pip curl unzip. Modern Tumbleweed and Leap 15.5+ bundle venv into python3.
The shared abstraction. The new pkg_detect(), pkg_install(), and pkg_refresh() functions are duplicated verbatim into bootstrap.sh, install.sh, and uninstall.sh rather than sourced from a shared library. This is deliberate, not accidental: the curl-installed bootstrap.sh runs from /tmp before any release zip is downloaded, so there's no shared library file it could source. ~70 lines of identical code in three files is honest cost; trying to be clever about it would mean either inline-from-zip (broken when there's no zip yet) or a separate downloaded helper (extra HTTP round-trip, more failure modes). The functions are also small and stable — package-manager command-line surfaces haven't changed in a decade, so the cost of duplication-drift over time is low. The shared logic includes the /etc/os-release parse, the family-detection case statement, the per-family install-command and package-name table, and the install/refresh wrappers.
Uninstaller now family-aware too. Pre-v3.2.0, uninstall.sh ended with a hint reading "Remove manually if desired: sudo apt remove python3-venv" — useful for Debian users, confusing for everyone else. v3.2.0 detects the family the same way and emits the right removal command per distro (sudo dnf remove ... on Fedora, sudo pacman -R ... on Arch, sudo zypper remove ... on openSUSE). The actual destructive work of the uninstaller — stopping and removing both systemd units, removing the sudoers rule, removing the install directory — was already distro-agnostic; only the trailing informational hint needed updating.
Behind the scenes — what's left as Debian-specific. Almost nothing. The Aerodrome runtime has no apt, dnf, pacman, or zypper references anywhere; the only code that knew about apt was the three install scripts. The optional ntfy-installer feature (ntfy_installer.py) was already distro-agnostic by design — it downloads the ntfy binary from GitHub Releases as a Go static binary rather than using any package manager. The systemd integration uses standard systemctl calls that work identically across all four families. The sudoers rule format (/etc/sudoers.d/aerodrome) is identical too. Python's venv, pip, and the FastAPI/uvicorn stack all work the same way regardless of which distro installed them.
What this enables next. With multi-distro support landed, the option of containerizing Aerodrome (Docker image, OCI compatible) becomes much more interesting as a separate-but-complementary deployment option — a container is essentially "one more 'distro' to support," and the architectural separation we now have (data plane distro-agnostic, install surface family-aware) is exactly what makes a container build straightforward. That's on the longer-term roadmap rather than scoped for v3.2.0; the multi-distro work here is the right foundation.