sugarrush 2026.8.3

A terminal UI for viewing Nightscout CGM (blood glucose sensor) data
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
<p align="center">
  <img src="assets/logo.png" alt="sugarrush" width="520">
</p>

**Your [Nightscout](https://nightscout.github.io/) CGM data, in the terminal.**
A fast, keyboard-driven TUI for glanceable blood glucose — live value, history,
forecast, alerts, and stats — built with Rust + [Ratatui](https://ratatui.rs/).

[![CI](https://github.com/ronaldlokers/sugarrush/actions/workflows/ci.yml/badge.svg)](https://github.com/ronaldlokers/sugarrush/actions/workflows/ci.yml)
[![release](https://img.shields.io/github/v/release/ronaldlokers/sugarrush?sort=semver)](https://github.com/ronaldlokers/sugarrush/releases/latest)
![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)
![Built with Rust](https://img.shields.io/badge/built%20with-Rust-orange.svg)

![sugarrush running in demo mode](assets/demo.gif)

> ⚠️ **Not a medical device.** Don't use `sugarrush` for treatment decisions —
> always confirm with your meter, pump, or official app.

## Try it in 5 seconds

No Nightscout, no config, no network — just synthetic data:

```bash
sugarrush --demo
```

That's the recording above. When you're ready, point it at your own site
([configure](#configuration)).

## Who this is for

You can use sugarrush for your own readings or to follow someone else's
Nightscout site. Following is a relationship, not just a URL: the person whose
data is shown should know what you can see, why you are watching, and when you
will act on an alert. Agree those expectations together, use a separate
read-only token, and remove that access when it is no longer wanted.

The person wearing the sensor remains the authority on treatment and on who
may see their health data. Sugarrush is an additional display and alarm layer;
it does not replace their official CGM app, agreed care plan, or emergency
arrangements. This matters especially for children and other people who may not
be able to grant or withdraw access on their own: involve them at a level they
can understand and revisit the arrangement as their independence changes.

## What it does

**History & forecast**
- Switchable **graph views** (`Tab`) — a 3h or 24h timeline, or an **AGP**
  (ambulatory glucose profile) folding days of readings into a percentile band
  (median + IQR + 5/95), which also **names the pattern** it finds — e.g.
  `⚠ lows 02:00–05:00 (down to 3.1 mmol/L)`
- Live braille/dot graph you can **pan** (`h`/`l`), **zoom** (`+`/`-`,
  1h–24h), step **day by day** (`[`/`]`), and **jump to a date** (`g`)
- A 24h **minimap** you click or drag to move the window
- Short-term **forecast cone** (uploader predictions or a local AR2 fallback)
  showing the high/low uncertainty band, with a "now" line and a
  *time-to-low/high* ETA

**Alerts & safety**
- A **headless watcher** (`sugarrush watch`) that keeps alarming with no
  terminal open — the 3am case — and hands a single-site alarm to the dashboard
  while it is up
- In-TUI banner + cross-platform desktop notifications (Linux/macOS/Windows),
  switchable to **content-free** so nothing readable lands on a lock screen
- An **Omarchy 4 panel**: the chart, time in range, an ambulatory glucose
  profile, the patterns, whether the alarm is armed, and full settings editing
- Bar output for Waybar, polybar, tmux, i3blocks and Quickshell, including the
  last hour as a **sparkline** and a pill that changes colour for a **predicted**
  crossing, not only a current one
- On **Omarchy**, urgent alerts also take the shell's **on-screen display**,
  which sits above fullscreen windows and is not suppressed by Do Not Disturb,
  and the notification is **clickable to snooze** the site that alarmed
- **Audible alarm** for urgent lows/highs with snooze, per-level tones,
  **quiet hours**, and unacknowledged-alarm **escalation** (incl. phone push)
- Predictive alerts before a threshold is crossed; offline vs. sensor-gap
  distinction so you know *why* data stopped

**Share it**
- **Export** the clinical window (`e`, or `sugarrush export`) as a CSV of every
  reading plus a plain-text summary — time in range across the five bands, mean,
  GMI, CV, and an hour-by-hour profile — to send to a clinician or open in a
  spreadsheet

**Yours to shape**
- In-app **settings screen** (`s`) — edit units, thresholds, alarms, theme,
  and more live, then save back to `config.toml`; the **site URL and token** are
  editable there too, so a bad token is fixed without leaving the app. A detail
  pane explains the selected field and the list shows when more rows are above
  or below the viewport
- Optional **private offline history cache** for instant startup, outage
  context, and cached exports. It is off by default, owner-only, bounded to
  1–90 days, isolated per site, visibly labelled when used, and deleted when
  disabled
- Configurable colours (incl. a colorblind-safe preset), graph style, and
  **multiple sites**`n` to switch between them, `m` for a **follower view**
  that lists everyone you watch at once, worst first. Each site can carry the
  person's IANA timezone so AGP patterns and clinical exports describe their
  day rather than the viewer's clock
- **Status-bar output** for Waybar, Quickshell, tmux, polybar, i3blocks, or
  anything that takes plain text — with a Quickshell panel carrying the chart,
  time in range and patterns (see [Status bars]#status-bars)
- Optionally, **logging carbs and insulin** back to Nightscout — off by default,
  behind a separate token and an explicit confirmation
  (see [Writing treatments]#writing-treatments)

## Writing treatments

Treatment logging is optional and read-only remains the default. A separate
Nightscout `careportal` token can authorize an explicitly confirmed command;
Sugarrush checks its exact treatment-create permission before each write and
keeps a private audit without token or note contents:

```sh
sugarrush treatment --site Alex --carbs 15 --note "snack"
sugarrush treatment --site Alex --insulin 1.5 --at 2026-08-09T14:30:00+02:00
```

The interactive command shows a summary and requires typing the person's name.

Unattended writes are **off by default**. Automation must provide
`--non-interactive --confirm` and a stable `--operation-id UUID`, *and* the
install must grant it in `config.toml`:

```toml
allow_unattended_writes = true
```

That grant is deliberately not editable in the settings screen. The interactive
path is guarded by typing the person's name; the unattended path skips that by
construction, so permitting it should take opening the file — otherwise anything
that can run a command on this machine can write to that person's health record.
`sugarrush about` reports whether it is on.

Reuse the operation UUID after an unknown outcome so Nightscout can deduplicate
the retry. This records what someone reports having taken; it does not recommend a dose,
deliver insulin, or verify that a treatment was clinically correct. Confirm the
accepted entry in Nightscout. Create the write token as a Nightscout Subject
with the `careportal` role, keep the existing `readable` token separate, and
remove the write token in Settings by entering `off` when it is no longer needed.

`sugarrush treatments --days 30 [--site NAME] [--format text|json|csv]`
reviews the owner-only local submission audit. It shows stable operation IDs
for reconciliation but never note text, tokens, or endpoint URLs. It is an
audit of what Sugarrush attempted—not a complete copy of Nightscout.

Inspect or deliberately erase the opt-in private history cache without exposing
its readings:

```sh
sugarrush cache status
sugarrush cache clear --site Alex --confirm
sugarrush cache clear --all --confirm
```

**At a glance**
- Big, colour-coded current value with trend arrow, delta, and a plain-text
  range label (readable without colour)
- Time-in-range across the five clinical bands (very low → very high) with
  time-below-range called out, mean glucose, GMI (estimated A1c), and CV
  (glycaemic variability) over a fixed clinical window (last 14 days by
  default), plus device status (battery, sensor age, last seen)
- Insulin-on-board / carbs-on-board, with carb & bolus markers on the graph

## Install

```bash
# Arch (AUR)
yay -S sugarrush-bin

# Homebrew (macOS/Linux)
brew install ronaldlokers/tap/sugarrush

# crates.io (compiles from source)
cargo install sugarrush

# …or a prebuilt binary via cargo-binstall (no compile)
cargo binstall sugarrush

# …or the shell installer (Linux/macOS) — grabs the right prebuilt binary
curl --proto '=https' --tlsv1.2 -LsSf \
  https://github.com/ronaldlokers/sugarrush/releases/latest/download/sugarrush-installer.sh | sh
```

Prebuilt archives (Linux gnu/musl, macOS x86_64/arm64, Windows) are attached to
every [release](https://github.com/ronaldlokers/sugarrush/releases). From a
checkout: `cargo build --release` (binary at `target/release/sugarrush`).

## Configuration

First run with no config launches an interactive setup wizard. It links to
Nightscout's token help, lets you enter `q` at the URL prompt to leave, and only
saves after Nightscout returns a fresh reading. After setup it points out the
main dashboard keys and how to install and test the always-on alarm. Prefer to
do it by hand? Copy the example:

```bash
mkdir -p ~/.config/sugarrush
cp config.example.toml ~/.config/sugarrush/config.toml
chmod 600 ~/.config/sugarrush/config.toml
```

### Getting CGM data into Nightscout

Sugarrush reads an existing Nightscout site; it does not connect directly to a
Libre or Dexcom sensor. If you do not see fresh readings in Nightscout itself,
set up or repair the uploader before configuring sugarrush. Nightscout's
[supported uploaders guide](https://nightscout.github.io/uploader/uploaders/)
is the maintained starting point because the right path depends on sensor,
phone, region, and whether a loop app is already uploading.

- **Dexcom G6/G7/ONE/ONE+/Stelo:** Nightscout can pull from Dexcom Share using
  its connector, or an uploader such as xDrip+ / xDrip4iOS can send readings.
  If a DIY loop already uploads, Nightscout recommends using that single path
  instead of adding the Share bridge.
- **FreeStyle Libre:** the route varies more by generation and region. Current
  options include Juggluco, xDrip+ / xDrip4iOS, or a LibreView-to-Nightscout
  connector; older Libre sensors may need a separate transmitter.

Confirm a current value and timestamp on the Nightscout web page first. Then
run sugarrush and enter the site's base URL plus a dedicated read-only token.
Do not put Dexcom, LibreView, or Nightscout admin credentials in sugarrush.

### Nightscout token (read-only)

Do **not** use `API_SECRET` (admin-level). Create a read-only token in
**Nightscout → Admin Tools**:

1. Add a **Subject** (e.g. `sugarrush`).
2. Give it the `readable` role.
3. Copy its access token into `config.toml` as `token`.

It's sent as a `?token=…` query parameter and only grants read access — which
is why the site should be **https**. Over plain `http://` the token and your
readings are visible to anything on the network path; sugarrush warns in the
footer (loopback addresses excepted). The URL itself is forgiving: a bare
`mysite.example.com` or a pasted `…/api/v1/entries.json` is normalized to the
base URL.

### Token storage & permissions

The token is stored **in plaintext** in `config.toml`. It's read-only (exposes
your glucose data, not account control), but keep the file private —
`chmod 600`. The setup wizard already does this, and sugarrush warns in the
footer if the file is group/world-readable. No `token_cmd`/env indirection by
design: file-only, documented.

The optional history cache is also stored owner-only under
`$XDG_STATE_HOME/sugarrush/cache`, but contains longitudinal glucose readings
rather than a credential. It is disabled by default. Enabling it is an explicit
privacy choice in Settings; reducing retention bounds future updates, and
turning it off deletes the cache directory.

## Keybindings

| Key | Action |
|-----|--------|
| `q` | Quit |
| `?` | Toggle the keybinding help overlay (works on every screen) |
| `r` | Refresh now (also resumes fetching after a token/URL error) |
| `u` | Toggle mg/dL ↔ mmol/L |
| `Tab` / `Shift+Tab` | Switch graph view (3h / 24h / AGP) |
| `h` / `` · `l` / `` | Pan back / forward in time |
| `H` / `L` · `PgUp` / `PgDn` | Pan a whole window at a time |
| `+` / `-` | Zoom window (1h/3h/6h/12h/24h) |
| `g` | Jump to a date (`YYYY-MM-DD`) |
| `[` / `]` | Previous / next day (same time of day) |
| `End` | Jump to the start of the overview strip |
| `f` / `Home` / `Esc` | Return to live |
| `e` | Export the clinical window (CSV + summary) |
| `a` | Snooze the active person's alarm (also reaches a running `watch`) |
| `n` | Switch site (multi-site) |
| `m` | Follow all sites at once (caregiver view) |
| `s` | Open / close settings |

Settings screen: `↑`/`↓` select, `←`/`→` change, `Enter` edit or run an action
(including add/remove site), `w` save, `?` help, `s`/`Esc` back. The overlay is screen-aware — on settings it
lists the settings keys, not the graph ones.

Caregiver view: `↑`/`↓` or `j`/`k` select, `PgUp`/`PgDn` move five people,
`Home`/`End` jump to the first/last person, `Enter` opens that person's dashboard,
`a` snoozes only that person, `m`/`Esc` returns to the dashboard, `r` refresh,
`s` settings, `?` help, `q` quit. The worst state stays summarized
in the header even while the list is scrolled.
When the minimap is on, click or drag it to move the window — or use `H`/`L`
and `End` for the same navigation from the keyboard.

## Is the alarm armed?

The header answers it, always:

| Chip | Means |
|---|---|
| `⚑ alarm armed` | it will sound |
| `⚑ alarm armed · watcher up` | …and a headless `watch` is running too |
| `☾ quiet until 07:00 · urgent lows only` | quiet hours, with the safety override |
| `☾ quiet until 07:00 · all alarms silent` | quiet hours, no override |
| `⏸ alarm snoozed · 12m left` | someone snoozed it |
| `⚠ watcher stopped` | a watcher was running and isn't now |
| `⚑ alarm off` | nothing is switched on to announce with |

`⚠ escalation inactive` appears alongside when "escalate after" is set but the
push webhook — its only channel — isn't configured.

## Checking the alarm works

"Audible alarm: on" is a claim about a config field, not about whether your
machine can make a noise. `sugarrush watch --test` checks the whole chain and
says what it found:

```
$ sugarrush watch --test
sugarrush alarm self-test

✓ config                 1 site(s), thresholds valid
✓ site                   reachable · newest reading 3m old (5.6 mmol/L)
✓ audible alarm          played via paplay
· quiet hours            set (23:00–07:00), not active now
✓ snooze                 none active
✓ desktop notification   delivered
✓ on-screen display      shown
· push webhook           not configured
✗ escalation             set to 10 min but the push webhook is its only
                         channel — it will do nothing
✓ watcher                running
```

It 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 — so it can go in a cron
or a health check. `--quiet` runs the checks without making a noise. Lines
marked `·` are switched off on purpose; they're worth reading anyway.

The settings screen has a **Test the alarm** row that runs the audible half
in place.

## What the alarm has done

```
$ sugarrush alerts --days 7
sugarrush alerts · last 7 day(s)

08-07 03:14    22m  URGENT LOW  2.9 mmol/L
08-08 02:51     9m  LOW  3.6 mmol/L
08-09 10:43     0m  URGENT LOW  2.5 mmol/L

3 episode(s), 31 minutes alarming
```

Episodes are recorded by both the dashboard and the daemon, kept for 90 days in
`$XDG_STATE_HOME/sugarrush/alerts.jsonl`, owner-only — in follower mode it's
someone else's alert history.

An episode still running shows `—` rather than a duration and isn't counted:
one we haven't seen the end of has no length yet, and guessing would be worse
than saying so.

The same report records privacy-safe channel outcomes (`accepted` or
`rejected`) without storing webhook destinations, tokens, messages, or glucose
values. “Accepted” only means the local notification API or remote endpoint
accepted the request; it cannot prove anyone saw, read, or heard it.

For external monitoring, `sugarrush health --json` reports watcher liveness,
per-site endpoint/data freshness, active snoozes, alarm state, and the last
delivery attempt. It exposes separate `process_healthy`, `data_healthy`,
`alarm_configured`, `currently_suppressed`, and `delivery_degraded` fields: no
single result claims a person can or did receive an alarm. By default the exit
status preserves the original process-and-data contract. Use
`--strict-delivery` when a monitor should also fail for no configured channel,
an active snooze, or a known rejected/retrying delivery.

## Snoozing the alarm

`sugarrush snooze` silences a running `sugarrush watch` — the alarm daemon —
without stopping it, so the *next* alarm still fires:

```bash
sugarrush snooze                         # one configured site only
sugarrush snooze 15m --site Alex         # target one followed person
sugarrush snooze 2h --all                # household-wide, explicitly
sugarrush snooze off --site Alex         # cancel for one person
```

It works whether or not a watcher is running: with none up, it arms the next one
to start. A running watcher picks it up on its next poll. The snooze survives a
service restart, so restarting is not a way to un-silence an alarm someone
deliberately silenced.

Pressing `a` in the dashboard does the same thing, so a snooze set there isn't
lost when you close the dashboard.

## Status bars

`sugarrush status` prints one line and exits — the reading, trend arrow, and
delta, coloured by alert state — in whatever syntax your bar speaks:

```bash
sugarrush status                      # 5.6 → +0.2
sugarrush status --format tmux        # #[fg=#98971a]5.6 → +0.2#[default]
sugarrush status --format polybar     # %{F#98971a}5.6 → +0.2%{F-}
sugarrush status --format i3blocks    # full text / short text / colour
sugarrush status --format json        # {"text":…,"value":…,"units":…,"class":…}
```

Colours follow your configured theme, so the colourblind-safe palette carries
over to the bar. Plain `text` has no markup at all — use it in a shell prompt,
a macOS menu-bar helper, or anything that colours its own output.

Four facts is more than some bars have room for, so each part is switchable —
from the settings screen's **Status bar** section, or in `config.toml`:

```toml
[bar]
arrow = true      # the trend arrow after the reading
delta = true      # the change since the previous reading
units = true      # the unit label, for a bar that renders one
sparkline = true  # the last hour, for a bar that draws it
```

The reading itself and the out-of-range marker are always shown. `units` and
`sparkline` reach the JSON output only — the plain, polybar, tmux and i3blocks
lines have never carried a unit and no text format draws a trace.

Wiring it up:

```bash
# tmux (~/.tmux.conf)
set -g status-right '#(sugarrush status --format tmux) | %H:%M'
set -g status-interval 60

# polybar (config.ini)
[module/glucose]
type = custom/script
exec = sugarrush status --format polybar
interval = 60

# i3blocks (~/.config/i3blocks/config)
[glucose]
command=sugarrush status --format i3blocks
interval=60
```

The format is named `json` because every bar that takes JSON reads the same
document — Waybar, Quickshell, anything else. `waybar` and `bar` are accepted
spellings of it, and `sugarrush waybar` still prints exactly what it always
has, so existing configs need no edit. Example Waybar assets in
[`waybar/`](waybar/): the custom module, a Graph/Settings/About menu (Waybar
≥ 0.11.0), per-state CSS, and Hyprland float rules.

The JSON also carries the reading in parts — `value`, `units`, `arrow`,
`delta` — a `series` of the last hour as `[epoch_ms, value]` pairs, the
30-minute `forecast`, and a `color` from your theme, all of which Waybar
ignores. They are
there so a bar can compose its own line (putting the unit after the value, say)
and colour it without a stylesheet. [`quickshell/`](quickshell/)
is one such bar: a widget for the Omarchy 4 shell that colours itself from that
field, carries the sugarrush mascot, and opens a panel with the last hours as a
chart, the time-in-range bands and the pattern insights.

That panel is fed by `sugarrush snapshot`, which prints the whole picture as one
JSON document — current reading, a series for a chart, stats and patterns, all
in your display units:

```bash
sugarrush snapshot --hours 6 --days 14   # everything
sugarrush snapshot --hours 3 --days 0    # chart only, no history query
sugarrush snapshot --demo                # synthetic, no site needed
```

It always prints valid JSON and exits 0 — a failure comes back as
`{"schema":1,…,"error":"no site configured"}` — so whatever consumes it always
has something to render.

## Always-on alarm

The dashboard can only alarm while a terminal is open, which is the wrong shape
for the job. `sugarrush watch` runs the same alert pipeline headless — fetch,
classify, notify, sound, escalate, push — and logs each transition to stdout:

```bash
sugarrush watch
```

With more than one `[[sites]]` entry it watches **all of them**, each with its
own independent alert state — a low for one person doesn't silence the
announcement for another — and names whose reading it is in every notification
and log line.

Sites can be added, renamed, edited, and removed in the in-app settings screen;
press `w` to persist the list. A newly added site deliberately starts without a
token, so credentials are never copied from the person currently selected.
Each person also has an immutable internal UUID: changing their display name
does not move snoozes, alarm episodes, cached readings, or treatment receipts
to somebody else. Legacy configurations derive this identity from the endpoint
until Settings saves it explicitly.
Each site can either inherit the global alert settings or have its own complete
set of thresholds and alarm channels; select **Alert settings** on that site's
settings screen to switch between the two.

Before following another person, agree what “watching” means: whether the
watcher is expected to respond, which hours are covered, how to contact each
other, and what happens if Nightscout or the watcher is offline. A green screen
is not proof that another person is actively watching; use the watcher status,
alarm self-test, and an out-of-band check-in for safety-critical arrangements.

The dashboard shows `⚑ watcher up` in its header while the watcher is running,
and warns you with `⚠ watcher stopped` if it was running and then stopped — so
"is my alarm actually on?" is answerable at a glance. The watcher also logs a
line every 15 minutes even when nothing happens (`ok · 5.6 mmol/L · in range ·
2m ago`), so a quiet journal is evidence it was watching rather than evidence
of nothing.

It's safe to leave running alongside the TUI: with one configured site, the
dashboard claims that alarm and the watcher stays quiet. With several sites the
watcher remains authoritative for all of them, because the dashboard only
alarms for the person currently selected. The watcher also persists episode
state, so restarting the service doesn't re-announce a low you already saw,
reset an escalation timer, or cancel a snooze.

To run it as a user service — this writes a unit pointing at wherever your
binary actually is, so it works whichever way you installed:

```bash
sugarrush watch --install-service
sugarrush watch --service-status
# Later, if wanted: sugarrush watch --uninstall-service
```

Install and status print the diagnostic location. Linux uses the systemd user
journal; macOS and Windows write to an owner-created private `watch.log` in the
platform user-data directory. Uninstall deliberately retains logs and state
and says where they remain.

These are user-session services: launchd and Windows Task Scheduler coverage
depends on that user being logged in, and an in-process watcher cannot report
its own death. For independent dead-man monitoring, run `sugarrush health
--json --strict-delivery` from a separate machine or monitoring account and
send only a generic failure signal through a separately managed channel. Do
not include site names or glucose values in that signal.

> It's still not a medical device, and it's still only as reliable as the
> machine it runs on, your network, and your Nightscout site. Treat it as one
> layer, not the only one.

## Export

Press `e` in the app, or run it headless — handy from cron, or the morning of
an appointment:

```bash
sugarrush export                            # convenient for one configured person
sugarrush export --site Alex --days 30     # explicitly choose in follower mode
sugarrush export --all --out ~/             # one attributed pair per person
```

In a multi-person configuration, export refuses to guess: use `--site NAME` or
`--all`. Both write two files whose name includes the person and a shared
timestamp: `…​.csv` (every reading,
oldest first, in mg/dL *and* your display unit) and `….txt` (a summary: sensor
coverage, five-band time in range, time below range, mean, GMI, CV, and an
hour-by-hour median/spread profile). The text file is fixed-width on purpose —
it survives email and a printer.

Other subcommands: `sugarrush about` (version + a notification) and
`sugarrush --screen settings` (open straight to settings).

## Commands

<!-- generated from COMMANDS in src/main.rs — a test keeps this in step -->

| Command | What it does |
|---------|--------------|
| `sugarrush [--demo] [--screen settings]` | the dashboard |
| `sugarrush watch` | headless alarm watcher (no terminal needed) |
| `sugarrush watch --test [--quiet]` | check that every alarm channel actually works |
| `sugarrush watch --install-service\|--service-status\|--uninstall-service` | manage the native always-on user service |
| `sugarrush snooze [15m\|2h\|off] [--site NAME\|--all]` | silence the alarm daemon without stopping it |
| `sugarrush treatment --site NAME [--carbs G] [--insulin U] [--note TEXT] [--at RFC3339]` | review and write a durable CarePortal treatment |
| `sugarrush treatments [--days N] [--site NAME] [--format text\|json\|csv]` | review the local treatment submission audit |
| `sugarrush cache status\|clear [--site NAME\|--all] [--confirm]` | inspect or deliberately erase private cached history |
| `sugarrush alerts [--days N] [--site NAME] [--format text\|json\|csv]` | filter or export what the alarm has done |
| `sugarrush health --json [--strict-delivery]` | machine-readable watcher, data and delivery health |
| `sugarrush export [--days N] [--out DIR] [--site NAME\|--all]` | CSV + a clinical summary |
| `sugarrush summary [--days N] [--site NAME]` | the clinical summary alone, on stdout |
| `sugarrush status [--format FORMAT]` | one line for a status bar |
| `sugarrush snapshot [--hours N] [--days N]` | one JSON document: reading, series, stats, insights |
| `sugarrush config [KEY [VALUE]]` | read or write one setting |
| `sugarrush waybar` | alias for --format json |
| `sugarrush about` | version, config and a health check |

`sugarrush --help` prints the same list, `sugarrush --man` writes a man page:

```bash
sugarrush --man > /usr/local/share/man/man1/sugarrush.1
```

## Troubleshooting

**"authentication failed — check your read-only token"**
You almost certainly pasted your `API_SECRET`. sugarrush needs a *Subject*
token: Nightscout → Admin Tools → add a Subject with the `readable` role, then
copy its access token. Press `s` in the app to fix it in place — no need to
edit the config file.

**No sound when an alarm fires**
Work down this list; each is a real cause:
`Audible alarm` off in settings · a snooze still running (the footer shows a
countdown) · quiet hours (only urgent lows sound during them, and only if
`Quiet: urgent-low sounds` is on) · no audio player installed — sugarrush tries
`paplay`, `pw-play`, `aplay`, `ffplay`, `canberra-gtk-play`, `afplay` and
`cvlc`, then falls back to the terminal bell · system volume · the watcher
isn't running (the header says `⚑ watcher up` when it is).

**"config: … is outside the physiological range"**
Your thresholds are in the wrong unit — 3.9 mmol/L is 70 mg/dL, not 3.9. Edit
them under `[alerts]`, or set them on the settings screen, which always uses
your display unit.

**The numbers don't match Nightscout**
Time in range, mean, GMI and CV are computed over a fixed clinical window (the
`AGP days` setting, 14 by default) — not over whatever the graph is showing, so
panning doesn't change them. Nightscout's own reports use different bands and a
different window, so small differences are expected.

**The watcher isn't running / I don't know if it is**
The dashboard header shows `⚑ watcher up`, or `⚠ watcher stopped` if it was
running and stopped. The watcher also logs a line every 15 minutes even when
nothing happens, so `journalctl --user -u sugarrush-watch` tells you whether it
was awake overnight.

**The AUR package is behind**
Releases land on GitHub first; Homebrew, crates.io and the AUR follow within
minutes — unless a channel is having an outage. The
[releases page](https://github.com/ronaldlokers/sugarrush/releases) is the
source of truth for the current version.

## Roadmap

Planned and in-progress work lives in the
[open GitHub issues](https://github.com/ronaldlokers/sugarrush/issues?q=is%3Aissue%20state%3Aopen).
Completed product roadmaps remain available in the closed-issue history.

## License

MIT © Ronald Lokers