singleton.rs's tests used to call the real kill() on the current test
process itself (the recorded "other instance" PID was our own, since
tests run single-process) — split try_acquire (side-effect-free) out from
toggle_or_kill (sends the signal) so the concurrency assertions no longer
risk SIGTERM-ing the test binary.
Separately, hypr.rs's env-var test mutates HYPRLAND_INSTANCE_SIGNATURE/
XDG_RUNTIME_DIR process-globally; cargo runs tests in parallel threads by
default, so it could race a concurrently-running singleton or xdg test
expecting the real XDG_RUNTIME_DIR, intermittently failing them with
ENOENT. Added a shared env_test_lock() all env-var-touching tests now
acquire for their duration.
Verified via 5 repeated full test runs with zero flakes (28/28 passing
each time).
bread-utils extracts genuinely duplicated logic found across breadbox,
breadclip, breadmon, breadcrumbs, bos-settings, and breadhelp:
- hypr: Hyprland socket1 request/response client (breadbox's
get_active_workspace + breadclip's position.rs hyprctl_json were
near-identical), socket2 path resolution (breadmon), and a
version-tolerant `fullscreen` field parser (Hyprland has shipped both
bool and int representations across versions).
- singleton: correct flock-based single-instance toggle, replacing the
TOCTOU-prone read-pid/check-proc/kill/write-pid pattern duplicated
verbatim between breadbox and breadclip (breadclip's own comment says
"matches breadbox pattern").
- proc: breadcrumbs' timeout-guarded subprocess runner, promoted verbatim
as the one implementation in the ecosystem that already got this right.
- atomic + xdg: atomic (temp-then-rename) file writes with an optional
.bak-before-overwrite variant, and XDG path helpers that never fall back
to a literal "~/..." string (the exact breadclip-core and
breadpad-shared bug: PathBuf never expands `~`).
- tomlcfg (feature "toml"): the load_doc/save_doc TOML-editing discipline
bos-settings and breadhelp both implemented byte-for-byte identically in
the same fix pass that introduced it.
- gtk_popup (feature "gtk"): layer-shell overlay window setup, visible-row
navigation, and click-outside-close, deduplicated from breadbox and
breadclip (~150 duplicated lines, per both apps' own "same as breadbox"
comments).
bread-onnx extracts the embedding pipeline (tokenize -> tensor build ->
mean-pool -> L2-normalize) duplicated near-verbatim between breadarr and
breadsearch, a shared execution-provider session builder with loud EP-
registration logging, and a model download+integrity helper. Defaults AMD
iGPU acceleration to ort::ep::MIGraphX (not ROCm) per this machine's own
breadsearch-gpu-backends lesson: ROCMExecutionProvider silently no-ops to
CPU on distro ROCm onnxruntime builds compiled with --use_migraphx.
Both crates build and pass their own test suites standalone. Consumer
migrations follow in subsequent commits.
- Add minisign-based signing/verification for the bakery index:
scripts/gen-index.sh signs index.json (MINISIGN_SEC_KEY env var, dormant
no-op with a loud warning until a key is provisioned); bakery/src/manifest.rs
fetches index.json.minisig and verifies it with minisign-verify against a
hardcoded PUBKEY before parsing/caching, and re-verifies the cached copy
on every load (falls back to one re-fetch if the cache predates signing
or fails verification; a fresh fetch that fails verification is a hard
error).
- Close the previously-unchecksummed config-example and systemd-unit
downloads in bakery/src/install.rs (scaffold_config, install_service):
index.json now carries `sha256`/`example_sha256` for these artifacts
(computed in gen-index.sh), verified via the same download::verify_sha256
used for binaries. Downloads without a matching sha256 in the index are
refused rather than installed unverified.
- scripts/get.sh now verifies the bakery release binary itself against a
pinned minisign public key before installing it (falls back to the
existing sha256-only check with a loud warning if no .minisig is
published yet or minisign isn't installed; a present-but-invalid
signature is a hard failure).
- Add dormant "sign release binary" steps to the bakery and bread-theme
release workflows (.github/workflows/release.yml,
.forgejo/workflows/release-bread-theme.yml), gated on secrets that are
not yet configured — binaries ship unsigned exactly as before until the
owner wires up the secret.
- .gitignore: add *.minisign-sec / minisign.key so the signing key can
never be committed by accident.
- bread-theme: fix stale docs describing a "Catppuccin Mocha fallback"
(BREAD_DESIGN_SYSTEM.md, README.md, Cargo.toml/bakery.toml/registry
descriptions) — the actual implementation (palette.rs) uses a fixed BOS
dark base with only accent colors from pywal.
- bread-theme: fix the legacy css_vars() path, which had its own
hand-written @define-color block that predated the `accent` and computed
`on-*` ink colors used by the rest of the stylesheet — any caller whose
CSS referenced those names against css_vars()'s output would hit
undefined colors (the illegible-text bug). css_vars() now delegates to
the same define_colors() the full stylesheet uses, so the two can't
drift apart again.
Was previously an unmanaged binary baked into /etc/skel — never updated by
bakery or pacman, which is why fresh BOS installs (and existing ones) kept
regenerating the shared theme.css with the pre-fix pywal-driven background
even after bos-settings itself shipped the fix.
A light or muddy-toned wallpaper (e.g. an all-beige photo) makes pywal hand
back a light or off-hue background/surface slot, and every bread GUI's
panels inherited it directly — the app stopped looking like a dark BOS tool
and started looking like whatever colour the wallpaper happened to be.
background/foreground/color0(surface)/color7(overlay) are now fixed BOS
dark-theme constants, never read from pywal's special/colors blocks. Only
color1-6 (the actual accent slots) still track the wallpaper via pywal, which
is the feature breadpaper is for.
The stylesheet is written with write-tmp-then-rename (atomic), which replaces the
inode. A monitor on the file itself caught the first replace then went deaf
(inotify reports DELETE_SELF and never re-arms), so `bread-theme reload` updated
the file but no running GUI ever recoloured. Monitor the parent directory and
filter for the stylesheet filename instead — that fires on every reload. Verified
against a real atomic-rename write (event arrives as Renamed with the new name in
other_file, so match both file and other_file).
Readability: pywal can emit a light value in any palette slot, and the shared
sheet assumed dark backgrounds (white text), so text vanished on light surfaces/
accents. Add ink_on() — a WCAG-luminance pick of near-black/near-white per
background — exposed as @on-bg/@on-surface/@on-accent/@on-red/@on-overlay. The
component sheet now sets colour on containers and lets labels inherit (de-emphasis
via opacity), dropping the blanket `label { color }` rule that overrode
coloured-background text. pywal hues are untouched.
Hot reload: add gtk::apply_app_css(closure) — applies an app's own CSS now and
re-runs the closure whenever the shared theme file is rewritten, so apps recolour
in place. New `bread-theme reload` verb rewrites the file (atomic rename trips
every running GUI's monitor) — the command to run after changing pywal colours.
README: add recommended keybinds and a Theming section documenting the
bread-theme generator + live-reloaded shared stylesheet. Add
BREAD_DESIGN_SYSTEM.md to the repo (the README links it) and update it to
describe the single-source-of-truth architecture and the migrated apps
(incl. bos-settings).
Adds the single source of truth for bread GUI styling so the apps stop
each re-implementing (and drifting on) component CSS:
- stylesheet(&Palette): full component sheet (buttons, entries, switches,
dropdowns, lists/rows/sidebars, cards, chips, scrollbars, headings) built
from the design tokens + a canonical @define-color block (surface=color0,
overlay=color7, accent=color4).
- render() / shared_css_path() / write_shared_css(): render for the current
pywal palette and write to $XDG_RUNTIME_DIR/bread/theme.css.
- gtk::apply_shared(): load that file (or a rendered fallback) at APPLICATION
priority and watch it, so every app recolours live with no rebuild.
- new `bread-theme` CLI (generate|path|print) — gtk-free, light. Run at
session start and on palette change; apps pick it up via the file watch.
The contract is a CSS *file*, so apps stay decoupled from this crate's gtk4
version. Tests cover the stylesheet, path, and render helpers.
- packaging/arch/PKGBUILD: builds the bakery CLI from the workspace
- .forgejo/workflows/package.yml: publishes to the [breadway] Arch registry on tag
- .forgejo/workflows/mirror.yml: mirrors to GitHub
Critical fixes:
- gen-index.sh: emit services, config, optional_system_deps from bakery.toml;
parse product list from registry TOML instead of hardcoded array; fail loudly
when bakery.toml is missing (was silently producing empty metadata in prod)
- install.rs: download service units and example configs from dl server at
install time (were never fetched); check systemctl exit codes (were swallowed);
save state before file cleanup in remove_package (was inconsistent on error)
- doctor.rs: rewrite dep detection to use `pacman -Q` as primary (no more
dependency on `which` or pkg-config name mismatches); add optional_system_deps
support returning (missing, warnings) — warnings print but never block install
- get.sh: fix GitHub fallback URL (was 404 for both latest and versioned
releases); add SHA-256 checksum verification using published .sha256 file
High priority fixes:
- bakery doctor <unknown-pkg>: exit non-zero (was silently passing)
- bakery update: add --all flag (documented in README but missing from CLI);
add doctor gate before update (was bypassing dep check)
- bread_deps: now resolved recursively with cycle detection (was ignored)
- manifest.rs: add artifact_urls() helper and optional_system_deps field
- state.rs: atomic save via tmp+rename; cmd_info shows optional_system_deps
Tests: 17 new unit tests across doctor, download, install, state modules;
scripts/test-gen-index.sh fixture test for full pipeline
- breadbox: was 'cloud sync daemon + file browser'; it's actually a GTK4
fuzzy app launcher; breadbox-sync resolves icons, not cloud data
- breadcrumbs: was 'network information CLI'; it's a profile-aware Wi-Fi
state machine with Tailscale integration and a watch daemon
- breadpad: was 'scratchpad / quick-note app'; call out AI classification,
reminders, recurrence, and the breadman viewer
- system deps: add gtk4-layer-shell for breadbox and breadpad (both use
layer-shell windows); drop spurious 'dbus' from breadbox
- bakery: strip -x86_64 / -aarch64 / -arm64 / -armv7 suffix when placing
binary so `breadcrumbs-x86_64` installs as `breadcrumbs`
- gen-index.sh: GH_BASE was "github.com/Breadway" but repo slugs already
include the org, producing doubled paths; change to "github.com"
- Add bakery.toml describing the bakery binary as an installable product
- gen-index.sh: check DL_DIR/<pkg>/bakery.toml first (written by each
product's release workflow), fall back to sibling checkout for local dev
- gen-index.sh: include bakery itself in the products list
- release.yml: use GITHUB_WORKSPACE instead of ECOSYSTEM_DIR (the
bread-ecosystem runner IS the checkout, no separate clone needed)
- release.yml: copy bakery.toml to DL_DIR during artifact prep