# Burn Hud

> Burn HUD

- Skill: `intense-visions/burn-hud` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add intense-visions/burn-hud`
- Raw SKILL.md: https://api.skillmd.com/api/skills/intense-visions/burn-hud/raw
- Safety review: pending (external: skillspector WARNING)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Intense-Visions (https://skillmd.com/u/intense-visions)
- Updated: 2026-08-19
- Page: https://skillmd.com/skills/intense-visions/burn-hud

---

# Burn HUD

> Install, calibrate, verify and diagnose a local usage-pace HUD — an always-visible statusline plus reminder hooks that show weekly burn, flag when a session's context has stopped paying for itself, and refuse to report a comfortable green they have not earned.

## When to Use

- A user keeps hitting their weekly usage limit without warning and wants pace visible before they run out
- A user wants to be reminded to `/clear` after finished work, or to slow down when burning too hot
- Installing, calibrating, or re-calibrating a usage HUD on a machine
- Diagnosing a HUD figure the user believes is wrong ("it says green but I'm not")
- Re-calibrating after a limit change (plan change, promo start or end)
- NOT for explaining a single session's token breakdown — that is `/usage`
- NOT for reducing usage; this measures and warns, it does not optimise prompts
- NOT on Windows: POSIX file locking is required (see Prerequisites)

## Prerequisites

- macOS or Linux. Windows is unsupported — the scanner requires `fcntl` locking and must refuse to run unsynchronised rather than risk a corrupt store.
- `python3` 3.9+ (needs `zoneinfo`), `jq`, `git`.
- An agent CLI writing session transcripts as JSONL under a known directory (for Claude Code: `~/.claude/projects/**/*.jsonl`).
- A reference implementation of the HUD itself. This skill is the operating discipline, not the scanner; see **Implementation**.

## Implementation

This skill governs _how_ to install, calibrate and trust a usage HUD. The scanner, statusline, hooks and CLI are a separate deliverable, because a ~1.4k-line tool does not belong inside a skill directory.

For Claude Code the reference implementation ships with the harness itself, as `@harness-engineering/burn`:

- `harness burn` — the interactive surface (report, `weeks`, `calibrate`, `reset-day`, `budget`, `scan`, `install`).
- `harness-burn-hud` — a standalone binary for the two hot paths (`line` for the statusline, `session-start`/`stop` for the hooks). It deliberately imports nothing from the CLI: loading that module graph costs ~0.85s against a ~0.11s repaint budget, and a laggy statusline is a regression nobody bisects.

For any other agent CLI, an equivalent implementation is expected at the path the user supplies. Either way the contract this skill assumes throughout is:

| Artifact             | Contract                                                                                                                                                       |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `state/summary.json` | Written atomically. Carries `status`, `week.reset_spec`, `wtd.units`, `budget.pct_used`, `projection.confidence`, `models_exhausted`, `calibration`, `scan.*`. |
| `state/usage.tsv`    | Deduped record store, one row per request id.                                                                                                                  |
| `state/files.tsv`    | Scan fingerprints, first line `#count\t<n>` — the record count, written in the same atomic write.                                                              |
| CLI                  | `report`, `weeks`, `calibrate <pct> [valid_until]`, `reset-day <day> [time] [tz]`, `budget`, `scan` (for Claude Code: `harness burn <subcommand>`).            |
| statusline           | Reads the cached summary only. Never scans.                                                                                                                    |

If the user has no implementation, that is the blocker to resolve first — do not hand-roll a partial scanner mid-session, because an under-counting scanner is precisely the failure this skill exists to prevent.

## Process

### Iron Law

**No burn percentage is trustworthy until it has been reconciled against the provider's own usage report.**

A local HUD reads local transcripts. The real limit is enforced server-side and is not readable on disk. Every percentage is therefore derived from a calibration against a `/usage` reading — and a calibration whose window, weekday, timezone, or validity date is wrong produces a _confident wrong number_, which is worse than no number.

This law is not theoretical. Both real failures of the reference implementation were false greens, and neither was caught by the tool:

1. A Monday-midnight-UTC week assumption against a real Wednesday-08:59-Chicago reset understated a 97% week by **~81×** and displayed a calm `EARLY`.
2. A write race silently dropped **85%** of the record store while the HUD reported `OK` at 3% of budget.

In both cases the denominator was non-zero and the arithmetic was correct. Zero-denominator checks caught neither. Only reconciliation against ground truth did.

#### Corollary: a forecast may only escalate in proportion to the evidence behind it

Incurred spend is a fact and may always raise the alarm. A projection is evidence whose weight grows with the week, and must earn severity gradually.

The reference implementation shipped this wrong too, in the opposite direction from the failures above. It derived status from `max(projected, used)`, so 2% of budget spent in a week's first three hours extrapolated to 118% and fired `CRITICAL`. The warning then read "5.8M used this week ... 108% of your weekly budget" — self-contradictory on its face, which teaches the reader to discount every future alarm. **An alarm that fires on noise is worse than no alarm**, because it spends the credibility the real one depends on.

Two mechanisms, and both are needed:

- **Shrink the forecast toward the trailing baseline** in proportion to how much of the week has not yet happened. Early on, the best available estimate of where the week lands is "a normal week". Report the raw extrapolation alongside the blended figure — quietly adjusting a number the user reads daily is its own kind of untrustworthiness, even when the adjustment is the statistically sound one.
- **Cap how far a low-confidence forecast may escalate** (e.g. low → no escalation, medium → at most the second tier, high → any tier). With no baseline there is nothing to shrink toward, so this cap carries the load alone.

Note the asymmetry is deliberate and runs one way only: withhold a _reassuring_ verdict on thin evidence, and withhold an _alarming_ verdict built on a thin _forecast_ — but never withhold one built on spend already incurred.

---

### Phase 1: INSTALL — Wire It Up Without Breaking Anything

1. **Check prerequisites.** `python3 -c 'import zoneinfo, fcntl'` and `command -v jq git`. If `fcntl` fails, stop: this platform is unsupported. Say so plainly rather than installing something that cannot lock.

2. **Place the implementation one level below the agent config root** — e.g. `~/.claude/hud`, never `~/.claude` itself. This is a safety boundary, not a preference: the config root holds session transcripts (often client work) and prompt history. Rooted one level down, no `git add -A` can reach them.

3. **Run the installer.** It must back up the settings file, **append** hook entries rather than replacing the arrays, install the CLI, and run a first scan.

4. **Confirm nothing was clobbered.** If the user already had a statusline, leave it in place and print how to switch. Never silently replace a statusline the user built.

**Gate G1/G2** — see Gates.

---

### Phase 2: ALIGN THE WINDOW — Before Any Calibration

1. **Ask the user to run `/usage`** and report: the weekly percentage, the reset day _and_ time _and_ timezone, whether any per-model bar is shown separately, and whether a promo or temporary limit is active.

2. **Set the window first.** `harness burn reset-day <mon..sun> <HH:MM> <tz>`. Weekday alone is not enough — a time-of-day error is a multi-hour window shift, and the two together caused the 81× understatement.

3. **Re-scan.** The window change recuts every historical bucket, so the baseline moves too.

**Gate G3** — the window must match exactly, not approximately.

---

### Phase 3: CALIBRATE — Anchor to Ground Truth

1. **Calibrate late in the week, not early.** `/usage` reports whole percents, so the error is `±0.5/pct`: ~17% at 3%, ~1.5% at 34%. Calibrating just after a reset produces a near-useless ceiling.

2. **Record the validity date if a promo is active.** `harness burn calibrate <pct> <YYYY-MM-DD>`. A promo inflates the ceiling; a calibration taken during one **under-warns** once it lapses. With a date recorded the HUD flags itself instead of quietly trusting a stale budget.

3. **Add per-model budgets** if `/usage` shows a separate family bar. A family limit can be fully spent while the pooled bar looks survivable — observed in practice at 100% of one model family's own limit while that family was only 29% of the pooled week.

4. **Reconcile** the HUD's `budget.pct_used` against what `/usage` reported.

**Gate G4/G5.** Never adjust the budget to force agreement — that hides a window error behind a fudged ceiling.

---

### Phase 4: VERIFY — Prove It Cannot Fail Green

1. **Run the implementation's test suite.** All tests must pass.

2. **Verify the abstention paths by hand** at least once, because these are the ones that matter:
   - Move `state/summary.json` away → the statusline must say _no cache_, never a green figure.
   - Truncate `state/usage.tsv` while leaving `state/files.tsv` intact → the next scan must detect the loss, rebuild from source, and report it.
   - Empty store → status must be `NO_DATA` ("blind, not clear"), never `0% — fine`.

3. **Confirm the reminders fire.** With an elevated status the post-turn hook must warn; at `OK` or `EARLY` it must stay silent, or it becomes wallpaper.

4. **Test both directions of the forecast asymmetry**, because muting noise and muting a real alarm are the same edit if done carelessly:
   - Small spend a few hours into the week, whose linear extrapolation exceeds the budget → must **not** escalate, and must not print an exhaustion date.
   - Spend already past the budget a few hours into the week → **must** escalate to the top tier regardless of forecast confidence.
     A change that satisfies only the first is a muted alarm, not a fixed one.

**Gate G6/G7.**

---

### Phase 5: DIAGNOSE — When The User Says It Is Wrong

Believe the user. In the reference implementation's history, the user caught every real failure before the tool did. Work the cheapest checks first:

1. **Is the window right?** Compare `week.reset_spec` to `/usage`. This was failure #1.
2. **Did the store lose rows?** Compare `scan.records_total` against recent history and check for a data-loss flag. A sudden drop alongside `files_rescanned: 1` is the signature of failure #2 — fingerprints outliving the records they vouch for.
3. **Is the calibration expired or promo-inflated?** Check `calibration.expired` and `valid_until`.
4. **Is a per-model limit spent** while the pooled bar looks fine? Check `models_exhausted`.
5. **Is usage coming from another machine?** A local scanner sees local transcripts only, and `/usage` excludes other devices from its own breakdown, so a user on two machines is undercounted by design.

**Gate G8** — end with the corrected figure reconciled, and the cause named.

## Harness Integration

- **Upstream:** none. This is a leaf skill operating on the user's agent installation, not on project code.
- **Downstream:** pairs with any session-hygiene practice — the `/clear`-when-merged nudge is the enforcement surface for "clear context between tasks".
- **State:** lives entirely on the user's machine (HUD config plus a derived cache that regenerates in seconds and is never committed). This skill writes no project state.
- **CI:** the implementation's own suite is the gate. The reference suite is stdlib-only, so it needs no package installation.

## Success Criteria

- [ ] The HUD reports a `pct_used` within ~2 points of `/usage`
- [ ] `week.reset_spec` matches `/usage`'s reset weekday, time, and timezone exactly
- [ ] The statusline renders fast enough to be unnoticeable and never scans transcripts itself
- [ ] The implementation's tests pass; abstention paths verified by hand at least once
- [ ] A missing or corrupt cache produces a stated _unknown_, never a green figure
- [ ] A validity date is recorded whenever a promo or temporary limit is in effect
- [ ] Per-model budgets configured for every separate family bar `/usage` shows
- [ ] Any pre-existing statusline and hooks survived installation
- [ ] Uninstall removes only this HUD's wiring

## Gates

Each gate blocks the next phase. A gate that cannot be evaluated counts as **failed**, never as passed — an unverifiable gate has the same shape as the failures this skill exists to prevent.

| #   | After phase | Condition to pass                                                                      | On failure                                                                                 |
| --- | ----------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| G1  | 1 INSTALL   | The CLI prints a report and the summary cache exists                                   | Stop. Do not calibrate against a broken scan — it bakes a wrong ceiling into config.       |
| G2  | 1 INSTALL   | Pre-existing statusline and hooks still present in the settings file                   | Restore from the installer's backup before continuing.                                     |
| G3  | 2 ALIGN     | The configured window matches `/usage`'s weekday **and** time **and** timezone exactly | Return to Phase 2. "Close enough" is how the 81× error happened.                           |
| G4  | 3 CALIBRATE | `budget.pct_used` within ~2 points of the `/usage` reading                             | Return to Phase 2 — the window is still wrong. Never tune the budget to force agreement.   |
| G5  | 3 CALIBRATE | A calibration validity date is set if any promo or temporary limit is active           | Set it. An unrecorded expiry under-warns silently from the day it lapses.                  |
| G6  | 4 VERIFY    | The implementation's test suite fully passes                                           | Fix the code, not the test.                                                                |
| G7  | 4 VERIFY    | Missing-cache, truncated-store, and empty-store paths each state their own ignorance   | Do not ship. A silent HUD reads as all-clear.                                              |
| G8  | 5 DIAGNOSE  | The corrected figure reconciles with `/usage` **and** the cause is named               | Keep diagnosing. "Fixed" without a named cause means the next occurrence starts from zero. |

## Escalation

Escalate to the user rather than guessing:

- **`/usage` and the HUD disagree by more than a few points after Phases 2 and 3.** Something structural is wrong — likely a second machine contributing usage, or a limit that changed. Report both numbers and the gap; do not pick one.
- **Records are unrecoverable** because their transcripts were pruned. Every figure is then a floor, not a total. Say so explicitly.
- **The platform lacks `fcntl`.** Stop and say the platform is unsupported. Do not install a HUD that cannot lock.
- **The user disputes a figure and all five Phase 5 causes come back clean.** Say so plainly and treat `/usage` as authoritative. An unexplained discrepancy is a finding worth reporting, not something to explain away.
- **A limit change is suspected.** Re-calibration needs a fresh `/usage` reading, which only the user can produce. Ask; do not extrapolate a new ceiling.

## Red Flags

| Signal                                                                  | Why it is a stop                                                                                                                                     |
| ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| "It says 3% so we're fine" with no calibration on record                | An uncalibrated percentage is meaningless. Check for a budget and calibration before repeating any number.                                           |
| Status flipped to a much lower figure with no behaviour change          | Suspect record loss or a window change, not a quiet week.                                                                                            |
| `files_rescanned: 1` alongside a suddenly small record total            | The exact signature of fingerprints outliving their records. Force a rebuild.                                                                        |
| Adjusting the budget so the HUD agrees with `/usage`                    | This hides a window error behind a fudged ceiling. Fix the window instead.                                                                           |
| Calibrating within hours of a reset                                     | Whole-percent rounding makes this near-useless. Wait for mid-week.                                                                                   |
| A green statusline the user disputes                                    | Diagnose before defending the number.                                                                                                                |
| An alarm firing in the first hours of a week on a small absolute spend  | The forecast rests on almost no week. Verify the projection is shrunk and confidence-capped before believing it.                                     |
| A warning quoting a projected percentage beside a small absolute figure | Self-contradictory on its face ("5.8M used ... 108% of budget"), which trains the reader to discount later alarms. Lead with what is actually spent. |
| Installing on a platform without POSIX locking                          | Unsynchronised scans corrupt the store, and a corrupt store reports green. Refuse.                                                                   |

## Rationalizations to Reject

| Rationalization                                                    | Reality                                                                                                                                                                                                                                       |
| ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "The numbers look plausible, so calibration can wait"              | Plausible is exactly how both failures presented. The 81× understatement looked like a quiet week; the 85% record loss looked like 3% of budget. Reconcile or report nothing.                                                                 |
| "The denominator is non-zero, so the reading is sound"             | Both real failures had non-zero denominators and correct arithmetic. Zero-denominator checks catch _no data_; they cannot catch _wrong window_ or _partial data_.                                                                             |
| "Weekday is enough — the exact reset time hardly matters"          | A time-of-day error shifts the window by hours; combined with the wrong weekday it produced an 81× error. Set weekday, time, and timezone.                                                                                                    |
| "Atomic writes are in place, so a record-count check is redundant" | Atomic writes prevent _new_ corruption; they do not detect _existing_ loss. The count header is what makes fingerprints and records fail together instead of the fingerprints silently vouching for a gutted store.                           |
| "Scanning after every turn keeps it fresh"                         | That frequency caused the write race. Usage cannot move meaningfully inside a minute; throttle.                                                                                                                                               |
| "Just set a budget from the trailing median"                       | A self-referential budget drifts with behaviour and never maps to the real ceiling. It is a fallback for _no calibration yet_, not a substitute.                                                                                              |
| "The promo ends eventually; no need to record a date"              | An unrecorded expiry is a budget that under-warns silently from that day on.                                                                                                                                                                  |
| "Tests are overkill for a personal statusline"                     | The tool's entire job is not lying about usage, and it lied twice.                                                                                                                                                                            |
| "The pooled percentage is fine, so we're fine"                     | Per-model limits are separate and can be fully spent while the pooled bar looks healthy.                                                                                                                                                      |
| "The user is probably misreading it"                               | They caught both real failures before the tool did. Diagnose first.                                                                                                                                                                           |
| "The projection says 120%, so warn now"                            | A projection is not spend. Early in the week it is an extrapolation from hours, and escalating on it burns the credibility the real alarm depends on. Cap what a low-confidence forecast may escalate to; let incurred spend escalate freely. |

## Examples

### Example: "The HUD says green but I'm definitely not"

Phase 5, cheapest checks first:

```bash
python3 -c "import json;s=json.load(open('$HOME/.claude/hud/state/summary.json'));\
print(s['status'], s['scan'], s['week']['reset_spec'])"
```

Output showed `records_total: 4321` against roughly 29,000 the day before, plus `files_rescanned: 1`.

That combination is diagnostic: the record store lost rows while the fingerprint file still asserted every transcript had been scanned, so each later scan re-read exactly one file and the loss was permanent.

```bash
rm ~/.claude/hud/state/files.tsv     # distrust the fingerprints
harness burn                         # rebuild from source
```

Recovered 29,475 records; status moved `OK (3%)` → `CRITICAL (98%)`. Cause named: record loss. Then fixed structurally — atomic writes, an `flock`, and a count header so fingerprints and records can never again disagree.

### Example: Calibrating during a promo

`/usage` showed `97% used`, reset `Wed 08:59 America/Chicago`, a separate model-family bar at `100%`, and a `+50% weekly limits` promo with an end date.

```bash
harness burn reset-day wed 08:59 America/Chicago   # window FIRST
harness burn calibrate 97 2026-08-19               # expiry recorded
```

Then a per-family budget for the separate bar. Reconciled: HUD `97.2%` against `/usage` `97%` — inside G4.

The validity date matters most here. Without it the budget stays ~50% too generous the moment the promo lapses, and the HUD under-warns every week thereafter while looking perfectly healthy.

## Skill Test Scenarios

Regression scenarios for the discipline sections. Mentally execute each after any edit to this skill; if the prose does not clearly drive the expected behaviour, revise the skill rather than the scenario.

### Scenario 1: Red Flag — "A green statusline the user disputes"

**Input:** The user says the HUD shows green but they are certain it is not. The summary reports `status: OK`, `pct_used: 3`, `records_total: 4321`, `files_rescanned: 1`.

**Expected:** The agent does not defend the number or ask the user to re-check. It enters Phase 5, recognises `files_rescanned: 1` beside a small record total as the documented signature of fingerprints outliving their records, forces a rebuild, re-scans, and reports both the corrected figure and the named cause. G8 is satisfied only once the cause is named.

### Scenario 2: Rationalization — "The numbers look plausible, so calibration can wait"

**Input:** Fresh install showing a baseline-relative ratio and no budget set. The user asks whether they are okay on usage this week.

**Expected:** The agent refuses to answer from the HUD alone, states that without a calibration there is no percentage-of-limit to report, and asks for a `/usage` reading. It then runs Phase 2 before Phase 3 — not the reverse — and does not convert a baseline ratio into a reassurance about the real limit.

### Scenario 3: Gate — G4 (`pct_used` within ~2 points of `/usage`)

**Input:** `/usage` reports 97%; after calibration the HUD computes 62%. Lowering the budget would make them agree.

**Expected:** The agent halts at G4 and does **not** adjust the budget. A 35-point gap after calibration means the window is still wrong, so it returns to Phase 2. Forcing agreement at the display layer leaves the window broken and the next week wrong with no visible symptom.

### Scenario 4: Escalation — unrecoverable record loss

**Input:** A scan reports data loss with rows unrecoverable because old transcripts were pruned.

**Expected:** The agent gives the figure but labels it a floor, not a total, states how many rows are unrecoverable and why, and does not present the rebuilt number as complete.

