--- name: omarchy-iso description: Generate a bootable ARM64 Omarchy ISO from inside a running Omarchy ARM system (live ISO with squashfs + systemd-boot + installer). Use when someone wants an installable Omarchy ARM ISO image, a live/rescue ISO of their Omarchy machine, or asks how to turn the Parallels Omarchy ARM VM into redistributable install media. --- # Omarchy ARM ISO builder ## What this produces An El-Torito EFI-bootable **aarch64 ISO** (`omarchy-arm--aarch64.iso`, ~2 GB) built from a live Omarchy ARM system: ```text ISO9660 ├── EFI/BOOT/efiboot.img # FAT: systemd-boot BOOTAA64.EFI + Image + live initramfs ├── EFI/BOOT/BOOTAA64.EFI # (fallback copy) ├── boot/Image, boot/initramfs-live.img ├── omarchy.sfs # squashfs snapshot of the running system └── omarchy-arm-install.sh # installer (runs in the live session) ``` Booting it starts a live Omarchy session (squashfs + overlayfs); from there `sudo omarchy-arm-install /dev/sdX` partitions, extracts, and installs the bootloader. First boot of the installed disk runs Omarchy's own setup wizard. > Scope: machine-independent live/install media for UEFI-AArch64 VMs > (Parallels, UTM, QEMU) and ARM hardware with UEFI. Not an Apple-Silicon > bare-metal installer. ## Why not archiso `archiso` (the official Arch ISO tool) is x86_64-only and absent from Arch Linux ARM repos. This builder hand-rolls the equivalent for aarch64 with tools that *are* packaged (`squashfs-tools`, `libisoburn` for xorriso, `dosfstools`, `gptfdisk`, `busybox`), reusing the running kernel (all storage drivers built in) and systemd-boot extracted from the guest itself. ## Run it (from the host, via the MCP server or SSH) ```bash # 1. copy the builder + installer into the running guest scp iso/build-omarchy-arm-iso.sh iso/omarchy-arm-install.sh root@:/root/ # 2. build (15–30 min; squashfs dominates). Long timeout / nohup — poll, don't block: ssh root@ "nohup /root/build-omarchy-arm-iso.sh --ssh-key /path/to/test-key.pub > /root/iso-build.log 2>&1 &" ssh root@ "tail -3 /root/iso-build.log; ls -la /root/*.iso" # 3. fetch the ISO scp root@:/root/omarchy-arm-*.iso* ~/Downloads/ ``` `--ssh-key` injects a live-session root key (testing only — omit for release builds). The live initramfs writes it into the overlay (writable upper layer) just before `switch_root`, so the squashfs stays clean. Via MCP: `vm_exec` with `nohup … &` + `tail` polling (tool timeout caps at 300 s; the build outlasts any single call). ## Boot-test the ISO (host side, Parallels) 1. Scaffold a diskless VM from `templates/config.pvs.tmpl` (or clone the Omarchy ARM `.pvm`, delete its `.hdd` dir), set the CD-ROM `SystemName` to the ISO path and `Connected` to 1. Give it a **unique MAC** (never clone NIC identities — see `skills/omarchy-parallels` MAC trap). 2. `prlctl register ` + `open -a "Parallels Desktop" `. 3. Expect: `IsBootable=1` in `parallels.log`, systemd-boot menu, kernel+initrd read burst (~250 MB `[RH]`), live session on DHCP with SSH (if `--ssh-key` was used) → `omarchy.sfs` mounted from the optical device. 4. Screenshot proof: framebuffer read (`tools/get-screen.sh`) during boot, `grim` once Hyprland owns DRM (see `skills/omarchy-parallels`). Firmware notes (verified the hard way): xorriso 1.5.8 writes El Torito sector-count `0` for `-no-emul-boot` and ignores `-boot-load-size`, which Parallels reports as `IsBootable=0`. The builder therefore runs `iso/hybridize.py` after xorriso: it writes a protective MBR + GPT whose ESP partition points at the FAT image *inside* the ISO (Debian/Ubuntu ARM layout), so strict firmwares boot the GPT path. Never use xorriso `-dev` mode on the output — it **destroys the El Torito catalog** ("set to be discarded"). ## Installer contract (`omarchy-arm-install`) - Args: target whole-disk device + `--hostname`. `--yes` still requires the device basename (`--yes sda`); a bare `--yes` is rejected. Refuses the live boot device. Installed cmdline has no `mitigations=off` and no `tryomarchy.ssh_access`. devices and the live boot device. - Layout: 1 GiB ESP (`ef00`) + rest ext4 (`8300`); `bootctl install` for AArch64; loader entry reuses the proven `root=UUID=… rootwait` combo. - Fresh identity: new fstab/hostname, empty `machine-id`, host SSH keys deleted (regenerated by `sshdgenkeys.service`), live keys dropped. - Does NOT create users — first boot runs `omarchy-provision-owner`. ## Failure modes | Symptom | Cause | Fix | |---|---|---| | `mksquashfs` stalls for 30+ min, output frozen | xz `-Xbcj` on a RAM-constrained VM (fragment phase, memory pressure) | `--comp gzip` (builder flag); keep xz for release builds on bigger machines | | Build dies at the mksquashfs line | `pipefail` + mksquashfs non-zero exit on unreadable pseudo-files | builder logs to file and validates the artifact (`unsquashfs -s` + leak grep) instead of trusting the exit code | | `/proc`, `/run` files *listed* during squash | exclude patterns wrong | paths must be absolute (source is `/`); list **both** the bare dir and `dir/*` (`/run` **and** `/run/*` — the bare form alone was verified insufficient for `/run`) | | Pseudo-fs content inside the `.sfs` | missing bare-dir exclude | builder aborts if `unsquashfs -l` shows `proc|sys|dev|run|tmp|mnt|media` under the root | | `pkill -f ` kills your own SSH session | the remote shell's cmdline contains the pattern | use a `[b]racket` self-excluding pattern, or `pgrep` first | | Build intermediates vanish after guest reboot | `/tmp` is tmpfs | builder works in `/var/tmp/iso-build` (persistent; excluded from the snapshot) | | Live boot can't find ISO (`no ISO device found` → rescue shell) | CD not attached as first optical, or virtio-blk vs sr naming | pass `iso_dev=/dev/sr0` (or the right node) on the loader command line (`e` in systemd-boot) | | Live boot mounts the build machine's disks | fstab from snapshot applied | builder already empties `/etc/fstab` in the overlay upper — if you customized, check `/init` | | Installed system panics on root mount | AHCI/enumeration race | the generated entry includes `rootwait` — keep it | | `bootctl install` fails in live env | ESP not mounted at the `--esp-path` | installer mounts ESP at `$MNT/boot` first — rerun | | Release ISO starts sshd or writes `/dev/sda` | default boot entry had `tryomarchy.ssh_access=1` (starts sshd) and `live_debug=1` (writes breadcrumbs to `/dev/sda` and streams kmsg to 10.211.55.2) | those flags are off unless the ISO was built with `--debug`. Do not publish a `--debug` ISO | | Live desktop looks unthemed or missing the bar/GTK theme | `/home` is excluded, so live init restores `/etc/skel`. Skel has no `theme.name`, and the shell/GTK theme/app defaults are applied by `omarchy-provision-user`, not by copying files | live `/init` must run `omarchy-provision-user --first-install` as the autologin user with `OMARCHY_THEME_HEADLESS=1` and `OMARCHY_SETUP_CONTEXT=iso-chroot` before `switch_root`. Hyprland's autostart then runs `omarchy-provision-first-run` (user units, welcome) once the session bus exists | | ISO boots on VM but not bare-metal USB | El Torito only; no isohybrid/GPT-ESP appendage | burn with a tool that synthesizes GPT+ESP, or extend the builder with a `--hybrid` xorriso `-append_partition` step (future work) | ## Ethics & legal The ISO contains Arch Linux ARM packages + Omarchy (its own licenses) plus the user's installed packages. Do not redistribute an ISO containing personal data — build release ISOs from a clean snapshot (`/home/*` is excluded by default; review the exclude list in the builder first).