Persistence layer changes, all backward-compatible with existing
databases via in-place column migration:
- WAL journal mode + a 5s busy timeout so overlapping `--capture-once`
writers and the popup reader stop dropping captures on SQLITE_BUSY.
- `HistoryError` replaces bare `rusqlite::Error` so a filesystem failure
while writing an image file surfaces instead of leaving a row that
points at a file that was never written.
- Image files are created 0600 from the first syscall (O_CREAT|O_EXCL,
mode 0600) — no world-readable window before a chmod. Data and images
dirs are forced to 0700 on every open. `gc_orphaned_images` sweeps
image files no row references (older than 1h, to spare in-flight
writes).
- `pinned` and `is_primary` columns. Pinned rows are exempt from trim
and sort first; `list_entries` breaks timestamp ties by `id DESC` so
ordering (and which rows trim keeps) is deterministic within a second.
- `Retention` caps are now a field on `HistoryDb` (`open_with`), and
`0` is a legal value ("keep no unpinned entries of this kind").
New `config` module: optional TOML at
`$XDG_CONFIG_HOME/breadclip/config.toml`, every key defaulted and
clamped, unparseable file backed up once (bread-utils tomlcfg
discipline). Keys: retention.text/images, panel.width, capture.primary.
Repoint bread-theme, bread-utils, and bread-screenshots at tag v0.7.2
on git.breadway.dev. Drop the 69ce2d67 rev pin now that screenshots
is on a tagged release.
Popup, daemon, and core were split across git.breadway.dev v0.3.0 and
GitHub v0.3.1. Point every bread-theme / bread-utils dep at the same
Forgejo tag. bread-screenshots is not in v0.7.1 (the crate landed after
that tag) so it stays on that remote's main until the next ecosystem
release.
CLAUDE.md now documents the single-trunk model. EVENTS.md is unchanged
— no pin/select verbs.
Same fix as breadpad: build inside the shared pinned Arch container
(bread-ecosystem/ci/, cloned at the sha in ci/bread-ecosystem.rev)
instead of building natively against whatever's on the runner host.
Adds check.yml (clippy + test on feature/**/fix/**) as a fast-fail gate
before anything reaches main.
Verified locally: build, clippy, and test all pass through the new
container path — no pre-existing lint/test debt found here.
Replaces the dev/beta branch split with one trunk (main): dev-track
builds still publish on every push, but the beta track now publishes
from a vX.Y.Z-rc.N prerelease tag instead of a separately-maintained
beta branch. Removes the branch nobody reliably kept in sync.
Same pattern as breadbar/breadbox: render the clipboard-history panel,
capture it via bread-screenshots, then exit. One view ("history"), full
known-size canvas capture since the panel isn't its own layer surface.
active_window()/focused_monitor() (used to anchor the panel next to the
real focused window) both resolve to None inside bread-capture's isolated
environment (HYPRLAND_INSTANCE_SIGNATURE is deliberately unset there), so
the panel falls back to its already-existing centered layout — exactly
the deterministic behavior a screenshot needs, with no screenshot-mode-
specific positioning logic required.
Also fixes the same singleton footgun as breadbox: toggle_or_kill()
kills whatever's holding breadclip's single-instance lock, which is
typically the real running instance. A screenshot run now skips it
entirely instead of fighting over (and killing) the operator's real
clipboard panel.
Documents the dev/beta/main branch and release-track workflow shared
across the bread ecosystem. See bread-ecosystem's docs/release-channels.md
for the full policy this implements.
Beta is now a real stabilization branch: publishes on every push to
`beta` (mirroring dev's model, auto-versioned X.Y.Z-beta.<ts>+<sha>,
base version from the latest published tag) instead of a manual
beta-v* tag. Fixes made during the freeze land via fix/<issue> branches
merged into `beta` directly. The gen-index.sh clone for beta pulls
bread-ecosystem's default branch (main) rather than pinning to dev,
since beta is the more stable track and main now carries the
TRACK-aware script.
Cargo.toml can drift stale relative to the actual last release (observed
on breadbox/breadpad/breadcrumbs/breadpaper), which made the auto-bumped
dev version sort as OLDER than what's already installed — bakery's semver
check correctly refused those "updates". Deriving the base version from
git ls-remote --tags instead is self-healing regardless of Cargo.toml
drift, with a Cargo.toml fallback only for a repo with no tags yet.
The fixed /tmp/bread-ecosystem-ci path races when multiple repos' dev/beta
workflows run close together on the same self-hosted runner — one job's
rm -rf/clone can stomp another's in-progress checkout, causing the
regenerate-index step to fail intermittently. Switch to mktemp -d.
Adds dev-release.yml (publishes on every push to dev) and beta-release.yml
(publishes on a beta-v* tag), mirroring the pattern landing in
bread-ecosystem/bread. Also creates the dev branch for this repo, which
didn't exist before — see bread-ecosystem/docs/release-channels.md for the
three-track policy.
Mirrors tonight's breadbox migration (same shared crate, same duplicated
patterns):
- position.rs's raw socket1 client -> bread_utils::hypr (file removed
entirely, its logic now lives in the shared crate)
- toggle_or_continue's TOCTOU-prone PID-file dance -> bread_utils::singleton
- the layer-shell window setup, Up/Down visible-row navigation, and
click-outside-close gesture -> bread_utils::gtk_popup
- breadclip-core's data_dir(): replaced the buggy
`dirs::data_local_dir().unwrap_or_else(|| PathBuf::from("~/.local/share"))`
fallback (flagged but never fixed in tonight's earlier audit pass —
PathBuf never expands `~`) with bread_utils::xdg::data_dir, which
resolves a real $HOME before ever falling back.
Builds and tests clean across the whole breadclip workspace.
- history.db and images/*.png are now created with 0600 permissions
(owner-only) instead of default umask, since clipboard history can
contain plaintext passwords/tokens.
- breadclipd never persists clipboard content flagged with the
x-kde-passwordManagerHint MIME type (the convention KeePassXC,
Bitwarden, etc. use to mark content they own).
- Replaced breadclipd's 500ms busy-poll loop (2-3 wl-paste forks per
cycle, forever) with wl-paste --watch, so it only reacts on actual
clipboard changes.
- Documented both behaviors in the README.
GitHub Actions self-hosted runners need per-repo registration on a
personal account; Forgejo Actions' runner already serves every repo
with zero setup. Moves release publishing there (dl.breadway.dev stays
the primary bakery target; GitHub release upload is kept as the
fallback via an explicit token, since Forgejo Actions has no ambient
GITHUB_TOKEN) and adds a mirror workflow to keep GitHub in sync
automatically.