Peregrine is getting an image-based installer. Instead of flashing a stock OS and running a provisioning script on top of it, you will flash a single pre-built image that has everything already inside. Boot twice, answer a few questions on first login, and the voice assistant is running. This work is close to landing.
Why this matters
The current setup path for Peregrine asks more of the builder than it should. You flash the Radxa Dragon Q6A with a stock Ubuntu image, SSH in, and run a configuration script that installs packages, downloads the NPU model and voice files, builds a Python virtual environment, and wires up the systemd services. It works, but it is a long sequence of steps that all have to go right, and the install time is significant. Every new board starts from zero.
The image approach flips that. A pre-built Ubuntu Noble 24.04 image is assembled once with everything already baked in: the NPU model, the Piper TTS voice, the wake-word models, the Python environment, and all the systemd services. Flashing a new board takes about ten minutes. The board does the rest.
What the new setup experience looks like
Flash the image, power on, and the board handles its own first boot automatically. It regenerates its SSH host keys (they are intentionally stripped from the image so every board gets unique credentials), expands the filesystem to fill the NVMe, and reboots cleanly. That takes about three minutes and requires nothing from you.
SSH in for the first time and an interactive setup wizard runs automatically. It walks through four steps:
- Password change. The image ships with a default credential for initial access. The wizard forces a change before anything else continues.
- MQTT configuration. Peregrine can connect to your Headwaters broker to report status and receive device commands. The wizard asks for the broker address, port, and credentials. Skip it and the assistant still works for general queries. It just won't have access to the rest of the TrailCurrent platform until you configure it.
- Static IP. Optional. If you want Peregrine on a fixed address, the wizard sets it up via
nmcli. Otherwise it stays on DHCP. - Hardware self-test. Runs through eight checks: the Jabra Speak USB mic, the speaker, a short tone playback, microphone capture and amplitude validation, the Qualcomm CDSP coprocessor state, the NPU genie server, the wake-word model, and the voice assistant service itself. Not required to complete, but good to run before you mount the module somewhere hard to reach.
The wizard creates a completion flag when it finishes. Re-run it any time by calling peregrine-first-login.sh directly. All site-specific config lives in a single environment file in the home directory and is never touched by future updates.
Closer to how Headwaters works
Headwaters has always used an image-based approach because the Raspberry Pi ecosystem made it the natural choice. Raspberry Pi Imager, write to SD, done. Peregrine runs different hardware and a different SoC, so the toolchain is different, but the principle is the same: ship a known-good image, let the board configure itself on first boot, and collect the site-specific details from the user in one focused step rather than across a sprawling install session.
Getting both full-Linux modules on the same conceptual path also makes the platform easier to reason about. The ESP32-based modules are flashed from the browser via the web flasher. The Linux modules get pre-built images. Both end up in a state you did not have to babysit into existence.
What is in the image
The build pipeline takes a stock Ubuntu Noble arm64 rootfs and runs it through 29 automated steps inside a QEMU arm64 chroot. By the time it comes out the other side, the image contains the full Llama 3.2 1B model staged for the Hexagon NPU, the Piper TTS voice, the openWakeWord models, the Python virtual environment with all dependencies pre-installed, and all five systemd services configured and enabled. The build includes two smoke-test checkpoints that verify critical artifacts are present and importable before moving on, so a failed model download or a broken dependency fails the build fast rather than producing a broken image that only fails on the board.
The output is a single flashable .img file. Flash it to the Q6A with flash.sh and you have a board in a known, reproducible state. Every board built from the same image is identical before first boot.
When it lands
The build pipeline is written and the image has been through initial validation. The remaining work is final testing of the first-login wizard across a few edge cases and documentation cleanup before tagging the release. When it ships, the Peregrine detail page will be updated with the new setup path. Watch the repo for the tagged release.