CLI Tool
burnrateshipped
A terminal dashboard for multi-window, multi-burn-rate SLO alerting — watch a fast and a slow error-budget window side by side so you catch a real outage in minutes without paging on every blip.
Author · Maintainer · Terminal UI (CLI) · Go · v1.0.0
Windows
Fast + slow
A short window catches outages fast; a longer one filters noise from blips.
Built on
Bubble Tea
Styled with Lip Gloss, gauge from Bubbles — all three from Charm.
The problem
Why this exists
A single instantaneous error rate is a bad alerting signal on its own — it can't distinguish a brief blip from a real, sustained regression. Multi-window burn-rate alerting needs a place to live closer than a dashboard nobody has open, so it can be checked at a glance from a terminal.
Architecture
How it's built
burnrate is a single Go binary split into three independent packages: internal/slo holds the pure burn-rate arithmetic (no terminal dependency at all, so it's fully unit tested on its own), internal/data supplies rolling per-minute traffic samples from either a simulated demo generator or a static JSON snapshot file, and internal/tui wires both together into a Bubble Tea program styled with Lip Gloss.
slo.Budget / slo.Window
Given an SLO target and a window's error/total counts, computes the burn rate — how many multiples of a sustainable pace the current error rate represents — and whether it crosses that window's alert threshold.
slo.Tracker
Accumulates errors against a fixed-size rolling budget (e.g. a 30-day period) so the dashboard can show how much error budget is left, not just the instantaneous burn rate.
data.DemoSource
Generates a gently fluctuating, believable error rate with an occasional simulated incident spike, backed by a rolling per-minute ring buffer — so the fast-burn window always has something real to catch.
data.FileSource
Loads a fixed JSON snapshot of chronological per-minute request/error counts and answers the same window-lookback queries as the live demo source, so real exported metrics render identically to simulated ones.
tui.Model
The Bubble Tea model: ticks once a second in live mode, re-evaluates both burn-rate windows, updates the error-budget gauge, and renders the whole dashboard with Lip Gloss styling.
Request flow
What happens, in order
- 01Source (demo generator or JSON file) supplies rolling per-minute samples
- 02Model.Update requests the short-window and long-window sums for each configured Window
- 03slo.Budget.Evaluate computes the burn rate and compares it to the window's threshold
- 04slo.Tracker.Consume updates the running error-budget total
- 05Model.View renders window rows, badges, and the error-budget gauge via Lip Gloss
- 06A tea.Tick every second re-runs the loop for live (demo) sources
Runbook
Worked example: catching a real incident in demo mode
Symptom
Running `burnrate demo` for a few minutes, the fast-burn window occasionally flips from OK to CRITICAL for a handful of ticks — this is DemoSource's simulated incident, injected roughly every few hours of simulated time to prove the alerting logic actually reacts to something.
Diagnosis
- 01DemoSource rolls a low-probability chance each simulated minute to start a short incident window (a few minutes of elevated error rate) rather than a fixed schedule, so it feels like something that could actually happen rather than a scripted demo.
- 02Once the incident window starts, the per-minute error rate jumps by roughly 50–100x its baseline — well past the fast window's threshold of 14.4x for a 99.9% SLO.
- 03The slow-burn window barely moves during a short incident, because it averages over 6 hours — which is exactly the point: a brief spike alone shouldn't have escalated as a slow-burn issue.
Response
- 01The dashboard's fast-burn row flips to a red CRITICAL badge the tick after the sample lands, since Model.Update re-evaluates both windows every second in live mode.
- 02The error-budget gauge (`slo.Tracker`) ticks down proportionally to the errors consumed during the spike, so the 30-day budget reflects the incident even after the fast window recovers.
- 03Once the simulated incident ends, the next few minutes of samples dilute the 5-minute window back toward baseline and the badge returns to OK — visibly demonstrating why the short window needs to stay short.
Blast radius
Contained entirely to the demo's simulated traffic — nothing in this tool talks to real infrastructure. In a real deployment, the same two-window pattern with a Prometheus-backed source would bound the blast radius to whatever it takes a human to notice the CRITICAL badge and start the actual incident response.
Lessons learned
This is exactly why the fast and slow windows are evaluated independently rather than averaged together — averaging a 5-minute spike into a 6-hour window would have hidden it almost completely, which defeats the entire purpose of multi-window burn-rate alerting.
Design decisions
Why it's built this way
Burn-rate math lives in its own dependency-free package
internal/slo has zero imports from Bubble Tea or Lip Gloss. It's pure arithmetic over Go structs, which means it's trivially unit tested and could be reused by a completely different frontend (a web API, a Slack bot) without touching the terminal code at all.
A demo mode is a first-class feature, not an afterthought
SLO tooling usually requires a real metrics backend before anyone can even see what it does. burnrate's DemoSource simulates believable traffic (with an occasional incident) so the tool is immediately useful — and immediately understandable — with zero setup.
Two windows, not one
A single error-rate reading can't tell a brief blip from a genuine regression. Pairing a short, sensitive window with a longer, noise-resistant window is the well-established fix for that — a hard outage trips the fast window in minutes, while a slow leak still eventually trips the slow window instead of hiding inside noise.
Static snapshots and live demo data share one interface
Both `DemoSource` and `FileSource` implement the same small `Source` interface (`Tick`, `Window`, `Label`, `ServiceName`). The dashboard code has no idea — and doesn't need to know — whether it's looking at simulated or real data.
Roadmap
Where it's headed
Phase 1 — Coredone
- Multi-window burn-rate evaluation (`internal/slo`, unit tested)
- Rolling error-budget tracker with a live gauge
- Self-contained `demo` mode with simulated traffic
- `run --file` snapshot mode for real exported metrics
Phase 2 — Real backendsplanned
- A Prometheus-backed `data.Source` for live production metrics
- Configurable window/threshold pairs instead of the built-in defaults
- Multiple services in one dashboard view
Phase 3 — Distributionplanned
- Homebrew tap for one-command install
- Prebuilt release binaries for common platforms
Key capabilities
What it does today
- Multi-window burn-rate math (fast + slow window pairs) with tested thresholds, not just a single instantaneous error rate
- Self-contained `demo` mode with simulated traffic and an occasional incident spike — runs instantly, no infra required
- `run --file` mode replays a fixed JSON snapshot of real per-minute request/error counts
- Live 30-day error-budget gauge showing exactly how many errors are left before the budget is spent
- Core SLO arithmetic lives in a pure, unit-tested package (`internal/slo`), decoupled from the terminal UI