buffr — update channel
A version-check + manual-update flow. No automatic binary replacement. Real auto-update needs signing infrastructure (Apple Developer ID + notarization on macOS, Authenticode on Windows, a signing service we don't have yet) so it's deferred to post-1.0. What ships today:
- Once per
[updates] check_interval_hours(default 24 h), buffr makes one HTTP GET against the GitHub releases API:https://api.github.com/repos/{repo}/releases/latest. - The result is cached at
<data>/update-cache.json. - The statusline reads the cache on launch; if a newer release exists it shows
* upd. If the cache is older thancheck_interval_hoursit shows* upd?(stale — we don't know if it's still current). - The user runs
buffr --check-for-updatesto refresh manually. There is no in-chrome "update now" button (no signed binary swap to trigger).
CLI
buffr --check-for-updates # hits the network, prints status, exits 0
buffr --update-status # reads cache, prints status, exits 0
Output format:
up-to-date <current_version>
available <current> <latest> <tag> <html_url>
stale <last_checked_rfc3339> <latest> <tag> <html_url>
disabled
error <message>
Config
[updates]
# Master switch. When false, buffr makes ZERO network calls — the
# `--check-for-updates` flag short-circuits to "disabled" without
# touching the network. The statusline indicator never appears.
enabled = true
# How often `--check-for-updates` is allowed to actually hit GitHub.
# Reads inside the window are served from the disk cache. Minimum 1.
check_interval_hours = 24
# `owner/repo` slug. Forks point this at their own repo.
github_repo = "kryptic-sh/buffr"
What gets sent
A single GET to a public REST endpoint. The request carries no PII:
- Path:
/repos/{repo}/releases/latest - Headers:
User-Agent: buffr/<version>(mandatory — GitHub rejects user-agent-less requests) andAccept: application/vnd.github+json. - No cookies, no auth token, no telemetry payload.
GitHub logs the request like any other API request (IP + timestamp). buffr does not receive that log; we do not run our own collector.
Dismissing a release — API only, not reachable yet
UpdateChecker::dismiss(version) records a release in the cache as "ignored".
Subsequent check_cached/check_now for the same version resolve to UpToDate
instead of Available. Filtering happens at read time, not write time: the
cache stays the source of truth for "what GitHub last reported".
Not user-facing. Nothing outside
updates.rsand its unit tests callsdismiss()— there is no CLI flag and no chrome affordance for it, so a user cannot currently dismiss a release. Both the dismiss entry point and a--reset-update-dismissalsflag to clear the list are outstanding work.
Implementation
crates/buffr-core/src/updates.rs—UpdateChecker,UpdateStatus,HttpClienttrait,UreqClientimpl.crates/buffr-config/src/lib.rs—[updates]section schema + validation (repo shape, non-zero interval).apps/buffr-app/src/main.rs—--check-for-updates/--update-statusCLI short-circuits. Statusline* updindicator wired to the cache read. (Thebuffrsupervisor takes only--heartbeat-timeout/--heartbeat-disableand forwards everything else tobuffr-app, so typingbuffr --check-for-updatesstill works.)
The trait HttpClient exists so unit tests can drive the state machine without
touching the real network. The real network path uses ureq 3.x
(Agent::config_builder()) with a 5 s connect + 5 s read timeout.