Two remaining pieces from the original report, both explicitly signed off on: 1. Wire cargo run -p xtask -- check-docs into dev-release.yml as a fail-fast step ahead of the release build/test, so drift between api-schema.toml and the real API surface now fails CI instead of relying on local discipline. 2. Extend api-schema.toml and check-docs to cover the bread CLI's command surface (bread-cli/src/main.rs's Commands/ModulesCommand/ HooksCommand enums) against README.md's "CLI reference" section, not just Lua bindings/IPC methods against Documentation.md. This was the specific blind spot that let modules audit, hooks install-shell/install-git, and events --tree drift out of README in the first place -- check-docs would not have caught that fix without this extension, since its prior scope never touched the CLI-vs-README relationship at all. Extraction reuses the same deliberate-textual-scanning approach as the existing Lua/IPC extractors: depth-tracked enum variant scanning, clap's PascalCase->kebab-case rename convention, and a hardcoded (TABLE_VARS-style) map of which top-level Commands variants delegate to a nested subcommand enum (Modules->ModulesCommand, Hooks->HooksCommand), producing dotted names like modules.audit. CLI commands are versioned against the package version (Cargo.toml), not API_VERSION, since the CLI was never part of that versioned contract -- documented in api-schema.toml's header. Verified check-docs actually catches CLI/README drift, not just passes: temporarily deleted the "bread modules audit" line from README.md, confirmed check-docs failed with the exact right message, restored it. 4 new unit tests cover the extraction and cross-check logic (11 total in xtask, up from 7).
4.5 KiB
Contributing
bread — Reactive automation daemon (breadd) and CLI for Linux desktops.
Part of the bread ecosystem; this repo follows the same branch/release workflow as every other ecosystem product.
Branches
There is one long-lived branch: main. All day-to-day work lands here.
Every push to main automatically builds and publishes a dev-track
build (see Tracks below) — a real install you can test before cutting
anything more formal.
New work — features and bug fixes alike — goes on a short-lived branch:
feature/<short-name>
fix/<issue-number-or-short-name>
Branch off main, open a PR/push back into main when ready. Short-lived
branches get deleted on merge — they never accumulate the kind of drift a
second long-lived branch does.
The release cycle
There's no separate beta or release branch — "stable" and "beta" are both
just tags on main, not branches that need to be kept in sync:
- Work accumulates on
mainviafeature/x/fix/xbranches. Each push auto-publishes a dev build — install it withbakery track set devandbakery update --all, then fix anything broken with another push. - When you want to stabilize before a real release, tag a release
candidate:
git tag vX.Y.Z-rc.1 && git push origin vX.Y.Z-rc.1(push to both remotes). That tag alone triggers a beta-track build — "freezing" is just pausing pushes tomainwhile you test it, not a branch operation. Cut-rc.2,-rc.3, etc. for further fixes. - Once an RC has gone without issues, tag the real release:
git tag vX.Y.Z && git push origin vX.Y.Z— that's what triggers the signed stable release build.
Tracks, from a user's perspective
bakery track show # what you're currently on (defaults to stable)
bakery track set dev # or beta, or stable
bakery update --all # pull the latest build on your current track
| Track | What it is | Published from |
|---|---|---|
stable |
The last tagged release | a vX.Y.Z tag |
beta |
Latest release candidate | a vX.Y.Z-rc.N tag |
dev |
Bleeding edge | main, on every push |
Dev versions are auto-computed (X.Y.Z-dev.<timestamp>+<sha>) from the
latest published stable tag, so they always sort as newer than what you
have installed — no manual version bumping needed. Beta versions are just
the RC tag itself (already valid semver, already sorts below the real
release it's a candidate for).
Local development
cargo build --release --workspace
cargo test --release --workspace
Keeping the API docs honest
Documentation.md's Lua API/IPC protocol sections and README's CLI
reference are hand-written and have drifted from the actual code before —
there's a checked-in registry, api-schema.toml, plus an xtask checker
(cargo run -p xtask -- check-docs) that catches it happening again, and
it's enforced in CI (dev-release.yml fails the build on any drift).
Whenever you add, rename, or remove a bread.* Lua binding
(breadd/src/lua/mod.rs), an IPC method (breadd/src/ipc/mod.rs), or a
bread CLI command (bread-cli/src/main.rs):
- Add/update/remove its entry in
api-schema.tomlto match. - Add/update the corresponding section — a
#### bread.<name>heading inDocumentation.mdfor a Lua binding, a row inDocumentation.md's IPC Methods table for an IPC method, or abread <name>line inREADME.md's "CLI reference" section for a CLI command. - Run
cargo run -p xtask -- check-docsbefore committing. It fails with a non-zero exit and a list of exactly what's out of sync — added but undocumented, stale in the schema, or missing a doc line — ifapi-schema.toml, the code,Documentation.md, andREADME.mddon't all agree. CI runs this too, so anything that slips past a local run still fails the build rather than landing onmain.
CI
dev-release.yml— triggered on push tomain.rc-release.yml— triggered on anyvX.Y.Z-rc.Ntag push.release.yml— triggered on any otherv*tag push, cuts the actual stable release.
All CI runs on a self-hosted runner; nothing runs automatically on plain commits or PRs beyond the track builds above. See bread-ecosystem's docs/release-channels.md for the full policy, including how a new product gets wired onto these tracks.
Questions
Open an issue on this repo's Forgejo tracker.