# AGENTS.md Arch Linux ISO profile (archiso). Builds a live ISO with Hyprland desktop, end-4 dots-hyprland, and curated packages. Hosted on Gitea. ## Build & Test Commands ```bash # Build the ISO (repo root IS the profile directory) sudo mkarchiso -v -w work -o out/ . # Build AUR deps for end-4 (run locally before ISO build if localrepo/ is stale) ./localrepo/build-end4-deps.sh # build all ./localrepo/build-end4-deps.sh --quick # skip large AUR pkgs # Refresh localrepo DB after adding/moving .pkg.tar.zst files ./localrepo/update.sh # re-indexes existing packages ./localrepo/update.sh pkg1.pkg.tar.zst # add files, then re-index ``` `update.sh` also refreshes `airootfs/opt/localrepo/` (the copy that ships on the ISO), so run it after touching `localrepo/` before building. ## CI Checks (must pass before merge) - **ShellCheck**: all `.sh` files, plus extensionless bash scripts in `airootfs/usr/local/bin/` (by shebang), checked with `shellcheck -x -s bash` - **yamllint**: all `.yml`/`.yaml` files (relaxed config) - **packages.x86_64 syntax**: one package per line, no trailing whitespace, `[a-zA-Z0-9._@+\-]+` only - **Package repo check**: every package in `packages.x86_64` must be resolvable via `pacman -Si` in allowed repos (`cachyos`, `extra`, `multilib`, `chaotic-aur`), OR have a pre-built `.pkg.tar.zst` in `localrepo/`, OR appear in `localrepo/build-end4-deps.sh` ## Package Management **Three sources** contribute packages to the ISO: 1. **`packages.x86_64`** — main list, installed by mkarchiso. Must be in an allowed repo. 2. **`localrepo/*.pkg.tar.zst`** — pre-built AUR packages. The `local-aur` repo is configured in `pacman.conf` and picked up by mkarchiso automatically. 3. **`build-end4-deps.sh`** — builds end-4 AUR deps at build time. There is a **fourth source**: `customize_airootfs.sh` runs end-4's own `./setup install-deps` inside the image (as a throwaway `ii-builder` account), which resolves and compiles everything the dotfiles need (quickshell, MicroTeX, theming, fonts, ...). Those packages are installed in the live system, land in `pkglist.x86_64.txt`, and are harvested into `/opt/localrepo` so pacstrap can install them into the target without the network. **Important**: `localrepo/update.sh` auto-appends new package names to `packages.x86_64`. If you remove a package from `packages.x86_64` that exists in `localrepo/`, it will be re-added on the next `update.sh` run. ## Key Files | File | Purpose | |------|---------| | `packages.x86_64` | Live ISO package list (~402 packages) | | `profiledef.sh` | ISO metadata, compression, boot modes, build-stamp staging | | `pacman.conf` | Repos: cachyos → core → extra → multilib → chaotic-aur → local-aur | | `bootstrap_packages` | Minimal build-time packages (`base`, `arch-install-scripts`) | | `airootfs/root/customize_airootfs.sh` | Runs inside chroot during build: keyrings, skel dotfiles (incl. end4-pC), qsConfig patch, end-4 `install-deps`, package harvest, uv/font pre-warm | | `airootfs/root/.live-pacman.conf` | `/etc/pacman.conf` of the built image (adds `[local-aur]` = `file:///opt/localrepo`) | | `airootfs/usr/local/bin/alvin-install` | Installer: partitions, pacstrap, LUKS (systemd initramfs **or** experimental unl0kr + optional TPM2 unlock), user (fish shell), git identity + GitHub SSH keys, login manager (none/greetd/sddm/gdm) + autologin, optional sshd (default on), end-4 dotfiles (`--skip-alldeps`), boot | | `localrepo/build-end4-deps.sh` | Non-interactive AUR builds for end-4 dependencies | | `localrepo/update.sh` | Regenerates localrepo DB, syncs names to packages.x86_64, syncs `airootfs/opt/localrepo/` | | `localrepo/check-quickshell-pin.sh` | Tripwire: our quickshell pin and end-4's must include the Qt 6.12 fix and stay <45d old (`QUICKSHELL_PIN_MAX_AGE_DAYS` overrides) | | `.gitea/workflows/pin-check.yaml` | Runs the pin check weekly (Mon 06:00), on dispatch, and on pushes touching pins/`customize_airootfs.sh` | ## alvin-install (installer inside the ISO) Source: `airootfs/usr/local/bin/alvin-install` (~1,880 lines, **no `.sh` extension**). The airootfs overlay ships it as `/usr/local/bin/alvin-install` (mode `0755` forced in `profiledef.sh` `file_permissions`), and `/etc/motd` advertises it on the live medium. - **Invoke**: as root from the live session. Hard requirements: `gum` and UEFI — `check_prereqs` exits if `/sys/firmware/efi` is missing. Log: `/var/log/alvin-install.log` (copied into the target at the end; `ERR` trap prints the failing line). - **Structure**: `main()` runs 16 `screen_*` TUI functions (collect answers: welcome, keymap, network, disk, luks, unl0kr, filesystem, username, password, hostname, git, timezone, locale, login manager, sshd, summary) then a fixed order of `install_*` steps (partition → LUKS → format/mount → pacstrap → fstab → repos → timezone → locale → hostname → network → sshd → user → git/SSH → end-4 dots → mkinitcpio → bootloader → TPM/unl0kr → login manager → autologin → cleanup). Screens and install steps are independent — edit one without touching the other. An `EXIT` trap unmounts `$TARGET` and closes `cryptroot` on any exit. - **Package list**: `install_pacstrap` builds the *installed* system's list from the medium's `/run/archiso/bootmnt/arch/pkglist.x86_64.txt` (i.e. `pacman -Q` of the live ISO), so `packages.x86_64` changes flow into installed systems. It drops `PKGS_EXCLUDE` (`archiso mkinitcpio-archiso mkinitcpio-nfs-utils syslinux memtest86+`) plus names not resolvable in the live repos, then always appends hardcoded essentials (`base linux linux-firmware linux-cachyos networkmanager grub efibootmgr sudo git …`). - **Linting**: CI's shellcheck step picks it up by its bash shebang. Locally: `shellcheck -x -s bash airootfs/usr/local/bin/alvin-install` - end-4 quirks (`--skip-alldeps`, `yes i`, end4-pC re-copy) are in [Gotchas](#gotchas) below. ## Verify a single change locally (mirrors CI) ```bash shellcheck -x -s bash