0.9.20 - 2026-08-10
Added
- Desktop panel fetches drop from seconds to milliseconds. The app, the web dashboard and the macOS menubar now hold one resident
codeburn serveprocess instead of spawning a fresh CLI per panel: the parsed session cache stays warm in memory, panel bursts share one parse, filesystem watches over every provider's discovery roots let a no-change fetch skip the scan entirely, and the web dashboard prefetches every period tab at startup. Cold start, mixed CLI versions and any serve failure all fall back to the exact spawn behavior shipped today, and one-shot CLI output is byte-identical. (#956, #957, #959, #960) - Spend punchcard in the desktop app. The hour-of-day × weekday spend matrix from the web dashboard, on the Spend page, fed by a dedicated timeline fetch so every other panel keeps its lean payload. (#962)
- Top pull requests in the menubar. The popover shows the period's top three PRs by attributed spend under Models; hidden when the payload carries none. The Workflow strip is retired from the popover — those metrics live in the desktop app, web dashboard and TUI, where there is room to read them. (#962, #963)
- Mouse-wheel scrolling in the terminal dashboard. The viewport enables SGR mouse reporting while mounted (three lines per tick, clicks stay inert, tracking restored on quit); click-drag text selection needs Shift held while the dashboard is open. (#951)
- Credit-metered ChatGPT workspaces (Business / Edu / Enterprise) now show their limit. These plans report no rate-limit windows, so the admin-set monthly allowance from
spend_control.individual_limitis shown as a "Monthly usage limit" bar in the desktop app and the menubar. (#833) - Combined-device scope in the desktop Dashboard, mirroring the menu bar. A Local / Combined toggle aggregates paired-device usage in the Overview hero and the menu bar badge, degrading gracefully to the local figure when a peer is unreachable; the badge then shows a dimmed
reachable/totalmarker so a momentary drop to the local number reads as "a peer is unreachable" rather than a glitch. (#866, #867, thanks @marcreynolds)
Added (CLI)
- Cline CLI provider. The Cline command-line agent (npm
cline, 3.x) stores sessions as~/.cline/data/sessions/<id>/<id>.json+<id>.messages.json, a layout the existing Cline provider never scanned — it requirestasks/<id>/ui_messages.json— so every CLI session was silently reported as $0.00, with no warning even under--verbose. Added as its owncline-cliprovider so the shared Cline-family parser (Roo Code, KiloCode, IBM Bob) is untouched; it mirrors the CLI's own root resolution (CLINE_SESSION_DATA_DIR→CLINE_DATA_DIR→CLINE_DIR→~/.cline) and reports its probed root throughcodeburn doctor. Per-message cost is metered by the CLI, socline-clijoins the reported-cost pass-through allowlist rather than being re-priced from tokens. (#874) - Codex throughput tracking: per-model Tok/s in the dashboard and report, active time excludes tool wait. (#805, thanks @ihearttokyo)
codeburn sync push --attribution(opt-in): sends git attribution spans — the session→commit correlation fromcodeburn yield(codeburn.session.attributionandcodeburn.commitspan types with normalized repo remote, commit SHAs, merged/reverted state, and PR links). Nothing new is sent without the flag; local-only repos and Windows filesystem paths are never emitted as repo identities, and sessions whose project path no longer resolves never inherit the push-time working directory's repo. See docs/sync/README.md "Git attribution".
Fixed (CLI)
-
A pull request no longer swallows a whole repo's spend. The working-directory correlation rule attributed every session sharing a checkout with a PR-linked session, with no time bound — a repo whose only captured PR link was pasted once attributed a month of unrelated work (129 of 131 sessions on real data) to that PR. Checkout evidence now only attributes sessions overlapping the linked sessions' own activity window. (#961)
-
Shell reads finally count as reads.
rg,grep,cat,git logand friends were invisible to the read-edit-ratio detector (90%+ of real reads uncounted on bash-first workflows) while every Bash call counted as a verification step, soedit → grep → editscored as rework. One shared read-shaped-command classifier fixes both detectors; unknown or mutating commands keep the old behavior. (#941, thanks @laulpogan) -
Phantom corrections from injected skill prose. The user-correction detector matched "the wrong answer" inside a templated skill prompt, counting the same non-correction four times on real data; "answer" left the wrong- pattern list, concrete artifacts (wrong file, wrong approach) still count. (#952)
-
Pricing coverage is floored, never rounded. 99.6% coverage with unpriced calls outstanding rendered as the "100%" reserved for genuinely complete pricing, contradicting the unpriced-model warning on the same screen. Applies to the TUI panel and the web dashboard. (#786, #783)
-
Model efficiency one-shot rate showed 10000% in the web dashboard. The payload field is already a percent; the dash multiplied by 100 again. (#958)
-
Copilot CLI sessions report their input and cache tokens. The Copilot CLI writes the same
producer: 'copilot-agent'in itssession.startevents that VS Code transcripts carry, so content-based detection classified every CLI session as a transcript and skipped itssession.shutdownrollup — the only place the CLI records input, cache-read and cache-write tokens — leaving cache hit rate at 0.0% and dramatically underreporting cost. Whether a file is a transcript is now decided by where discovery found it, never by its contents. Resumed sessions, whose legs each append a cumulative rollup, are billed as per-leg deltas so a growing session never double-counts or goes stale; the GitHub Copilot desktop app writes the same session store, so its usage is covered by the same fix. The copilot session cache takes a parse-version bump and the daily cache bumps from v16 to v17 for the one-time re-parse that heals already-recorded days whose logs still exist. (#944) -
Copilot CLI subagent runs are attributed to their agent. Newer CLIs announce delegation with
subagent.started/subagent.completedrather thansubagent.selected, so delegated turns lost their agent label; the label now also clears when the subagent completes instead of bleeding onto the parent's later turns. Rides the #944 re-parse, so already-cached sessions gain the attribution. (#944) -
--project/--excludenow apply to the headline totals, not just the detail panels. The durable headline unions the carry-forward daily cache with today's live parse, and the cached days were sliced to the requested provider but never to the requested project — so the Overview panel counted excluded projects while By Project / By Activity / By Model (built from the name-filtered parse) left them out, and the two could not be reconciled. Cost, calls, sessions and savings are now sliced out of the per-project day stats the cache has carried since v15. Tokens, models and categories have no per-project split in the cache, so under a project filter they come from the (project-filtered) live parse instead; cached days — or provider slices — carried from before v15 have no project split at all, so they cannot be attributed to a filtered project, and the terminal overview now states how much was set aside rather than folding it into the total. (#864) -
Codex parser corrections: fork-replay no longer double-counts
patch_apply_endandmcp_tool_call_end;execis normalized to Bash;custom_tool_callevents are handled; token_count lines larger than 32 KiB now parse exact token counts instead of estimating. Codex session cache bumps from v7 to v8 for a one-time re-parse. Only tool attribution changes for ordinary sessions, leaving their cost identical; sessions that logged an oversized token_count line are repriced from exact counts instead of an estimate. (#805) -
Midnight-straddling turns keep both halves. A turn whose calls span local midnight was attributed whole to its start day, so
codeburn todayunder-reported until the turn ended and multi-day totals mis-split it. Calls are now range-filtered inside the turn so each day gets the calls that belong to it, and By Activity and the daily turn counts reconcile with the headline. (#853, thanks @KENSHI601) -
--provider <x>no longer leaks Claude spend into the detail panels. A provider-filtered run still ran the Claude scan, whose orphan pass re-injected every cached Claude session, so By Project / By Model / By Activity showed Claude usage under, e.g.,--provider cursorwhile the headline was correct. (#872, thanks @ozymandiashh) -
A degraded session parse no longer freezes daily history. A read-only parse that served a stale or missing session file was treated as complete and finalized days it never covered, freezing warm-cache ingestion; a corrupt refresh lock is now recovered rather than ending ingestion, and a legitimately idle tail is no longer re-derived on every launch. (#856, thanks @avs-io)
-
Pi / Oh My Pi transcripts with a leading title record are discovered. OMP writes a
type: "title"line before the session header; discovery now scans a bounded number of leading lines for the first session record instead of requiring it on the first physical line. (#846, #859, thanks @jbspeakr, @avs-io) -
Nine providers served silently stale numbers after you pointed their env override at a different profile or root. Kiro, Grok, Kimi, Mux, Mistral Vibe, Zerostack, Codebuff, Goose and Crush each honor an env var that relocates where discovery looks, but the var was never declared in the provider env fingerprint, so the cache section survived the change and kept reporting sessions parsed from the old root — with no diagnostic anywhere. The fix declares those vars, the adjacent OS-set path variables that resolve a discovery root for Claude, IBM Bob, Open Design and Kilo Code on Windows and Linux, Cursor's parse-budget override, and the Vercel AI Gateway credential — which must invalidate the fingerprint because a read-only refresh serves the cached report and would otherwise keep reporting the previous account's usage after a swap. Your next run re-parses the fourteen file-backed providers whose declarations changed — the nine above plus Claude, Cursor, Open Design, IBM Bob and Kilo Code — once, and only once; the Vercel AI Gateway declaration is a read-only-path correction, not a migration (its report is re-fetched on every writable run anyway); Copilot is deliberately NOT included, because declaring its overrides would force a re-parse that can drop OTel history only the cache still holds;
codeburn doctornames deliberate overrides including the XDG_* vars, never the Windows ambient APPDATA / LOCALAPPDATA, and redacts credential values. (#920)
Fixed (Desktop & Menubar)
- Menubar icon on macOS 26.5.x: best-available fix for the never-rendering status item. The app now activates with the window server before creating its status item — the half of the original #147 fix that the ghost-item fix removed — with the activation policy pinned so neither historical bug can return. Falsifiable on this release by affected 25F80 machines. (#868, #955, analysis by @ozymandiashh)
- Punchcard tooltips no longer crop at the container edges (top rows flip the tooltip below the cursor). (#963)