Updates
tmnl pings GitHub at launch to see whether you’re on the latest version. The check is best-effort, runs in the background, and never blocks startup.
What happens
Section titled “What happens”On every launch, a short-lived background thread issues a single blocking GET
to https://api.github.com/repos/chris-mclennan/tmnl/releases/latest, compares
the response’s tag_name against the running CARGO_PKG_VERSION, and — if the
remote is newer — prints a one-liner to stderr:
tmnl: v0.1.6 available — https://github.com/chris-mclennan/tmnl/releases/tag/v0.1.6Where you see this depends on how you launched. From a terminal, the line
shows up in the parent shell alongside any other output tmnl emits. From the
dock or open target/tmnl.app, the stderr stream ends up in Console.app on
macOS (filter by process name “tmnl”). A toast inside the focused tmnl
window is planned but not yet wired (v2 plan below).
The implementation lives in src/update_check.rs.
It uses ureq (the small blocking HTTP client) instead
of an async crate so the check drops directly into tmnl’s winit + wgpu
setup without dragging in a runtime.
Frequency
Section titled “Frequency”The check runs once per process launch — no in-process polling, no file-based cache. If you keep tmnl running for days, you won’t see fresh release announcements until you relaunch.
This is intentional. Update checks belong at the natural “start of session” boundary, not interleaved with day-to-day work. There’s no caching layer beyond what the OS does for the HTTPS connection itself, so the next launch re-asks GitHub from scratch.
Failure modes (all graceful)
Section titled “Failure modes (all graceful)”The check is wrapped in best-effort error handling — every failure mode leaves tmnl running normally with no user-visible noise:
| What goes wrong | What you see |
|---|---|
| Offline / no DNS | Silent — no announcement |
| GitHub API down or rate-limited (HTTP 5xx/429) | Silent |
| Malformed JSON in the response | Silent |
| Local clock skewed past TLS cert validity | Silent |
| You’re already on the latest | Silent (the common case) |
| You’re on a newer-than-released dev build | Silent (version compare) |
There is no retry logic. If GitHub rejects this launch’s request, tmnl waits until the next launch to try again.
Turning it off
Section titled “Turning it off”Set check_updates = false under the [ui] table in
~/.config/tmnl/config.toml:
[ui]check_updates = falseThe change takes effect on the next launch. There’s no Settings-overlay row for this knob yet — it stays TOML-only.
Skipping the check has no functional consequence beyond suppressing the
“newer release available” announcement. You’ll still know about new releases
through the GitHub releases page, the project README, or cargo install tmnl-rs (which always pulls the latest version on crates.io).
What the request actually sends
Section titled “What the request actually sends”The request is what ureq’s default User-Agent ships — ureq/<version> —
plus the standard Accept: */* headers. It contains no telemetry, no
identifying token, no auth header, and no payload. GitHub’s anonymous-API
rate limit (60 requests per hour per IP) covers the use case comfortably for
single-user laptops; an environment that launches tmnl thousands of times an
hour would hit the cap and silently fall into the failure path above.
Family consistency
Section titled “Family consistency”mnml and mixr ship the same update_check shape against their own
repositories — same [ui] check_updates toggle, same once-per-launch cadence,
same silent failure modes. If you have all three installed, each one
announces its own updates independently against its own GitHub repo.
That means setting check_updates = false in one app’s config doesn’t
affect the others; they each read their own ~/.config/<name>/config.toml.
Set it in all three configs if you want a fully-quiet launch experience
across the family.
v2 plan — welcome-banner integration
Section titled “v2 plan — welcome-banner integration”The read APIs (update_check::latest() and
update_check::take_pending_announcement()) are already wired but
dead_code-gated until the integration lands. The plan is for the welcome
overlay (the centered modal you see on a bare launch when
~/.config/tmnl/recents.toml has entries) to surface “new version
available” as a non-blocking chip in the corner — same affordance as the
stderr line today, but discoverable without having to scan a parent
terminal or open Console.app.
There’s no ETA, and the stderr behaviour will stay even after v2 ships — it’s useful for launches from a terminal where the welcome screen never appears.