python-pywal was dropped from Arch's [extra] repo (AUR-only now), so
`pacstrap` can no longer resolve it and every ISO build fails with
"target not found: python-pywal". The `wal` binary is load-bearing —
bread-theme shells out to it to extract the colour palette from the
user's wallpaper.
Republish it the same way as calamares / bibata / powerlevel10k /
yay-bin:
- `packaging/python-pywal/PKGBUILD` — in-house copy of the AUR PKGBUILD
(Morten Linderud's), modernised to `python -m build` / `installer`
instead of the removed `setup.py install`, sha256-only sources like
the sibling PKGBUILDs. Test-built locally: 28 unit tests pass, package
ships `/usr/bin/wal`.
- `.forgejo/workflows/python-pywal.yml` — builds + PUTs to the Forgejo
Arch registry on a push to `packaging/python-pywal/**`.
- `signed-repo.yml` gains it as a `workflow_run` trigger;
`ci-publish-signed-repo.sh` gains it in `PACKAGES` so the signed
dl.breadway.dev/arch db picks it up.
- packages.x86_64 keeps the `python-pywal` line (now sourced from
[breadway]) with a note.
Ordering: `python-pywal.yml` must publish to the registry once before
`signed-repo.yml` runs, or the collect step errors "registry db missing
packages: python-pywal".
Docker as root left 0600 .sig files the runner could not chmod
(run 1050), so publish_tree never moved the tree into
/srv/breadway-dl/arch/x86_64. Sign as the host uid so nginx can
read the files and the next publish can replace them.
Host job on hestia (no container) collects breadlock plus the ISO AUR
republishes from the Forgejo registry, detach-signs them, repo-add -s,
and writes /srv/breadway-dl/arch/x86_64/. ISO SigLevel stays Never.
Click-to-install path for machines first-boot already offers. Installs
nvidia + nvidia-utils (never cuda), writes ~/.config/hypr/nvidia.lua,
and hyprland.lua dofiles that file only if it exists. Mesa stays
unchanged. Not on the ISO. Reboot after.
Recovery is reboot → GRUB “snapshots” submenu. snapper rollback
does not change what GRUB boots (rootflags=subvol=@). Same wording
in README Recovery and docs/hardware.md.
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.
BOS opts in to bakery's system prefix so desktop apps live on @
and ride snapper/grub-btrfs snapshots. The builder home stays
~/.local; build-local.sh copies bins, share/data, and user units
onto the image. Per-user installed.json and the index cache stay
in skel. Recovery is still grub-btrfs, not snapper rollback.
Live-ISO bos-rescue finds the installed btrfs @ and ESP, then offers
arch-chroot and/or the same GRUB NVRAM + --removable sequence as
post-install.sh. Recovery is grub-btrfs or this reinstall — GRUB pins
rootflags=subvol=@.
bos-first-boot runs once after the first graphical login: NVIDIA offer
file + notify (no driver install), VM-without-GL notify, HiDPI hint
file (never rewrites monitors.json).
Re-enable the Calamares packages module as a refresh-only step with
skip_if_no_internet and ignore_update_db_error so offline installs
cannot abort on pacman -Sy.
profiledef.sh uses uefi.grub. mkarchiso checks for grub-install on the
host before building; archiso does not pull grub, so the v0.6.0 bake
aborted after bakery staging.
Newer git tags for breadpad, breadmon, breadclip, breadshot,
breadhelp, and breadcrumbs have no artifacts on dl.breadway.dev
because bakery release CI failed. Pin what the signed index
actually serves so the ISO bake can verify sha256.
Point os-release at the bos repo and issues; drop Arch privacy terms.
Take a best-effort snapper pre snapshot before pacman and bakery.
Pin current stable bakery versions so CI fetches the same bits per commit.
Autostart breadpaper/breadshot listen behind command -v.
Document signed-repo setup and Mesa/NVIDIA/grub-btrfs recovery.
Upstream tarball has 12 variants. BOS only selects Bibata-Modern-Ice;
keep that plus the left-handed -Right sibling. Needs a [breadway]
rebuild to take effect on the ISO.
Remove Calamares, archiso boot-chain, and memtest/EFI-shell packages
from the installed system (plus orphan sweep). Socket-activate avahi.
Mask the systemd-homed stack so presets cannot re-enable it. Cap
journald at 256 MiB instead of 10% of the @log pool.
List linux-firmware subpackages so nvidia blobs stay off the image.
Drop unused noto-fonts-cjk, base-devel, linux-headers, and zathura
(skel already maps PDF to Zen). Keep webkit2gtk-4.1, breadlock, cage,
and the bakery-vs-pacman comments; rustup was already gone.
systemd-boot can only read the ESP it launched from, so mkarchiso copies
vmlinuz + initramfs into efiboot.img on top of the ISO9660 copy (~244 MiB
duplicate). uefi.grub reads ISO9660 directly; iso/grub configs were already
present and BOS-branded.
The tagged ISO workflow fetched bos-settings/src/Cargo.toml from the
dev branch (404 after the Tauri split) and cargo-built bread-theme.
bread-theme 0.7.1 is already on the stable index. Stage required bins,
units, breadhelp content, and desktop/license files from the
minisign-verified index instead; optional bread-emit/module-host skip
until bread publishes them. Fail the bake if a required bin is missing.
Derive BREAD_BINS from iso/bread-lockfile.toml and fail the bake when a
listed binary or breadhelp content is missing. Bake bakery share files
and drop breadcast from the copied installed.json. Add WebKitGTK 4.1 for
Tauri bos-settings, remove rustup, and rewrite README/DESIGN to match the
ISO+skel tree.
Adds a bot-moved-only stable marker branch, never merged into by
hand — fixes the same "long-lived branch silently rots" failure mode
found in the app repos' old dev/beta/main model, applied here since
bos shares the single-main-branch principle even though its ISO
release cadence stays manual/deliberate rather than continuous.
bos-settings moved its Rust manifest to src/Cargo.toml and switched the
bread-theme dependency from a tag pin to branch = "main" (no release with
the needed functions yet). The workflow was still fetching the old root
Cargo.toml path and grepping for a tag field, so it 404'd and broke every
v0.5.2 release-iso run.
Both now install like every other bread app: staged into skel via
build-local.sh's BREAD_BINS array from this laptop's real bakery
install, with hand-committed .desktop files matching the existing
breadclip/breadman/breadmon/breadsearch pattern. Removes the last two
BOS-specific pacman packages from packages.x86_64.
bos is ISO-only (release-iso.yml); it has never been bakery-distributed.
This file was a byte-for-byte copy of bos-settings/bakery.toml (name,
binaries, description all describe bos-settings, not bos) and isn't
referenced by the bread-ecosystem registry or any workflow in this repo.
DESIGN.md already documents that bos-settings — not bos — is the one
meant to get a bakery.toml and a registry entry.
- release-iso.yml's "Build bread-theme from source" step grepped
bos-settings/Cargo.toml for the bread-theme tag pin, but bos-settings was
split out into its own repo (git.breadway.dev/Breadway/bos-settings) --
that path no longer exists in this checkout, so the grep would fail (or
silently find nothing). Now fetches bos-settings' Cargo.toml directly from
its own repo (dev branch, the one its own CI actually publishes the
bos-settings pacman package from) via the Forgejo raw-file endpoint.
- calamares.yml cloned the repo's default branch instead of the branch/tag
that actually triggered the run -- bibata.yml, powerlevel10k.yml, and
yay-bin.yml (the other in-house-PKGBUILD workflows in this same family)
all correctly clone --branch "${GITHUB_REF_NAME}". Brought calamares.yml
in line with them.
- breadhelp-tour.lua interpolated an untrusted, client-controlled Wayland
window class / layer-shell namespace directly into a bread.exec shell
command string -- a session-level shell injection vector (verified
exploitable with a crafted window class before this fix, e.g.
"evil; touch ~/pwned #"). bread.exec only accepts a single shell string
(always run via `sh -lc`, per breadd/src/lua/mod.rs) -- there's no
array-exec form to bypass the shell with -- so the fix is a proper POSIX
shell_quote() helper wrapping every interpolated value in single quotes
before it reaches bread.exec.
breadhelp's own repo builds cleanly but hasn't been published yet (see
git.breadway.dev/Breadway/breadhelp package.yml — needs REGISTRY_TOKEN
added to that repo's Actions secrets). Re-add once a tag publish
succeeds.
Mirrors the bos-settings extraction (664298b): a breadhelp release no
longer requires a v* tag on the whole bos monorepo, which was
indistinguishable from an actual BOS-version release tag. Source lives
at ~/Projects/breadhelp now, full history preserved via git-filter-repo.
Root Cargo.toml/Cargo.lock and .forgejo/workflows/package.yml removed
too — breadhelp was the sole workspace member and the sole thing that
workflow built.
Replaces the old in-window onboarding wizard with a real screen-wide
tour: dim + spotlight cutout around the actual on-screen component
(breadbar, breadbox), floating callout teaching the shortcut, and
event-driven confirmation via real Hyprland/breadd signals instead of
click-through fakery.
The sed matched snapper's default config template text exactly
(ALLOW_USERS=""), so any drift in that template across snapper versions
made it silently no-op -- leaving ALLOW_USERS empty and every non-root
snapper call (including bos-settings' Snapshots page) failing with
"No permissions." forever, with no error surfaced anywhere at install
time. `snapper -c root set-config` is the stable API regardless of
template wording.
bos-settings moves to git.breadway.dev/Breadway/bos-settings (full history
preserved via git-filter-repo) so its release cadence is decoupled from
BOS's own. breadhelp takes its place as this repo's workspace member: a
GTK4 onboarding/help center replacing the old bos-welcome/bos-keybinds
bash scripts with searchable guides, an interactive keybind viewer
(sourced from the new keybinds.toml, not parsed out of hyprland.lua or
hardcoded), a troubleshooting wizard with one-click fixes, and a proper
first-run tour. bos-netcheck extracts bos-welcome's network-check half,
which still needs to run every login independent of breadhelp's own
first-run gating.
hyprland.lua's keybinds/settings/monitors/autostart are now JSON-driven
(binds.json/settings.json/monitors.json/autostart.json) with every
loader pcall-wrapped and falling back to hardcoded defaults per field on
bad or missing config, so bread* apps (bos-settings' new editors, and
breadhelp's keybind viewer) can read/write this config without ever
being able to leave the compositor unable to start.
CI's package.yml now builds breadhelp instead of bos-settings on tag
push; bos-settings needs its own equivalent workflow in its new repo
(not yet set up).
Confirmed on the test laptop's real install: /etc/snapper/configs/ was
completely empty post-install — snapper create-config failed silently and
BOS's advertised snapshot/rollback feature was entirely non-functional,
despite snapper-cleanup.timer being enabled and grub-btrfsd active (both
harmless no-ops with no config to act on).
Root cause is the known chroot-specific busy-mount race already documented
in this section's comments, but the existing recovery (retry umount 5x,
then one lazy-unmount fallback) wasn't sufficient on this hardware — a
lazy unmount detaches the mountpoint from the namespace immediately, but
whatever was holding it busy can take a moment longer to actually release,
and the immediately-following rmdir/create-config both fail if anything
still references /.snapshots at that instant.
Wrap the entire unmount → rmdir → create-config → cleanup → remount
sequence in an outer retry loop (checking whether the config file actually
exists before each attempt and after the loop), add a settle delay after
the lazy-unmount fallback, and turn the final failure into a loud ERROR
instead of a warning that's easy to miss — a system silently shipping
without snapshots is worse than one that's slow to set them up.
Verified against the actual cached mkinitcpio package (41-4), not assumed:
its shipped /etc/mkinitcpio.conf template is
HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole
block filesystems fsck) — there's no "udev" token at all on a stock
install anymore, systemd is the base hook instead.
This silently broke two things:
- The existing plymouth-hook insertion (`sed 's/\budev\b/\0 plymouth/'`)
has been a no-op on every fresh install using a current mkinitcpio
package — the boot splash was never actually getting wired into the
initramfs, just failing quietly (the script's best-effort `|| echo WARN`
pattern doesn't catch a sed that "succeeds" by matching nothing).
- My own new encrypt-hook insertion from the previous commit had the same
flaw, and would have used the wrong hook regardless: `encrypt` is the
udev-based hook, systemd-based initramfs needs `sd-encrypt` instead.
post-install.sh now detects which base hook (systemd or udev) is actually
in HOOKS once, and uses the matching hook name for both plymouth
(unaffected by the choice, just needed the right anchor to insert after)
and LUKS unlocking (encrypt vs sd-encrypt — genuinely different hooks).
Also: avoid a redundant pacman -Sy in release-iso.yml's signing step —
the job already synced repos earlier in the same container.
Continues reducing terminal-reliance for graphical system control. Five
new panels, plus three GUI apps shipped for things better served by an
existing dedicated tool than reimplemented in bos-settings
(gnome-disk-utility, gufw, mission-center).
- Power: battery status/health, brightness, charge-limit thresholds where
the hardware exposes them, TLP profile shown read-only by design (no
Balanced/Performance switcher — TLP auto-selects by power source, and
power-profiles-daemon isn't installed because it conflicts with tlp).
- Firewall: ufw enable/disable, add/remove rules, view active rules.
ufw's own status check requires root (confirmed against the installed
script — not just changes, reads too), so unlike every other panel this
one does NOT query state in build(): every view is constructed eagerly
at app launch, and an unconditional privileged read here would mean a
polkit prompt on every single bos-settings open. Starts blank with a
"Status not loaded" placeholder; state loads only on an explicit Refresh
click, with a guard so refresh's own set_active() doesn't loop back into
triggering ufw enable/disable.
- Users: add/remove accounts, change passwords. All through pkexec on a
background thread. Can't remove the account you're currently running as.
- AUR: search via yay. Installing deliberately opens a terminal instead of
a silent --noconfirm install — yay's interactive PKGBUILD diff review and
sudo prompt are the actual safety mechanism against a malicious AUR
package, not a formality worth automating away.
- Firmware: fwupd device list + updates, same stream-output-then-refresh
pattern as Packages.
packages.x86_64: gnome-disk-utility, gufw, mission-center for disk/firewall/
task-manager GUIs that don't need reinventing inside bos-settings.
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.
Root cause of two panels rendering full-bleed instead of the 760px column
(breadsearch, breadclip): hint()'s long unwrapped text reported an
unbounded natural width, and CONTENT_MAX_WIDTH is a floor (set_size_request),
not a cap — nothing was actually capping width. hint() and empty_state()
now bound their labels with set_max_width_chars, which stabilizes every
panel's column at a consistent width and left edge for the first time.
service_control(): added a second status line (enabled-at-boot vs
just-running), a confirm dialog on Stop for critical units (breadd — the
whole desktop's event backbone was one accidental click from stopping,
styled identically to optional helpers), and a consistent "Save only
writes the file, Restart applies it" hint on panels that have both a
service and a config file (previously only breadsearch said this, in its
own inconsistent wording).
Consistency sweep: Network's Scan button and empty-state treatment now
match the rest of the app (was full-width where every other secondary
action is auto-width; "not scanned" was a hint while "no results" was an
empty_state card — now both empty_state). breadclip gets an actual "Open
history" action instead of reading as an unfinished stub. breadbox's Save
button pulled out of a mixed row into its own row like every other panel.
Packages list rows now get the same card styling as every other row in
the app.
Panel title now shares view_scaffold's width+center treatment with the
content column, so it actually heads the column instead of sitting ~440px
to its left.
Also: switch widgets had a stray box-shadow/outline/border showing as a
faint ring around the knob, and bread-theme's switch slider color
(@on-surface) was being masked by Adwaita's default gloss background-image
— clearing it reveals the correctly-themed near-white knob against the
dark surface.
sidebar.rs and window.rs each independently hardcoded "about" as the
default selected/visible page — harmless while both literals happened to
match, but a real latent bug: changing one without the other silently
desyncs the sidebar highlight from the actually-displayed panel. Found
while capturing screenshots of every panel for a design review, where
exactly that happened. window.rs now owns DEFAULT_PAGE and passes it to
sidebar::build().
New panels: About, Network (Wi-Fi/Ethernet via nmcli), Sound (PipeWire
volume/device via pactl), Date & Time (timedatectl), and Clipboard
(breadclip previously had no bos-settings presence at all despite running
its own daemon).
Layout: every panel now shares one scaffold (6 views were hand-rolling their
own, inconsistently) with a centered, width-capped content column instead of
rows stretching edge-to-edge on a wide window with the control stranded far
from its label. Rows render as individual cards. Sidebar got human labels +
icons + task-based grouping (System/Personalization/Maintenance/About)
instead of raw binary names under "Apps"/"System".
New capability: a shared service_control() widget gives every bread app
backed by a systemd --user daemon (breadd, breadbox-sync, breadcrumbs,
breadmill, breadclipd) live status plus Start/Stop/Restart/View logs —
previously these panels only ever edited a TOML file and hoped the running
process picked it up. breadbar (no systemd unit) gets an equivalent: Save
now actually sends the SIGHUP its own reload mechanism needs, instead of
just claiming to in the hint text.
Fixed two real bugs surfaced while building About: CPU model string kept a
stray leading tab+colon (trim_start_matches was missing '\t'), and GPU
showed "unknown" on hardware whose lspci entry says "Display controller"
instead of "VGA compatible controller".
Local CSS patches (bos-settings/src/theme.rs) for two upstream bread-theme
gaps: suggested/destructive buttons and scale widgets don't clear Adwaita's
default background-image, so flat colour overrides were invisible; and
destructive-action red must not be pywal-derived (it can land on gold
depending on the wallpaper, indistinguishable from a primary action).
Pulls the fix for panels turning brown/off-hue when pywal extracts a light
or muddy background from the wallpaper — background/surface now stay BOS's
fixed dark constants regardless of what the wallpaper looks like.
breadsearch v0.2.1+ ships breadmill built with --features full (npu + rocm
+ cuda in one binary via ort's load-dynamic/dlopen mode), so the earlier
CPU-only restriction here no longer applies. Hint explains what each
backend needs and how to confirm it actually took effect, since a failed
GPU EP registration falls back to CPU silently at the ONNX Runtime level.
Round-3's autostart fix (breadpaper set instead of raw awww img) had a side
effect I missed: breadpaper set always runs real pywal against the wallpaper
image, which overwrote the curated colors.json baked into skel (#0c0c0c
black background, bread-toned browns reserved for accent slots only) with
colors genuinely extracted from bread-background.png — an all-beige photo,
so every bread-theme app (breadbar included) turned brown on first boot.
Revert autostart to plain `awww img`. Bake .cache/wal/wal (pywal's own
"last image" marker — the only thing breadpaper get/the bos-settings panel
actually read) alongside the existing colors.json instead, so the panel
still shows the real default without ever running pywal for real. pywal
only generates a genuine palette once the user picks their own wallpaper.
Snapshots panel was non-functional (wrong snapper flag); breadgreet picked
the wrong session .desktop and skipped bos-session's PATH fixup; Calamares
aborted offline installs over an unnecessary packages module; snapshot
rollback silently no-op'd on BOS's pinned-subvolume layout (now points at
grub-btrfs instead); breadcrumbs was configurable but had no daemon to run
it. Also: SUPER+I double-bind, breadpaper/packages panels blocking the GTK
main thread, dead polkit rule, and a sweep of smaller drift (default
sidebar view, stale wording, missing .desktop launchers, wallpaper daemon
not recording its own default).