No description
  • Rust 99.2%
  • Shell 0.8%
Find a file
Breadway 6e2010a625
All checks were successful
dev release / build (push) Successful in 20m52s
check / check (push) Successful in 15m27s
Merge pull request #33: breadbug-gui and breadbug::session
2026-10-20 10:56:00 +08:00
.forgejo/workflows Merge branch 'feature/breadbug-status' into feature/breadbug-release 2026-10-20 09:21:16 +08:00
.grok can't be bothered writing a commit message 2026-08-16 14:23:42 +08:00
bread-bug Merge branch 'feature/breadbug-release' into feature/breadbug-consent 2026-10-20 09:23:00 +08:00
bread-cli Merge branch 'feature/breadbug-scrubber' into feature/breadbug-store 2026-10-13 12:06:39 +08:00
bread-emit chore: bump workspace version to 0.9.0 2026-09-11 19:05:56 +08:00
bread-module-host fix(module-host): bridge bread.hyprland to out-of-process modules (BREAD-42) 2026-10-14 14:15:20 +08:00
bread-scrub fix(bug): narrow identity scrub exemptions to configured identities 2026-10-15 12:14:57 +08:00
bread-shared Merge main into feature/breadbug-store after PR21 landed 2026-10-13 21:07:55 +08:00
breadbug test(bug): serialize session capture test with the capture lock 2026-10-20 09:38:59 +08:00
breadbug-gui Add breadbug-gui: windowed bug reporter, and breadbug::session shared by CLI and GUI 2026-10-09 22:05:09 +08:00
breadd fix(bug): apply reload exclusions to the freeze watchdog 2026-10-20 10:00:50 +08:00
ci Merge branch 'feature/breadbug-status' into feature/breadbug-release 2026-10-20 09:21:16 +08:00
docs docs(bug): state that the consent copy matches the upload client 2026-10-20 09:54:43 +08:00
examples/modules fix(examples): use checked monitor keyword compatibility 2026-10-13 13:40:35 +08:00
graphify-out can't be bothered writing a commit message 2026-08-16 14:23:42 +08:00
packaging feat(bug): status check and opt-in fixed notifications 2026-10-09 15:34:08 +08:00
scripts ci: ship breadbug and publish debug symbols with every release 2026-10-09 21:34:03 +08:00
xtask feat(xtask): check-docs covers the module_host bridge methods (BREAD-42) 2026-10-14 19:23:39 +08:00
.gitignore State engine applies bread.hyprland.* and snapshots compositor topology 2026-08-15 22:03:30 +08:00
AGENTS.md Merge pull request 'Remove em dashes from code and docs' (#4) from fix/em-dash-cleanup into main 2026-09-09 14:12:43 +08:00
api-schema.toml Merge branch 'feature/breadbug-consent' into feature/breadbug-reload 2026-10-20 09:24:00 +08:00
bakery.toml ci: ship breadbug and publish debug symbols with every release 2026-10-09 21:34:03 +08:00
Cargo.lock Merge remote-tracking branch 'origin/main' into feature/breadbug-upload 2026-10-20 09:17:06 +08:00
Cargo.toml ci: ship breadbug and publish debug symbols with every release 2026-10-09 21:34:03 +08:00
CLAUDE.md docs: remove em dashes from code and docs 2026-09-06 20:42:42 +08:00
CONTRIBUTING.md docs: remove em dashes from code and docs 2026-09-06 20:42:42 +08:00
DEPRECATIONS.md docs: remove em dashes from code and docs 2026-09-06 20:42:42 +08:00
Documentation.md Merge branch 'feature/breadbug-consent' into feature/breadbug-reload 2026-10-20 09:24:00 +08:00
Examples.md fix(examples): check hyprland keyword refusals in doc snippets 2026-10-13 20:14:18 +08:00
LICENSE Daemon release-ready 2026-05-11 12:21:23 +08:00
README.md feat(bug): status check and opt-in fixed notifications 2026-10-09 15:34:08 +08:00

Bread

A reactive automation fabric for Linux desktops.

Bread is a modular desktop automation runtime built around a single idea: your desktop should behave like a programmable system, not a collection of disconnected config files.

Instead of scattering behavior across shell scripts, compositor configs, udev rules, and ad-hoc daemons, Bread centralizes runtime awareness into a coherent layer that can observe, interpret, and react to system state dynamically.

Status: Early development. The daemon (breadd) is stable. The Lua automation API is active and feature-complete for daily use.


How it works

Bread runs a long-lived daemon (breadd) that:

  1. Ingests raw signals from your compositor, hardware, and OS
  2. Normalizes them into stable, semantic events (bread.device.dock.connected, bread.hyprland.monitor.connected, etc.)
  3. Maintains a live model of your desktop state
  4. Delivers those events to Lua modules that implement your automation

Your automation lives in Lua. You subscribe to events, read state, and call APIs:

local M = bread.module({ name = "dock", version = "1.0.0" })

bread.on("bread.device.dock.connected", function(event)
    bread.profile.activate("desk")
    bread.exec("waybar --config ~/.config/waybar/desk.jsonc")
    bread.notify("Dock connected", { urgency = "low" })
end)

bread.on("bread.device.dock.disconnected", function(event)
    bread.profile.activate("default")
end)

return M

Architecture

breadd/              Rust daemon: event pipeline, state engine, IPC, adapter supervision
bread-cli/           CLI frontend: talks to breadd over a Unix socket
bread-emit/          Tiny fire-and-forget IPC emitter (hooks / command bus)
bread-module-host/   Out-of-process sandboxed Lua module runtime
bread-shared/        Shared types: RawEvent, BreadEvent, AdapterSource
packaging/           systemd user service unit (bakery installs this)

The daemon is structured in four layers:

  • Adapters: interface with Hyprland IPC, udev, power state, network interfaces, and Bluetooth (BlueZ)
  • Normalizer: transforms raw adapter signals into semantic Bread events
  • State engine: maintains runtime state and dispatches events to subscribers
  • Lua runtime: loads your modules, registers handlers, executes automation

Requirements

  • Linux (Arch recommended)
  • Wayland compositor (Hyprland for full functionality)
  • Rust toolchain (stable, 2021 edition)
  • udev (standard on systemd systems)

Optional but preferred:

  • UPower (for battery events via D-Bus rather than sysfs polling)
  • rtnetlink (for network events; falls back to sysfs polling without it)
  • BlueZ (for Bluetooth device events and control)

Installation

From source

git clone https://git.breadway.dev/Breadway/bread.git
cd bread

Run the install script: it builds, symlinks breadd, bread, bread-emit, and bread-module-host into ~/.local/bin (override with BIN_DIR=...), installs the systemd user service, and starts the daemon:

bash scripts/install.sh

Or step by step (system-wide install):

cargo build --release
sudo install -Dm755 target/release/breadd /usr/bin/breadd
sudo install -Dm755 target/release/bread /usr/bin/bread
sudo install -Dm755 target/release/bread-emit /usr/bin/bread-emit
sudo install -Dm755 target/release/bread-module-host /usr/bin/bread-module-host

Via bakery

Prebuilt binaries ship through bakery (the bread-ecosystem package manager), not a PKGBUILD / pacman package:

bakery install bread

systemd user service

mkdir -p ~/.config/systemd/user
cp packaging/systemd/breadd.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now breadd

Configuration

Bread reads from ~/.config/bread/breadd.toml. All values are optional; the daemon runs with defaults if the file doesn't exist.

[daemon]
log_level = "info"   # trace | debug | info | warn | error

[lua]
entry_point = "~/.config/bread/init.lua"
module_path = "~/.config/bread/modules"

[adapters.hyprland]
enabled = true

[adapters.udev]
enabled = true
subsystems = ["usb", "input", "drm", "power_supply"]

[adapters.power]
enabled = true
poll_interval_secs = 30

[adapters.network]
enabled = true

[adapters.bluetooth]
enabled = true

[events]
dedup_window_ms = 100

[compat]
legacy_hyprland_event_names = true   # dual-emits bread.hyprland.* alongside legacy flat names; see Documentation.md

[notifications]
default_timeout_ms = 5000
default_urgency = "normal"
notify_send_path = "notify-send"

[modules]
builtin = true    # load built-in modules (monitors, devices, workspaces, binds, rules)
disable = []      # list of built-in module names to disable

For the common "when event X happens, do Y" case, you don't need Lua at all: drop rules straight into ~/.config/bread/rules.toml and skip init.lua entirely:

# ~/.config/bread/rules.toml
[[rule]]
on = "device.dock.connected"
run = "~/.config/bread/scripts/dock-connected.sh"

[[rule]]
on = "power.ac.disconnected"
notify = "Unplugged"

It's optional and purely additive alongside init.lua; see Getting started in Documentation.md for the full schema (run vs exec vs notify, wildcard on patterns, and how a malformed rule surfaces via bread doctor).

For anything beyond a single action per event, your automation lives in ~/.config/bread/init.lua. Modules placed in ~/.config/bread/modules/ are auto-loaded after init.lua:

-- ~/.config/bread/init.lua

bread.on("bread.system.startup", function(event)
    bread.profile.activate("default")
end)

CLI reference

All commands communicate with the running daemon over a Unix socket at $XDG_RUNTIME_DIR/bread/breadd.sock.

# Daemon
bread ping                            # Check daemon connectivity
bread health                          # Daemon version, uptime, PID
bread doctor                          # Diagnose daemon and module health
bread doctor --json                   # Output raw JSON

# Lua runtime
bread reload                          # Hot-reload all Lua modules
bread reload --watch                  # Watch config dir and reload on changes

# State and events
bread state                           # Dump full runtime state as JSON
bread state network                   # Read a single path from state
bread state --json                    # Output raw JSON
bread events                          # Stream live normalized events
bread events bread.device.*           # Stream filtered events
bread events --since 60               # Replay events from the last 60 seconds
bread events --fields event,data      # Limit output to specific fields
bread events --json                   # Output raw JSON
bread events --tree                   # Render as a causality tree (caused_by) instead of a flat stream
bread emit <event>                    # Manually fire an event (for testing)

# Profiles
bread profile-list                    # List defined profiles
bread profile-activate <name>         # Activate a named profile

# Modules
bread modules list                    # List installed modules and daemon status
bread modules install /local/path     # Install from a local module directory
bread modules remove <name>           # Remove an installed module (--yes skips confirmation)
bread modules info <name>             # Show full manifest and daemon status
bread modules audit <name>            # Scan a module's Lua source and suggest a [[permissions]] block

# Hooks
bread hooks install-shell [shell]     # Install precmd/preexec/chpwd shell hooks (auto-detects $SHELL)
bread hooks install-git               # Install git hooks (post-commit/checkout/merge) in the current repo

# Compositor integration
bread init                            # Install breadbar's Hyprland layer-rule integration (shows a diff, asks to confirm)
bread init --dry-run                  # Print the proposed diff only, change nothing
bread init --yes                      # Skip the confirmation prompt (scripted/image builds)
bread init --undo                     # Remove the previously installed integration

Bug reports (breadbug)

breadbug reviews and optionally sends a crash, freeze or bug report for a bread app. It is opt-in: nothing is sent unless you choose to, and you see exactly what would be sent first. See docs/breadbug.md.

breadbug                          # pick an app, review the report, save or send
breadbug list                     # installed bread apps, recent problems first
breadbug --app clip --dry-run     # print the exact report
breadbug --app clip --save r.json # save it to a file; nothing is sent
breadbug config upload on         # allow sending (off by default)
breadbug history [--refresh]      # what you sent or saved, with receipts and status
breadbug delete <receipt>         # delete a sent report from the server
breadbug queue [flush|cancel|clear] # reports waiting for the network
breadbug status [--notify]        # how your sent reports are doing; fixes you can update to

Module system

Modules are Lua files (or directories) installed to ~/.config/bread/modules/. Each module must declare itself with bread.module() and have a bread.module.toml manifest.

Installing modules

Modules install from a local directory only. By default a module runs in-process with full, ungated bread.exec() privileges (the same trust model as before), so to use a module published on a git host, clone it yourself and review the Lua before installing from the local checkout. A module can opt into a smaller, enforced footprint by declaring [[permissions]] in its manifest: it then runs out-of-process under an OS-level (Landlock) sandbox limited to exactly what it declared, with a bread table that only exposes the granted namespaces. See Capability-scoped modules and Out-of-process module sandboxing for the full permission taxonomy and what's enforced at the kernel level versus what isn't yet.

git clone https://github.com/someuser/bread-wifi ~/src/bread-wifi
# review ~/src/bread-wifi, then:
bread modules install ~/src/bread-wifi

Writing a module

A module directory looks like:

~/.config/bread/modules/
└── wifi/
    ├── bread.module.toml    ← required manifest
    └── init.lua             ← entry point

bread.module.toml:

name = "wifi"
version = "1.0.0"
description = "WiFi management for Bread"
author = "someuser"
source = "/home/you/src/bread-wifi"
installed_at = "2026-01-01T00:00:00Z"

init.lua:

local M = bread.module({ name = "wifi", version = "1.0.0" })

bread.on("bread.network.connected", function(event)
    bread.log("Network up: " .. (event.data.interface or "unknown"))
end)

return M

Event reference, Lua API, and IPC protocol

These are fully documented in Documentation.md, the single canonical reference (event catalogue, per-function Lua API, runtime-state schema, and IPC protocol), versioned as Bread Automation API v1. This README no longer keeps a parallel copy, to avoid the two drifting apart.


Contributing

Bread is early-stage software. Contributions, issues, and feedback are welcome.

The daemon (breadd) is the most stable part of the codebase. Active development is happening across the Lua API and module system.


License

MIT; see LICENSE.