No description
Find a file
Breadway 70d4dd424b iso: enable bakery user units globally for later accounts
Bins live in /usr/local, so a later useradd no longer gets
~/.local/bin copies. systemctl --global enable the bakery
--user units (bake writes /etc/systemd/user/*.wants/, and
post-install + live-setup run the same enable) so first
login starts breadd, breadbox-sync, breadclipd, breadcrumbs,
and breadmill. Stock useradd -m copies skel (Hyprland +
bakery state). Rollback is still grub-btrfs.
2026-08-16 00:27:14 +08:00
.forgejo/workflows ci: install grub on the ISO builder 2026-08-15 23:47:03 +08:00
assets v0.4.0: branding refresh, breadpaper baked in, bos-settings 0.4.0 2026-06-18 14:50:44 +08:00
docs iso: bake bakery apps into /usr/local 2026-08-16 00:10:32 +08:00
dotfiles CI: stage bakery from signed stable index, drop bread-theme cargo build 2026-08-15 22:20:29 +08:00
iso iso: enable bakery user units globally for later accounts 2026-08-16 00:27:14 +08:00
packaging packaging/bibata: ship only the Bibata-Modern-Ice variant 2026-08-15 22:35:58 +08:00
scripts iso: enable bakery user units globally for later accounts 2026-08-16 00:27:14 +08:00
.gitignore CI: stage bakery from signed stable index, drop bread-theme cargo build 2026-08-15 22:20:29 +08:00
AGENTS.md iso: bake bakery apps into /usr/local 2026-08-16 00:10:32 +08:00
build-local.sh iso: enable bakery user units globally for later accounts 2026-08-16 00:27:14 +08:00
DESIGN.md CI: stage bakery from signed stable index, drop bread-theme cargo build 2026-08-15 22:20:29 +08:00
KEYS.asc Ship yay, wire up LUKS disk encryption, self-signed Secure Boot, release signing 2026-07-04 10:39:44 +08:00
LICENSE Add bakery.toml and packaging/arch to match bread ecosystem 2026-06-13 11:32:40 +08:00
README.md iso: enable bakery user units globally for later accounts 2026-08-16 00:27:14 +08:00

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.

This file is the product as the tree ships it. DESIGN.md is the original plan, kept as history — several of its sections (in-tree GTK bos-settings, bakery-at-post-install, A/B as if it were current) are not how the ISO works today.

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 /usr/local from bakery-managed binaries (no network needed at install time; per-user bakery state is seeded in /etc/skel): the bread/breadd automation daemon (bread-emit / bread-module-host when the stable bread release publishes them), breadbar (status bar + notifications), breadbox (launcher), breadclip (clipboard history), breadcrumbs (Wi-Fi profiles), breadpad/breadman (notes), breadpaper (wallpaper + theme), breadsearch (system search), breadmon (monitor layout TUI), breadshot (screenshots), bread-theme (the shared palette engine), breadhelp (onboarding + cheatsheet), bos-settings (control panel), and the bakery package manager. Most of those apps are zero-config on first boot; breadcrumbs networks are user-filled after install. See below.
  • breadlock (lock screen + greeter) is the one bread* app that ships as pacman, not bakery — it needs a root-owned PAM service.
  • bos-settings: a Tauri 2 + Svelte control panel (standalone bakery product, not a member of this repo). Configures every bread* app non-destructively, plus snapshots, bakery/pacman updates, and day-to-day machine administration.
  • Login: greetd + breadgreet (under cage) → Hyprland session.
  • Boot splash: Plymouth bos theme (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. yay ships for AUR access beyond bakery + [breadway].
  • Hardware: pipewire audio, NetworkManager, BlueZ + blueman, CUPS printing with avahi mDNS discovery, TLP power management, fwupd firmware updates. Mesa only — NVIDIA proprietary drivers are not included and NVIDIA is unsupported out of the box (see docs/hardware.md).
  • Resilience: btrfs + snapper + snap-pac + grub-btrfs snapshots on every pacman transaction; zram swap; ufw firewall (deny-incoming, mDNS allowed). A/B root swapping is not implemented. Recovery is a grub-btrfs reboot, not snapper rollback (GRUB pins rootflags=subvol=@). See docs/hardware.md.
  • Security: optional full-disk encryption is LUKS1 (GRUB cannot unlock LUKS2 + Argon2id). Secure Boot is self-signed Setup Mode only via sbctl — not a Microsoft-signed shim; enrollment is skipped unless the firmware is already in Setup Mode.

What ships vs what does not

Channel What
Bakery, required bakery, bread / breadd, breadbar, breadbox / breadbox-sync, breadcrumbs, breadpad / breadman, breadpaper, bread-theme, breadmon, breadsearch / breadmill, breadclip / breadclipd, breadshot, bos-settings, breadhelp (+ breadhelp content under /usr/local/share/breadhelp/)
Bakery, optional bread-emit, bread-module-host — baked when the verified stable index publishes them; skipped (not a failed bake) until bread ships them
pacman (packages.x86_64) breadlock, plus the rest of the distro (Hyprland, Calamares, Zen, …)
Not shipped breadcast, breadarr

The baked name list is iso/bread-lockfile.toml (plus optional [versions] / [[pin]] so CI fetches https://dl.breadway.dev/<pkg>/<ver>/...). build-local.sh fails if any required binary is missing on the builder.

Repo layout

This is an ISO + Calamares + skel repo. There is no Cargo workspace and no bos-settings/ member — bos-settings and breadhelp live in their own repos and arrive via bakery.

bos/
├── iso/                           # archiso profile
│   ├── bread-lockfile.toml        # bakery bins + optional version pins
│   ├── profiledef.sh
│   ├── packages.x86_64            # live + installed pacman set
│   └── airootfs/                  # files overlaid onto the image
│       └── etc/
│           ├── skel/              # live user defaults (hypr, kitty, gtk, …)
│           └── calamares/         # installer config + post-install.sh
├── packaging/                     # in-house PKGBUILDs for AUR-only deps
│   ├── calamares/
│   ├── bibata/
│   ├── powerlevel10k/
│   └── yay-bin/
├── dotfiles/                      # STALE — not the live skel; see its README
├── scripts/
│   ├── ci-stage-bakery.py     # CI: minisign-verified index → $LAPTOP_HOME
│   ├── ci-verify-bake.sh      # CI: read-only checks before mkarchiso
│   └── smoke-test.sh
├── docs/
│   ├── hardware.md                # Mesa only, NVIDIA, grub-btrfs recovery
│   └── signed-repo.md             # future dl.breadway.dev/arch signing
├── .forgejo/workflows/            # CI: AUR republish + tagged ISO release
├── build-local.sh                 # native ISO build for this machine
├── README.md
└── DESIGN.md                      # historical plan

Live binds are iso/airootfs/etc/skel/.config/hypr/binds.json (Super+Lloginctl lock-session, breadshot on Super+Shift+S/C/P, Super+U breadpad). Do not treat dotfiles/hypr/keybinds.conf as current.

Branches and remotes

Single-trunk: work on main via short-lived feature/* / fix/* branches. stable is a marker branch CI fast-forwards to the latest non-RC release tag — do not land work there by hand.

Dual remotes:

  • origin — Forgejo (ssh://git@100.66.238.26:2222/Breadway/bos.git), authoritative
  • github — GitHub (https://github.com/Breadway/bos.git) mirror

Push origin (and github when mirroring). Do not treat origin as GitHub.

Building the ISO

build-local.sh builds the image natively (no container) and copies this machine's bakery-installed bread binaries + breadhelp content from the builder's ~/.local into the image at /usr/local (bins, share/data, desktop files, licenses) and /usr/lib/systemd/user (units). Per-user bakery state (installed.json + index cache) is seeded in /etc/skel. User units are systemctl --global enable'd so a later useradd -m starts them on first login. BOS opts in via /etc/bakery/config.toml (prefix = "/usr/local"); default bakery without that file is still ~/.local. Snapper @ snapshots include /usr/local; recovery is still grub-btrfs, not snapper rollback.

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), rewrites the [breadway] repo URL to the Tailscale-reachable Forgejo registry for the build, and exits non-zero if any required lockfile binary (or breadhelp content) is missing. Optional bins are skipped with a warning.

CI stages the builder from the minisign-verified stable bakery index (index.json + index.json.minisig) and prefers lockfile [versions] URLs (https://dl.breadway.dev/<pkg>/<ver>/...) when set, so two bakes of the same commit fetch the same bits. Local builds still snapshot the builder.

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). [breadway] is not where bakery/breadbar/bos-settings live.

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. That key signs ISO checksums only — it does not sign the [breadway] pacman repo (Forgejo's Arch registry has no pacman-compatible db signatures; that section stays SigLevel = Never until a signed repo exists — see docs/signed-repo.md). 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.

Post-install, scripts/smoke-test.sh (run as the installed user) checks subvolumes, services, bakery bins on PATH, breadhelp content under /usr/local/share/breadhelp/content, and that bakery user units are --global enabled (or the preset / wants files exist).

Second account

Bakery desktop apps live in /usr/local — shared, already on PATH. A later account does not get a private copy of those binaries.

/etc/default/useradd keeps SKEL=/etc/skel. Stock useradd -m is enough:

sudo useradd -m alice
sudo passwd alice
  • Apps: /usr/local/bin (and /usr/local/share) — already there.
  • Session files: useradd -m copies /etc/skel (Hyprland, bread config, bakery installed.json + index cache) so first login has a session. Skel does not contain bakery binaries.
  • Daemons: breadd, breadbox-sync, breadclipd, breadcrumbs, breadmill, … are systemctl --global enable'd at install (and on the live image). Creating a user starts them on first login.
  • Login: greetd/breadgreet lists any local user with a login shell (SHELL=/usr/bin/zsh is the useradd default).

breadclipd is WantedBy=graphical-session.target. BOS does not activate that target (no uwsm), so Hyprland still systemctl --user starts it after the compositor is up. --global enable still records it for every account.

Rollback is still the GRUB snapshots submenu (grub-btrfs), not snapper rollback. /usr/local rides the @ snapshot.

bos-settings

Standalone bakery product: Tauri 2 + Svelte, not GTK4, and not built from this repo. Install/update with bakery; the ISO just bakes whatever binary the builder has.

It aims for GNOME-Settings-style parity: live system state and control, so day-to-day administration doesn't require a terminal. Bread-ecosystem configs are edited non-destructively (comments and unmodeled keys stay). Panels with a daemon (bread, breadbox, breadcrumbs, breadsearch, breadclip) also get live systemd status + Start/Stop/Restart/Logs.

Panel What it does
About System info (OS/kernel/CPU/GPU/memory/disk/uptime) + hostname
Network Wi-Fi scan/connect, Ethernet status, radio toggle
Wi-Fi Profiles (breadcrumbs) breadcrumbs.toml — settings, saved networks, profiles
Firewall ufw rules: enable/disable, add/remove, view active rules
Sound PipeWire output/input device + volume via pactl
Power Battery status/health, brightness, charge limits (hardware-dependent), TLP profile (read-only)
Date & Time Timezone, NTP sync toggle
Display (Hyprland) Connected monitors + open hyprland.lua in editor
Users Add/remove accounts, change passwords
Wallpaper (breadpaper) Set wallpaper, drives the pywal-derived accent palette
Bar (breadbar) breadbar/style.css override, live-reloads on save
Launcher (breadbox) breadbox/config.toml — launcher contexts
Clipboard (breadclip) breadclipd service control + "open history"
Notes (breadpad) breadpad/breadpad.toml — settings, model + ollama, reminders, calendar
File Search (breadsearch) breadsearch/config.toml — index/search/model + breadmill service
Daemon (bread) breadd.toml — daemon, lua, modules, adapters, events, notifications
Packages bakery installed list + updates, pacman system update
AUR Search via yay; installing opens a terminal (AUR build scripts need review)
Firmware fwupd device list + updates
Snapshots snapper list / boot-into (grub-btrfs) / delete

Source and build live in the bos-settings repo, not here.

The bread ecosystem

Everything below is a separate bakery-distributed project with its own repo and release cadence, baked into /usr/local at ISO build time so a fresh install has them all with no network round-trip. Some ship more than one binary from a single package — that's noted where it applies. Most have a corresponding bos-settings panel; this table is about using the app directly.

Desktop shell

Tool Role Launch
bread / breadd Reactive automation daemon — normalises hardware/compositor/power/network signals into events dispatched to Lua modules (~/.config/bread/). bread-emit is the fire-and-forget helper hooks/CLIs use; bread-module-host is the sandboxed out-of-process module runtime breadd spawns. Both extra bins are optional on the ISO until a stable bread release publishes them. runs at login (breadd.service)
breadbar Top status bar: workspaces, clock, system stats, tray, and the notification daemon — one process, not two runs at login
breadbox Application launcher (fuzzy search, per-context results via breadbox-sync) SUPER+Space
breadlock Idle lock screen. Also provides breadgreet, the login greeter hosted under cage via greetd — same project, two binaries, one visual identity from login to lock. pacman, not bakery. SUPER+L (via loginctl lock-session, picked up by hypridle); breadgreet runs automatically at boot
bread-theme The shared palette engine every bread app renders through: fixed dark base colors, with only the accent slots following the current wallpaper's pywal palette. bread-theme generate regenerates the stylesheet; hyprland.lua calls it automatically on wallpaper change. invoked automatically, rarely run by hand

Productivity

Tool Role Launch
breadpad Quick-capture scratchpad/notes popup with AI classification and optional CalDAV calendar sync SUPER+U
breadman The fuller notes manager view (browse/organize) — ships from the same breadpad package as a second binary SUPER+M
breadclip Clipboard history. breadclipd is the background daemon that actually records history; breadclip is the GTK4 popup that browses it SUPER+V / SUPER+Shift+V
breadsearch Semantic system-wide search (indexes files/notes, embeds locally — CPU/ROCm/CUDA backend configurable). breadmill is its indexing daemon. via breadbox, or BOS Settings → File Search
breadhelp Onboarding + in-session help/cheatsheet. Content lives at /usr/local/share/breadhelp/content (bakery content.tar.gz, baked into the image). SUPER+/

System

Tool Role Launch
breadcrumbs Location-aware Wi-Fi profile state machine, with optional Tailscale integration — switches network behavior based on which saved network you're on CLI, or BOS Settings → Wi-Fi Profiles
breadpaper Wallpaper manager — sets the wallpaper via awww, generates the pywal accent palette from it, and reloads every bread-theme app BOS Settings → Wallpaper
breadmon TUI monitor layout manager (resolution/position/scaling) — the interactive counterpart to BOS Settings' read-only Display panel breadmon in a terminal
breadshot Screenshot utility wrapping grim/slurp/wl-copy with Hyprland-aware geometry (multi-monitor-safe region select) breadshot, or SUPER+Shift+S/C/P

Tooling

Tool Role Launch
bakery CLI package manager for the whole ecosystem — install/update/list, tracks installed binaries + versions independently of pacman bakery
bos-settings Unified Tauri 2 + Svelte control panel: live system state + control (network, power, firewall, users, packages, firmware, AUR, snapshots) plus non-destructive config editing for every app above 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 Notes (breadpad) / notes manager (breadman)
SUPER+, / SUPER+/ BOS Settings / keybind cheatsheet
SUPER+L / SUPER+N Lock / log out
SUPER+Backspace Close window
SUPER+F Fullscreen
SUPER+I Toggle floating
SUPER+P Toggle pseudotile
SUPER+R Resize mode
SUPER+T Toggle split direction
SUPER+V / SUPER+Shift+V Clipboard history (breadclip)
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 110
SUPER+Shift+1..0 Move window to workspace
SUPER+[ / ] Previous / next workspace
SUPER+Shift+[ / ] Move window to previous / next workspace
SUPER+scroll Cycle workspaces
SUPER+left/right-drag Move / resize window with the mouse
Volume / brightness / play-pause / next / prev Media keys — work even on the lock screen
Calculator key Opens gnome-calculator

Known limitations

See docs/hardware.md (GPUs, NVIDIA, recovery) and docs/signed-repo.md ([breadway] stays unsigned until dl.breadway.dev/arch exists).

  • GPUs: ships the generic Mesa stack — AMD and Intel work out of the box. NVIDIA is unsupported (no proprietary driver, no NVIDIA firmware). See docs/hardware.md.
  • 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 run sudo sbctl enroll-keys --microsoft && sudo sbctl sign-all -g yourself later (after clearing your firmware's existing keys, if any). The installer writes both an NVRAM entry and the removable EFI/BOOT/BOOTX64.EFI fallback 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 is the GRUB snapshots submenu, not snapper rollbackdocs/hardware.md.
  • [breadway] signatures: SigLevel = Never until a signed repo is stood up at dl.breadway.dev/arch. See docs/signed-repo.md.

Recovery

An update broke something (system still boots): open BOS Settings → Snapshots and pick a snapshot to boot, or choose one from the GRUB “snapshots” submenu (grub-btrfs) at boot, then reboot into it.

Do not run snapper rollback as the default recovery step. BOS GRUB pins rootflags=subvol=@, so a snapper-swapped default subvolume is not what the installed grub.cfg will boot next. Use the grub-btrfs entry so the kernel command line matches the snapshot you want. Details: docs/hardware.md.

A/B root swapping (SteamOS-style) is a future idea in DESIGN.md — it is not shipped.

The system won't boot (broken GRUB / lost EFI entry):

  1. Boot the BOS ISO and open a terminal (SUPER+Return).
  2. Run sudo bos-rescue. It finds the installed btrfs @ and the ESP, prints the devices it will use, and asks YES before writing. It can arch-chroot and/or reinstall GRUB with the same sequence the installer uses (NVRAM + --removable + grub-mkconfig).
  3. Manual equivalent, if you would rather type it:
    mount -o subvol=@ /dev/sdXN /mnt
    mount /dev/sdXP /mnt/boot/efi      # the EFI partition
    arch-chroot /mnt
    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.