2026.8.2
Release Notes
This release turns sugarrush from a dashboard you watch into something that
watches for you. sugarrush watch runs the alarm headless, so a nocturnal low
still wakes you when no terminal is open, and it now follows every configured
person at once — each with its own alert episode, its own snooze, and a record
of what the alarm actually did. You can log carbs and insulin back to
Nightscout behind an explicit confirmation, keep a private local history, and
export a clinical window as CSV plus a plain-language summary. Bars are
first-class too: one JSON line for Waybar, tmux, polybar and i3blocks, and a
full Quickshell widget for Omarchy 4 whose panel charts the last hours against
a typical day, the day's time in range, and the times of day where lows keep
happening.
Added
- sugarrush has a face. The running sugar cube is now the app icon
(assets/icon.png), the wordmark opens the README and leads the Quickshell
panel, and a silhouette of the cube rides in the bar beside the reading. - The Quickshell widget has a popup panel. Clicking the bar pill opens a
panel of labelled cards: the reading now, the last hours as a chart — your
line over a typical day for the same hours, changing colour as it crosses a
threshold, thresholds in their own colours, values and clock on the axes —
the day's five time-in-range bands, and the pattern insights. Hovering the
chart reads out the value and time under the pointer. Each card names
the window it covers, so a 24-hour average is never read as a six-hour one — the parts of the dashboard worth a glance without opening
the TUI. Right click still opens the full app. It fetches only while open,
and reuses its last reading for a few minutes, so the multi-day history the
patterns need is paid for only when someone is looking. sugarrush snapshotprints the whole picture as JSON. One document with
the current reading, a series for a chart, time in range and patterns, in
your display units. Built for the panel; useful to anything that wants
sugarrush's numbers without scraping a bar line.--demorenders it from
synthetic data with no site configured. The document also carries a
typical-day band (median and 25–75% per quarter hour, over the requested
history) for anything that wants to draw today against a usual day.- A bar widget for Quickshell. Omarchy 4 replaced Waybar with a Quickshell
bar, soquickshell/now ships a widget for it alongside the
Waybar examples: the reading, trend and delta in your theme's state colour,
the usual tooltip on hover, and a click that opens the TUI (right click for
its settings screen). Its README also covers the no-plugin route, running
sugarrush waybarthrough the bar's own command module.
Changed
- The Quickshell bar widget prints the unit. The bar now reads
10.5 mmol/L → -0.2rather than10.5 → -0.2: a number by itself names
nothing, and the unit is the one word that says what was measured. Turn it
off withshowUnitson a crowded bar. The sugar cube that used to carry that
job is now opt-in, behindshowMascot. --format waybaris now--format json. The same JSON is read by
Waybar, by the Quickshell widget, and by anything else that takes a JSON
line, so the format is named for its syntax rather than for one bar.
waybarandbarare accepted spellings, andsugarrush waybaris
unchanged — no config needs editing.--format jsonreports the reading in parts.value,units,
arrowanddeltajoin the JSON, so a bar can compose its own line instead
of parsingtextapart. Waybar ignores them.- The Quickshell bar widget no longer pops up a tooltip. Hovering the
reading used to show a second copy of it with a text sparkline; clicking
opens a panel with the real chart, so the tooltip was answering a question
that already had a better answer. --format jsonalso reports the state colour. The JSON now carries a
colorfield holding the hex colour of the alert state, from your configured
theme. Waybar ignores it and keeps styling the module from the CSS class;
it is there for bars that style themselves from the payload instead of a
stylesheet.
Fixed
--helpfits a terminal again. The new command signatures outgrew the
fixed column, so every row past it ran to 138 characters and the description
column stopped existing. Long signatures now put their description on the
next line; the widest row is 97 columns.- A lock left behind by a crash no longer disables treatment writes or the
history cache permanently. Both used a lock file removed on clean exit, and
aSIGKILLor a power cut leaves it behind — with no staleness rule, every
later run waited out the timeout and failed, so one hard kill disabled the
feature until someone found and deleted a file nothing had told them about. An
abandoned lock is now reclaimed after 30 seconds, a live one is still
respected, and the timeout message names the file and what to do about it. - A successful treatment write is no longer reported as a rejection. The
client read the array Nightscout returns on success — the documents it just
stored — as a list of refusals. So a treatment that Nightscout accepted was
reported as rejected, and following the retry advice wrote it again: two
identical carb or insulin records for one dose, both reported as failures.
Only a non-empty array now counts as accepted; every other response shape is
reported as unknown, which tells you to check Nightscout and retry with the
same operation ID rather than a new one — the one retry that cannot duplicate. - Health and delivery joins survive person renames safely. Concurrent
follower results and new delivery receipts now carry immutable site IDs;
legacy name-only receipts remain readable without letting a reused display
name inherit another person's current delivery status.
Added
-
Unattended treatment writes now need a grant in
config.toml.
treatment --non-interactivecould write to someone's health record with no
human in the loop, on a flag combination alone — available to anything that
can compose a command line. It now also requiresallow_unattended_writes = true, off by default and deliberately not editable in the settings screen, so
the grant is a decision made once in a file you own.sugarrush aboutreports
whether it is on, and now also reports whether each site has a write token at
all — the presence, never the value. -
Treatment submissions have a privacy-safe receipt view.
treatments
filters the bounded local audit by person and time, emits text/JSON/CSV, and
exposes stable operation IDs for reconciliation without notes or credentials. -
Managed watchers now point to usable diagnostics on every platform.
macOS and Windows services write to a private user-data log, install/status
print its path plus the strict health command, and uninstall says that logs
remain; platform session and independent dead-man limits are documented. -
Operational health is explicit instead of collapsing unlike guarantees.
JSON now separates process, data, configured-channel, suppression, and known
delivery status;--strict-deliverygives external monitors an opt-in
degraded exit policy without claiming that an accepted alert was received. -
Multi-person exports can no longer silently choose the first person. A
follower must select--site NAMEor explicitly request--all; filenames
and output identify their subject and the matching cache/timezone are used. -
Private cache storage is inspectable and selectively erasable.
cache statusreports each person's entry count, date span, and bytes without
printing readings; confirmed clear commands target one person or everyone. -
People now have immutable internal identities. Renaming a display label
no longer moves alarm episodes, snoozes, cached readings, or treatment audit
receipts between people; legacy configurations receive a deterministic ID
and newly added sites receive a generated UUID. -
Treatment writes are available behind an explicit security boundary. A
separate per-site CarePortal token is masked in Settings and capability-
checked before every confirmedtreatmentcommand; amounts, timestamps, and
notes are validated and each accepted/rejected attempt is recorded in an
owner-only audit without credentials or note text. -
Offline history is available as an explicit privacy choice. An opt-in,
owner-only per-site cache gives instant startup and outage context without
ever presenting cached data as a live fetch; retention is bounded to 1–90
days and disabling it deletes the local record. -
Caregiver review now follows the person's context. Each site can set an
IANA timezone used by AGP bucketing, pattern names, CSV offsets, and clinical
summaries; alert history can be filtered with--siteor emitted as
structured JSON/CSV for private audit workflows. -
The always-on watcher now has native service management on every shipped
desktop platform. One command installs, starts, inspects, or removes a
systemd user service on Linux, a launchd agent on macOS, or a Task Scheduler
task on Windows; the old--install-unitspelling remains an alias. -
Alarm delivery is now auditable and monitorable. Alert history records
privacy-safe channel outcomes using careful accepted/rejected language, and
sugarrush health --jsonexposes watcher liveness, per-site freshness,
snoozes, alarm state, and the latest delivery attempt for external monitors. -
Caregiver actions now target the right person. The follower list has a
stable selected row that opens that person's dashboard with Enter and
snoozes only that person witha; the CLI accepts--site NAMEand requires
explicit--allwhen several sites are configured.
Fixed
-
Fast alarm transitions and watcher webhooks now survive restarts. The
three-second reaction path persists episode latches immediately, while a
bounded owner-only webhook outbox retries outside the alarm loop, resolves
destinations from current config, and cancels obsolete sends on recovery. -
Private cache opt-out is now durable across running processes. Cache
merges and deletion are serialized, disabling writes a persistent boundary
that stale dashboards cannot cross, and write/deletion failures are surfaced
instead of silently pretending history was retained or removed. -
Treatment writes now survive ambiguous failures safely. An operation is
durably recorded before sending, transport uncertainty is distinct from
rejection, explicit retries reuse one UUID, remote acceptance is reported
even if final auditing fails, future entries are rejected, and interactive
writes require reviewing the person, amounts, and timestamp. -
Webhook delivery no longer blocks the watcher's three-second alarm loop, so
a slow destination cannot delay sound or stale-data detection for other
followed people. -
Settings now protect changes and credentials as a complete workflow. Push
destinations can be replaced without revealing embedded topics or tokens,
new and edited Nightscout sites must return a fresh reading before saving,
and leaving with dirty settings requires an explicit Save, Discard, or Cancel
decision; Discard restores the last loaded or saved configuration. -
The follower screen now scales past one terminalful of people. It has
worst-first scrolling and paging with explicit above/below affordances, a
screen-specific help overlay, bounded names and concise failure text so long
input cannot break the safety columns, and a header that keeps the worst
state visible while the list is scrolled. -
First-run setup now gets users all the way to a working dashboard. The
wizard has an explicit exit hatch and Nightscout token-help link, verifies
that the site returns a reading from the last hour instead of treating an
empty response as success, and finishes with the key dashboard controls plus
the commands for installing and testing the always-on alarm. -
Each followed site can now have its own alert settings. A person can
inherit the global thresholds and channels or use a complete override edited
from the same settings screen; the dashboard, followers list, status output
and headless watcher all classify that site with its effective settings. -
Sites can now be added and removed in the settings screen. Site names,
URLs and read-only tokens are editable in-app, additions never copy another
person's token, and the final site cannot be removed accidentally. -
The documentation now covers the human and technical on-ramp for
following. It explains consent, shared expectations, read-only access and
the limits of remote monitoring, then points Libre and Dexcom users to the
maintained Nightscout uploader paths so a new user can get readings into
Nightscout before configuring sugarrush. -
sugarrush aboutis now a real diagnostic. The issue template asks for
its output, and it printed a version number and the safety note — so every
bug report arrived without the answers that matter for a CGM alarm. It now
reports the build and toolchain, terminal and session type, config path and
validity, site count with hosts (not URLs) and whether a token is set,
thresholds, which alarm channels are switched on, whether a watcher or
dashboard is running, any active snooze, and how many alerts were logged this
week. No secrets: the token is reported as set or not set. -
sugarrush --manwrites a man page. Packagers had nothing to install as
sugarrush.1, soman sugarrushsaid "No manual entry" everywhere. The man
page,--helpand the README command table now all render from one table in
the source, with a test that keeps the README in step. -
sugarrush alertsshows what the alarm has actually done. Nothing kept a
record, so "did it go off last night, and for how long?" was unanswerable —
the systemd journal only exists if you run the daemon that way, is rotated by
someone else's policy, and says nothing about alarms the dashboard handled.
Episodes are now logged (owner-only, 90 days) andsugarrush alerts --days 7
prints them with durations. An empty report says so and says it might mean
nothing was running to notice — a quiet week and a dead watcher look
identical otherwise. -
The header always says whether your alarm is armed. Four things could
silence it with no on-screen evidence — quiet hours, a snooze, a watcher that
stopped, and an alarm with nothing switched on to announce with — and the app
never mentioned any of them. One chip now answers it, naming the most
suppressing condition:⚑ alarm armed · watcher up,☾ quiet until 07:00 · urgent lows only,⏸ alarm snoozed · 12m left,⚠ watcher stopped,
⚑ alarm off. Escalation configured with no push channel is called out
alongside as⚠ escalation inactive. It lives in the header, so unlike the
old snooze chip it survives an error state. -
sugarrush watch --testchecks that the alarm can actually reach you.
There are eight independent reasons a night can pass without a sound — the
alarm switched off, quiet hours, a forgotten snooze, no working audio player,
no watcher running, a dead notification daemon, a broken push URL, or
escalation configured with no channel to escalate on — and nothing in the app
could tell you which applied. The self-test walks all of them, plays a real
sound, sends a real notification and a real webhook, and exits non-zero if
anything that is switched on doesn't work.--quietchecks without making a
noise. There's a Test the alarm row in the settings screen for the
audible half. -
sugarrush snoozesilences the alarm daemon. Until now the only way to
stop a 3am alarm fromsugarrush watchwassystemctl --user stop, which
also disarms the next one.sugarrush snooze 15m(or2h, oroff)
silences it without stopping it, works whether or not a watcher is currently
running, and survives a service restart. Pressingain the dashboard now
does the same, so a snooze isn't lost when you close it. -
Every time-in-range band now has a number, not just a colour. The stats
panel printed only "in range" and "below"; above-range and very-low existed
solely as segments of the bar — and on the default palette two of those
segments are the same red. The line now reads e.g.43% in range · 29% below (14% very low) · 29% above, shedding detail whole as the pane narrows rather
than clipping a percentage into a different number. -
The clinical export cites its sources. Time-in-range and CV goals now
reference the 2019 international consensus (Battelino et al., Diabetes Care)
and GMI references Bergenstal et al. 2018, with a note that the consensus
targets are stated for 70–180 mg/dL while the percentages are computed
against your configured thresholds — so a clinician can tell whether they're
comparing like with like.
Fixed
- Alarm runtime edge cases now fail visibly without blocking detection. The
watcher warns when a configured push destination uses cleartext HTTP,
implausibly future-dated readings cannot suppress stale-data detection,
audio-player discovery runs off the async alarm loop, and the documented
delivery policy explains why failed one-shot notifications are surfaced but
not blindly replayed after recovery. - Local files and Nightscout responses now have explicit safety bounds.
Alarm WAVs live in an owner-only runtime directory instead of predictable
shared-temp paths, alert-log append and compaction are serialized across the
TUI and watcher, oversized API bodies are rejected at 8 MiB, and unreadable
or corrupt watcher state is reported instead of silently looking empty. - Opening a multi-site dashboard no longer silences every followed person's
watcher for 30 seconds. The TUI wrote an alarm-claim heartbeat at startup
before checking how many sites it covered. Startup and later site changes now
use the same rule: only a single-site dashboard claims the alarm, while a
multi-site watcher remains active and its liveness is shown in the header. - A slow followed site can no longer stall every alarm. The headless
watcher used to await entries and device status for each person in sequence
inside the same loop that rechecks alarms every three seconds. Polls now run
concurrently in the background, with at most one per site, so stalled
Nightscout requests cannot delay local stale detection or another person's
alarm cadence. - Watcher retries and concurrent saves can no longer erase alarm state. A
site skipped during retry backoff used to disappear from the persisted
episode map, and asugarrush snoozecommand issued while the daemon was
polling could be overwritten by its older snapshot. Every site now remains
restart-safe, while serialized updates merge the latest external snooze
immediately before the watcher saves. - A sensor gap now notifies and escalates as fast as it starts beeping. The
audible alarm ran on a 3-second tick while notifications and the escalation
webhook only went out on a refresh, so a gap that crossed into "no recent
readings" between refreshes sounded immediately and then stayed silent on
every other channel for up to a full refresh interval. All channels now fire
on the same pass. - Refreshes are faster and ask for less. The five supplementary reads
(treatments, device status, sensor age, history, overview) were awaited one
after another, costing the sum of five round trips to your Nightscout; they
now go out together and cost the slowest one. The sensor-age lookup — a
second/treatmentsrequest every cycle for a number that changes twice a
month — is now cached for 30 minutes. - The AGP fan renders on terminals without 24-bit colour. It was painted
as RGB cell backgrounds, which collapse on 16-colour consoles, tmux and SSH
sessions with noCOLORTERM— leaving an unlabelled median line where the
percentile fan should be. Those terminals now get the fan as shaded blocks in
the theme colour, which also distinguishes the two bands by texture rather
than colour alone. - The AGP legend no longer disappears when there's something to report. The
"median + IQR + 5/95" key was replaced by the pattern headline, so the reader
lost the key to the chart exactly when the chart had a finding. Both are
shown. --demois no longer silently ignored by the subcommands.sugarrush watch --demolooked like a safe way to try the alarm out and instead started
the daemon against the real site and the real config;export,statusand
waybarignored the flag the same way. They now say so and exit non-zero.- The AGP no longer calls one bad night a pattern. Insights were guarded by
how long a run lasted but not by how many days fed it, and with a single
day's readings the 25th percentile and the median are the same number — so
one rough night could be named as a recurring overnight low, on screen and in
the clinician export. A time-of-day pattern now needs readings from at least
three separate days. - Chart time labels no longer collide into a date that never existed. On a
narrow terminal the threeMM-DD HH:MMstamps under the graph overlapped and
rendered as text like8-09 01:-09— a wrong reading of when, on a chart
people read clinically. Labels now shrink to the clock alone (the pane title
already carries the dated range) and drop middles before they can overlap;
the AGP hour labels thin the same way. ?now works on every screen. Pressing it in the caregiver view did
nothing, then the overlay appeared unbidden on the next dashboard render; the
settings screen — the one with thirty rows of unexplained options — had no
help key at all. The overlay opens over whatever screen you're on, any key
closes it, and both footers advertise it. On settings it lists the settings
keys rather than the graph ones.- Two settings rows explain themselves again. Pressing
←/→on the site
URL or on push alerts is meant to answer "press enter to edit" and "set
push_url in config.toml"; both messages were written and then erased before
anything drew them, so the rows looked like dead keys. - Text prompts put the real cursor where you're typing. The site URL, the
token and the date-jump prompt drew a fake blinking_and never positioned
the terminal cursor, so screen-reader caret tracking and braille cursor
routing had nothing to follow — worst on the token field, where the text is
bullets and the caret is the only cue. The blink is gone too: it could not be
turned off, which is a problem for anyone with a migraine or vestibular
trigger. - The live dot now reports the connection, not the view. A green
●sat
next to a red authentication error, because the dot belonged to the
live/historyview mode and knew nothing about the network. The dot is now
green when the data is current, amber◌during a sensor gap, and red✖
when the site is unreachable;live/historystays as the view label. - One failure, one explanation. A rejected token produced three different
messages across three panels — "no data in this window…", "no readings in
this window…" and "loading overview…", the last of which was untrue: nothing
was loading and nothing would. Empty panels now give the same reason, and a
paused fetch never claims to be loading. - The glucose reading no longer disappears on a short terminal. Below
roughly 22 rows the fixed-height panes were crushed while the graph kept its
full size, socurrentcollapsed to a border and the number itself was not
on screen at all — on a tiling window manager, a phone SSH session, or a
terminal at 200% zoom. The layout now sheds panes deliberately: stats first,
then the overview strip, thencurrent's borders in favour of a one-line
readout with the value, arrow, state and range bar. The reading is the last
thing to go. - A slow or wedged Nightscout no longer freezes the dashboard. The run
loop waited for the whole fetch chain — up to five requests at a 12-second
timeout each — before it would handle a keypress, redraw, or sound the alarm.
A site that accepted the connection and then went quiet left an app that
looked alive and answered nothing, with the alarm silent for the duration.
Fetches now run in the background: keys, the graph and the alarm keep working
throughout, and the reading updates when the data lands. - The alarm no longer fires a burst after a stall. Missed ticks were
replayed back-to-back, so waking a suspended laptop set off one alarm sound
per missed three-second tick instead of one alarm. - A warning no longer hides the way to fix it. Any error or warning took
over the whole footer, including? helpands settings— and two of them
(a readable config file, an unencrypted site) never go away on their own, so
a user in that state never saw a keybinding hint again. Warnings now share
the line with? help, and are shortened with an ellipsis rather than being
cut off mid-sentence. - The alarm banner is readable on every palette. It drew black text on the
alert colour, which measured as low as 2.2:1 — worst of all on the
colourblind palette, the one chosen for legibility. The text colour is now
picked from the background it sits on. The banner also honours the theme for
every state; "no data" was hardcoded and ignored your palette entirely. - Status-bar output says how bad it is, not just what colour. Only the
Waybar format carried the alert state, so on tmux, polybar and i3blocks the
colour was the entire signal — and--format text, the one a shell prompt or
a screen reader reads, carried no state at all. Non-normal readings are now
prefixed!!,!or?. - The default palette gives "low" and "urgent low" different colours. Both
were plain red, so the split the time-in-range bar, the range bar and the
followers list all draw was invisible without reading the label.
Fixed
- No more "heading low" invented across a sensor gap. The short-term
forecast assumed its two readings were five minutes apart and never checked,
so a pair either side of a dropout was extrapolated as if the change had
happened in five minutes — a flat trend across 40 minutes projected a low and
fired a prediction. When the spacing isn't right, there is now no forecast
rather than a fabricated one. - The watcher polls once a minute instead of every few seconds. It inherited
the dashboard's interval, which is tuned for a responsive screen — about
17,000 requests a day per site against a self-hosted Nightscout, and a radio
kept awake for readings that arrive every five minutes. It also now respects
its own retry backoff instead of hammering a site that is down. - Another user on the same machine can't silence your alarm. Without a
per-user runtime directory the alarm handshake used a shared path in/tmp,
where anyone could pose as a running dashboard and keep the watcher quiet
indefinitely. The path is now per-user, and a heartbeat that isn't ours is
ignored rather than obeyed. - The watcher's saved state is written safely. It was rewritten in place
every cycle, so an interrupted write left a truncated file that loaded as
"no state" — cancelling an active snooze and restarting an escalation timer,
the two things it exists to prevent. It's now written atomically and
owner-only, since in follower mode it names another person. - Duplicate readings no longer flatten the delta. A site fed by two
uploaders holds each reading twice, which made the change-since-last-reading
show 0 during a genuine rise and double-counted those minutes in the stats. - Sensor age stops disappearing. It was read from the newest 50 treatments
of any kind, which for a pump user covers about three days — while a sensor
lasts ten to fourteen, so the sensor-change event fell off the end. The
server is now asked for sensor events specifically. - Two sites can't share a name. Alarm state is tracked per site name, so a
duplicate meant announcing a low for one person marked it announced for the
other. Startup now says so instead.
Fixed
- Push alerts now say whose reading it is, and respect your privacy
setting. The webhook is the only channel that reaches a phone, and with
several sites configured it sent a bare "URGENT LOW" with no way to tell
which person it was about. It also always spelled out the glucose value, even
withNotification detailset to generic — so a setting people turn on for
privacy was shipping their reading to a third-party broker anyway. - An unencrypted webhook is now flagged, the way an unencrypted site URL
already was. Ahttp://push URL sends your alerts in clear text; the
settings row now says so. (The topic path is still never displayed — it's a
password in all but name.) - Exports are written owner-only, and tell you where they went. Files
holding two weeks of glucose readings were created world-readable, while the
config file holding a read-only token was carefully created0600. The
in-appekey also reported a bare filename, so it wasn't clear which
directory your health data had landed in; it now prints the full path. - Exported CSVs can't corrupt or execute in a spreadsheet. Fields are now
quoted and escaped, and a value that a spreadsheet would run as a formula is
neutralised — which matters because the trend value comes from the server,
and in follower mode that's someone else's server. - The config-permissions warning now appears in every mode. It only showed
in the dashboard, so the person running the headless watcher — the one least
likely to open the dashboard — never learned their token file had become
readable by others.
Added
sugarrush --helpand--version. There were none:--helpopened the
dashboard, and on a machine with no config it opened the setup wizard and
started asking for a Nightscout token. Unknown arguments now say so and exit
instead of being silently ignored.sugarrush watch --install-unitwrites a systemd user service pointing at
wherever your binary actually is, and prints the commands to enable it. The
old instructions told you to copy a file out of a git checkout — which four of
the five install methods never produce — and the unit hardcoded a path only
cargo installuses.- A troubleshooting section and a command table in the README, including
every reason the alarm can be silent, in the order worth checking.
Fixed
- The systemd unit now survives logging out. It was tied to
graphical-session.target, which sway, Hyprland without uwsm, i3 and bare X
never activate — sosystemctl --user enable --nowappeared to work and then
never started again after a reboot. It now usesdefault.target, drops
PartOf=, and ships with hardening directives. config.example.tomlsetrefresh_secsinside[minimap], where it
parsed as a minimap key and was silently ignored — so copying the example and
changing the refresh interval did nothing. A test now parses the shipped
example and asserts what it actually means.- The keybinding overlay is sized from its contents. It was a fixed 56
columns, which clipped its longest line and cut off "press any key to close",
so the overlay never said how to leave it. It also now mentions that
watch,exportandstatusexist. - A broken release can no longer publish to the AUR. The job ran whenever
the release workflow wasn't cancelled — and a failure isn't a cancellation.
Fixed
- Looking at yesterday no longer silences today's alarm. Panning or jumping
into history made the app classify the historical reading, so an urgent low
happening right now read as "in range" — and because the dashboard tells the
watch daemon to stay quiet while it's open, the whole system went silent for
as long as you were reading history. Only the graph is historical now; the
alarm always follows the live edge. - A site that has never connected now raises the alarm. A watcher started
with a wrong token, or against a site that was never reachable, reported
"in range" indefinitely — indistinguishable from a healthy quiet night. After
the staleness window with nothing received at all, that's now a sensor gap
like any other. - With several sites configured, the dashboard no longer silences the
watcher. The dashboard alerts on the site you're viewing, but it was
tellingsugarrush watch— which covers every configured site — to stand
down, so a caregiver's other people went unalarmed whenever the dashboard was
open. It now only claims the alarm when it genuinely covers everything. - An undelivered desktop notification is reported instead of assumed. If no
notification daemon is running the D-Bus call fails silently, so "Desktop:
on" could be a lie — and paired with a failing audio player, that's two dead
channels both reporting healthy. The footer now says when notifications
aren't getting through.
Fixed
- The Nightscout token can no longer leak into an error message. Because
Nightscout takes the token as a URL query parameter, and the HTTP client
included the full URL in its errors,sugarrush exportprinted the token in
cleartext whenever a request failed — into cron mail, the journal, terminal
scrollback, and any bug report someone pasted. Request URLs are now stripped
from every client error before it can be displayed. - A units mismatch in
config.tomlcan no longer disable the low alarm.
The example config is written in mmol/L, so changingunitstomgdland
nothing else left thresholds likelow = 3.9mg/dL in force — and since
every real reading sits above them, a 40 mg/dL hypo was classified as urgent
high. Thresholds are now checked against the physiological range on load: an
implausible value falls back to the safe default, crossed thresholds are put
back in order, and each correction is reported on stderr and in the footer,
naming the value and pointing atunits. The settings screen has enforced
these rules for a while; the config-file path now matches it. - Snoozing a sensor gap no longer silences the low that follows it. An
alert episode was tracked as "urgent or not" rather than as which urgent
state, so a sensor gap and the urgent low that arrived when the sensor came
back were treated as one continuous episode: silencing the gap at 03:00 also
silenced the 40 mg/dL reading two minutes later, swallowed its push, and left
the escalation timer running from the gap — announcing "STILL URGENT LOW
after 20 min" for a low that was two minutes old. A change of urgent state is
now a new emergency: it re-arms the alarm, pushes at its own onset, and
restarts its own escalation clock. Repeated readings of the same urgent
state still share one episode, so a snooze keeps working. - A failed audio player no longer counts as a sounded alarm. sugarrush
picked the first player it could launch — but launching only proves the
program exists, not that it reached an audio server.paplayis installed
almost everywhere and exits immediately when the server isn't reachable (a
service started before the session, an SSH login, a container), with its
error already discarded — so the alarm was silent and the terminal-bell
fallback was never reached. sugarrush now checks that the player is still
playing shortly after launch, moves on to the next one if it isn't, and rings
the bell when none of them work. A player that fails is remembered, so it's
tried once rather than every few seconds all night.
Added
- The dashboard now tells you whether the alarm watcher is running. Nothing
ever read the watcher's heartbeat, so a deadsugarrush watchand a quiet
night looked exactly the same. The header shows⚑ watcher upwhile it's
alive and⚠ watcher stoppedif it was running and then wasn't — and stays
quiet for anyone who doesn't use the daemon, so it's information rather than
nagging. sugarrush watchsays it's alive even when nothing happens. It logged
only alert transitions, so the morning after a missed alarm an empty journal
could mean "glucose was flat all night" or "the daemon was dead" with no
way to tell them apart. It now writes a line every 15 minutes —
ok · 5.6 mmol/L · in range · 2m ago— so a quiet journal proves it was
watching.- Step through history a day at a time with
[and], keeping the same
time of day — checking "how was last night?" no longer means typing a date or
panning there a half-window at a time. - The AGP now names its patterns. Reading a recurring overnight low off a
percentile fan is a skill; the AGP title now states the worst finding
outright —⚠ lows 02:00–05:00 (down to 3.1 mmol/L)— and the exported
summary lists every one under a Patterns section. A "lows" window is a
time of day where a quarter of readings or more sit below target; "highs" is
where the typical reading is above it. Runs shorter than 45 minutes aren't
reported, and a gap in the data never joins two windows into one. - Follow more than one person. With several
[[sites]]configured,m
opens a follower view listing everyone at once — value, trend, how old the
reading is, and the alert state — sorted worst first, with a header that names
whoever needs attention. A site that can't be read ranks with the urgent ones
rather than showing a blank row that reads like "fine".sugarrush watchnow
watches every configured site too, each with its own independent alert
episode, naming the site in notifications and in the log. - Status-bar output for bars other than Waybar.
sugarrush statusprints
one line in the syntax your bar speaks —--format text(no markup),
tmux,polybar,i3blocks, orwaybar— coloured from your configured
theme, so the colourblind-safe palette carries over.sugarrush waybaris
unchanged and still prints the same JSON. - An always-on alarm watcher.
sugarrush watchruns the alert pipeline
headless — no terminal needed — so a nocturnal low still wakes you when the
dashboard isn't open. It defers to a running dashboard (both write a
heartbeat, so you never get two alarms for one low) and persists episode
state, so restarting the service doesn't re-announce an ongoing low, restart
an escalation timer, or cancel a snooze. Example systemd user unit in
packaging/systemd/. - Export what you're looking at. Press
e(or runsugarrush export) to
write two files for the clinical window: a CSV of every reading — oldest
first, in mg/dL and your display unit — and a plain-text summary with sensor
coverage, five-band time in range, time below range, mean, GMI, CV, and an
hour-by-hour median/spread profile. Meant for sending to a clinician or
opening in a spreadsheet, instead of screenshotting a terminal.
sugarrush export --days 30 --out ~/for a different window or directory.
Fixed
- The declared minimum Rust version was wrong —
rust-versionsaid 1.82,
but the dependency tree hasn't built on anything below 1.89 for a while,
socargo installcould fail with a confusing dependency error instead of a
clear "your toolchain is too old". CI now builds against the declared MSRV
every run, so it can't drift again. - Half the uploader requests are gone. Each refresh fetched
/devicestatustwice — once for battery/IOB/COB and once for the forecast.
It's now one request, which also rules out the two halves coming from
different records if the uploader posts in between.