yay (yay-bin, AUR-only like calamares/bibata) republished to [breadway] via the same PKGBUILD + Forgejo workflow pattern, so users can reach the wider AUR beyond bakery's bread ecosystem. Disk encryption: Calamares' partition module already has LUKS support enabled by default, but the checkbox led nowhere — no cryptsetup on the live/target image, no mkinitcpio encrypt hook, no GRUB cryptodisk wiring. An encrypted install would partition fine and then never boot. Added cryptsetup, pinned luksGeneration to luks1 (GRUB doesn't support LUKS2 + Argon2id), and post-install.sh now detects an encrypted root (lsblk TYPE == crypt) and conditionally adds the encrypt hook + GRUB_ENABLE_CRYPTODISK + --modules="cryptodisk luks luks2" on both grub-install passes. No effect on a normal unencrypted install. Secure Boot: self-signed via sbctl (shipped in packages.x86_64). BOS can't ship a Microsoft-signed shim without going through Microsoft's own paid UEFI CA process, so post-install.sh enrolls BOS's own keys automatically only when the firmware is already in Setup Mode (sbctl status --json), signs the kernel/bootloader, and leaves it alone otherwise — sbctl's own pacman hook re-signs on every future kernel/GRUB update, no further wiring needed. Release signing: generated a dedicated Ed25519 "BOS Release Signing" key (not reused from anything else), stored as the GPG_PRIVATE_KEY Forgejo Actions secret. release-iso.yml now generates SHA256SUMS and a detached SHA256SUMS.asc signature alongside every ISO upload; public key committed at KEYS.asc with verification instructions in the README. README updated: fixed a stale "greetd + tuigreet" line (breadgreet since round 3), documented yay/encryption/secure-boot/verification.
11 KiB
BOS — Bread Operating System
An Arch-based, Hyprland desktop distribution that ships the bread ecosystem preconfigured. One Calamares install produces a themed, bootable Wayland desktop — no manual Arch bootstrap, no wiring up dotfiles, no per-tool bakery installs.
Design rationale and the btrfs/A-B roadmap live in DESIGN.md. This file is the practical overview: what's in the image, how to build it, and how to test it.
What you get
- Compositor: Hyprland with a native-Lua config (
hyprland.lua), curated keybinds, snappy animations, blur, and pywal-driven colours on a black base. - bread ecosystem, baked into
/etc/skelfrom bakery-managed binaries (no network needed at install time):bread/breadd,breadbar(status bar- notification daemon),
breadbox(launcher),breadcrumbs(Wi-Fi profiles),breadpad(notes/reminders),breadman, and thebakerypackage manager.
- notification daemon),
- bos-settings: a GTK4 control panel that configures every bread* app's config from a GUI (non-destructively), plus snapshot rollback and bakery updates. See below.
- Login: greetd + breadgreet (bread-ecosystem's own greeter, under
cage) → Hyprland session. - Boot splash: Plymouth
bostheme (logo + spinner, black background). - Theming: global dark across GTK3 (Adwaita-dark), GTK4/libadwaita
(
color-scheme: prefer-dark), and Qt (qt5ct/qt6ct Fusion dark); Papirus-Dark icons; Bibata cursor. - Apps: kitty, nautilus (+ gvfs), Zen browser, VLC, loupe, gnome-text-editor,
gnome-calculator, file-roller, with file associations wired in
mimeapps.list.yayships for AUR access beyond bakery's bread ecosystem +[breadway]. - Hardware: pipewire audio, NetworkManager, BlueZ + blueman, CUPS printing with avahi mDNS discovery, TLP power management, fwupd firmware updates.
- Resilience: btrfs + snapper + snap-pac + grub-btrfs snapshots on every pacman transaction; zram swap; ufw firewall (deny-incoming, mDNS allowed).
- Security: full-disk encryption (LUKS, via Calamares' built-in support —
cryptsetup + the matching mkinitcpio/GRUB wiring ship so an encrypted
install actually boots) and self-signed Secure Boot (via
sbctl, enrolled automatically at install time when the firmware is in Setup Mode).
Repo layout
bos/
├── Cargo.toml # workspace (members: bos-settings)
├── bos-settings/ # GTK4 unified settings app (Rust)
│ └── src/
│ ├── config/mod.rs # non-destructive toml_edit config layer
│ └── ui/{widgets,window,sidebar}.rs, ui/views/*.rs
├── iso/ # archiso profile
│ ├── profiledef.sh
│ ├── packages.x86_64 # live + installed package set
│ └── airootfs/ # files overlaid onto the image
│ └── etc/
│ ├── skel/ # default user dotfiles (hypr, kitty, gtk, …)
│ └── calamares/ # installer config + post-install.sh
├── packaging/ # in-house PKGBUILDs for AUR-only deps
│ ├── arch/ # bos-settings
│ ├── calamares/
│ └── bibata/
├── .forgejo/workflows/ # CI: build + publish packages to [breadway]
├── build-local.sh # native ISO build for this machine
└── DESIGN.md
Building the ISO
build-local.sh builds the image natively (no container) and bakes this
machine's bakery-installed bread binaries into /etc/skel:
sudo ./build-local.sh # release-quality (xz squashfs)
sudo FAST_BUILD=1 ./build-local.sh # fast dev iteration (zstd squashfs)
The ISO lands in out/bos-<date>-x86_64.iso. The script pins
SOURCE_DATE_EPOCH (reproducible UUIDs) and rewrites the [breadway] repo URL
to the Tailscale-reachable Forgejo registry for the build.
Why some packages are in-house
calamares, zen-browser-bin, bibata-cursor-theme, and yay-bin are
AUR-only. BOS keeps a PKGBUILD for each under packaging/ and republishes the
built package to the [breadway] repo via a Forgejo Actions workflow (built
on the hestia self-hosted runner, published with a scoped registry token).
bos-settings itself publishes the same way on a v* tag.
Verifying a release
Every tagged release ISO on the Forgejo releases
page ships alongside a
SHA256SUMS file and a detached signature SHA256SUMS.asc, signed by a
dedicated release-signing key (not reused from anything else):
5620 3B86 A110 695A E7F3 1093 4AF3 323D 678E B5E2
The public half is committed at KEYS.asc. To verify a download:
gpg --import KEYS.asc
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum -c SHA256SUMS
Testing in a VM
A reusable, GPU-accelerated launcher lives at ~/bos-vm/run.sh:
~/bos-vm/run.sh install # boot the ISO installer (target disk attached)
~/bos-vm/run.sh # boot the installed system from the disk
It uses KVM + -cpu host, 8 GiB / 8 vCPU, and virtio-vga-gl with
-display gtk,gl=on (virgl) — 3D acceleration is essential for a smooth
Hyprland session in QEMU. The disk lives on NVMe (not the tmpfs /tmp) to
avoid memory pressure.
bos-settings
bos-settings edits each bread* app's TOML non-destructively: it parses
the file with toml_edit, changes only the keys a view exposes, and writes it
back — preserving comments and any keys the UI doesn't model (calendar
passwords, saved-network passwords, model paths). Views:
| View | Config |
|---|---|
| bread | bread/breadd.toml — daemon, lua, modules, all adapters, events, notifications |
| breadbar | breadbar/style.css override |
| breadbox | breadbox/config.toml — launcher contexts |
| breadcrumbs | breadcrumbs/breadcrumbs.toml — settings, saved networks, profiles |
| breadpad | breadpad/breadpad.toml — settings, model + ollama, reminders, calendar |
| Snapshots | snapper list / rollback / delete |
| Packages | bakery installed list + updates |
| Hyprland | open config in editor + monitor list |
Build standalone:
cargo build --release -p bos-settings
cargo test -p bos-settings # includes config round-trip tests
The bread ecosystem at a glance
| Tool | Role | Launch |
|---|---|---|
bread / breadd |
Reactive automation daemon — normalises hardware/compositor signals into events dispatched to Lua modules | runs at login |
breadbar |
Top status bar (workspaces, clock, stats, tray) and the notification daemon | runs at login |
breadbox |
Application launcher | SUPER+Space |
breadpad |
Notes & reminders (AI-classified, optional CalDAV sync) | SUPER+U |
breadman |
Package-manager UI | SUPER+M |
breadcrumbs |
Wi-Fi profile state machine (location-aware) | CLI / BOS Settings |
bakery |
CLI package manager for the ecosystem | bakery |
bos-settings |
Unified GTK4 control panel for all of the above + snapshots + updates | SUPER+, |
Keyboard shortcuts
SUPER is the Windows/Cmd key. Press SUPER+/ at any time for this
cheatsheet in-session; first boot shows a short welcome (once).
| Keys | Action |
|---|---|
SUPER+Return |
Terminal (kitty) |
SUPER+Space |
App launcher (breadbox) |
SUPER+E / SUPER+B |
Files (nautilus) / Browser (zen) |
SUPER+U / SUPER+M |
breadpad / breadman |
SUPER+, / SUPER+/ |
BOS Settings / keybind cheatsheet |
SUPER+L / SUPER+N |
Lock / log out |
SUPER+Backspace |
Close window |
SUPER+F / SUPER+V / SUPER+T |
Fullscreen / float / toggle split |
SUPER+Shift+V |
Clipboard history |
SUPER+Tab |
Last window |
SUPER+Shift+S/C/P |
Screenshot region→file / region→clipboard / screen→file |
SUPER+arrows |
Move focus |
SUPER+Shift+h/j/k/l |
Move window |
SUPER+Shift+arrows |
Resize window |
SUPER+1..0 |
Switch to workspace 1–10 |
SUPER+Shift+1..0 |
Move window to workspace |
SUPER+[ / ] |
Previous / next workspace |
SUPER+left/right-drag |
Move / resize window with the mouse |
Known limitations
- GPUs: ships the generic Mesa stack — AMD and Intel work out of the box.
The NVIDIA proprietary driver is not included; NVIDIA users must install
nvidia/nvidia-utilsand set the usual Hyprland env vars after install. - Virtual machines: Hyprland needs GPU acceleration to be smooth. Use
virtio-vga-gl+-display gtk,gl=on(virgl); plain software rendering is noticeably laggy. - Wayland-first: X11-only apps run through XWayland; a few may misbehave.
- Secure Boot: self-signed only, via
sbctl— BOS can't ship a Microsoft-signed shim (that needs going through Microsoft's own paid UEFI CA process). Post-install enrolls BOS's own keys automatically, but only when the firmware is already in Setup Mode (no vendor keys installed yet); otherwise it's skipped and you can runsudo sbctl enroll-keys --microsoft && sudo sbctl sign-all -gyourself later (after clearing your firmware's existing keys, if any). The installer writes both an NVRAM entry and the removableEFI/BOOT/BOOTX64.EFIfallback either way. - Disk encryption: full-disk LUKS is available on the installer's "Erase
disk" page (Calamares' own checkbox) and on manually-created partitions —
BOS ships the matching
cryptsetup/mkinitcpio/GRUB wiring so an encrypted install actually boots (LUKS1, since GRUB doesn't support LUKS2 + Argon2id). - Snapshots assume btrfs: the snapper/grub-btrfs tooling expects the default btrfs subvolume layout the installer creates.
Recovery
An update broke something (system still boots): open BOS Settings →
Snapshots and roll back, or pick a pre-update snapshot from the GRUB
“snapshots” submenu at boot, then run snapper rollback from the booted
snapshot.
The system won't boot (broken GRUB / lost EFI entry):
- Boot the BOS ISO and open a terminal (
SUPER+Return). - Mount the installed root and EFI, then chroot:
mount -o subvol=@ /dev/sdXN /mnt mount /dev/sdXP /mnt/boot/efi # the EFI partition arch-chroot /mnt - Reinstall the bootloader (the same sequence the installer uses):
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=BOS --recheck grub-install --target=x86_64-efi --efi-directory=/boot/efi --removable --recheck grub-mkconfig -o /boot/grub/grub.cfg
Firmware shows “no boot device”: select EFI/BOOT/BOOTX64.EFI from the
firmware boot menu — the installer always writes that removable fallback.
Boot architecture notes
archiso keeps the kernel and initramfs outside the squashfs, so the installer
stages them explicitly: a shellprocess@kernel step copies the kernel + ucode
into the target /boot and writes a stock mkinitcpio preset before the native
initcpio module builds the initramfs. GRUB is not installed by Calamares'
bootloader/grubcfg modules (they leave the ESP empty in this layout) —
post-install.sh runs grub-install (NVRAM and --removable) +
grub-mkconfig instead, which is the sequence verified to boot.