index
The Apple Silicon (Asahi Linux) installer path for TunaOS-family bootc images — and anyone else's (Dakota, Bluefin, Bazzite): a macOS-driven install flow for M1/M2 Macs.

Every frame is rendered in CI from the real SwiftUI views — see the step-by-step walkthrough.
Architecture (see docs/DESIGN.md): instead of one
installer payload per variant×desktop, we ship one minimal bootstrap
payload whose first boot runs fisherman
to bootc install the image ref the user picked in the macOS app. The catalog
is just registry refs (bonito:gnome-asahi, …), so a new variant needs no
installer change — but a ref must pass the Asahi golden-manifest harness
before it is offered, and "appears without touching the installer" must never
be read as "appears without being verified."
As of 2026-07-30 only bonito and grouper pass (36/36 each); the other six
promoted *-asahi tags would leave a Mac unbootable
(tunaOS#776). The catalog
is an explicit allowlist: every CatalogEntry carries a verified field
(false by default), and the macOS app only offers entries where it is
true. The shipped catalog.json includes both bonito and grouper,
marked verified: true. Adding a new variant requires both the image and a
passing harness sweep — the field is the gate. That gate is currently
hand-maintained rather than CI-generated from harness results
(#70); the
harness sweep itself (#41)
that produced the two verified entries above is closed.
Status
- Design (docs/DESIGN.md)
- D0 scaffold:
scripts/make-payload.sh+build-payload.yml— package any asahi-capable bootc image as an asahi-installer zip +installer_data.json(wired with R2 upload step fordownload.tunaos.org/asahi) - D0 validated against a real asahi image (
bonito:gnome-asahi, tunaOS#774) - D1 first-boot fisherman agent config (
install-config.json→ unattendedbootc install) - D2 asahi-installer
--jsonmachine mode (upstreamable) - D3 macOS app (SwiftUI, wraps the asahi-installer Python backend)
- D4 recoveryOS walkthrough UX, LUKS, Wi-Fi handoff (RecoveryWalkthroughView QR & instructions; LUKS fail-closed #20/#47; Wi-Fi prompt at first boot #46)
Development & testing
Contributor workflow, code style, branch conventions and the full local test matrix live in CONTRIBUTING.md. The short version:
shellcheck -S warning scripts/*.sh components/*/*.sh # lint, as CI runs it
sudo ./scripts/selftest.sh # payload + installer_data.json contract
./scripts/test-backend-contract.sh # pinned asahi-installer --json contract
./components/bootsahi-agent/test-agent.sh # install-config.json -> recipe.json
cd macos-app/Bootsahi && swift build -v && swift test -v
What's tested and what it proves
The project distinguishes two claims that are easy to conflate (see #27):
| Claim | Test | What it proves |
|---|---|---|
| "A payload boots" | test-payload.sh + test-boot-payload.sh | The kernel, DTBs, modules, and U-Boot EFI chain work. Any asahi-capable image passes this — it proves the packaging, not the product. |
| "The bootstrap handoff is green" | test-agent.sh + test-agent-disk.sh + test-agent-install.sh | The agent generates a valid recipe, the recipe passes real fisherman validate, and a real bootc install succeeds end-to-end (canaries on ESP / neighbour / bootstrap / target). |
| "The bootstrap image contains everything it needs" | test-bootstrap-contents.sh | Static verification: bootsahi-agent, enabled unit, fisherman, cosign, jq, nmcli, blkid — all present and accounted for. Also gates a negative fixture (agent removed → must fail). |
| "The actual bootstrap image boots" | test-bootstrap-boot.sh (opt-in) | Build, package, and boot the repo's own bootstrap under qemu+U-Boot. The deepest fidelity achievable without Apple hardware. Needs aarch64 + qemu + u-boot-qemu. |
Payload layout & installer_data.json schema modeled on
fedora-asahi kiwi-descriptions and
nixos-asahi-package.
M1/M2 only — M3+ has no Asahi installer support yet.