The Project Structure tree was duplicating information that
docs/architecture.md already covers in better detail (and updates
faster). Removing it from the README keeps the marketing-facing
README scoped to "what is this and how do I install it" and
points contributors at the proper map.
In its place, a short Sponsor section pointing at
https://github.com/sponsors/iamtoruk so users who find the tool
useful know where to support development.
Adds an OS-delimited list env var so a user with more than one
Claude account or profile can scan all of them in a single run.
Sessions across every configured dir merge into one ProjectSummary
per project, matching the option-1 design agreed on the issue
thread (no per-account splitting in the data model or the UI).
Format: `CLAUDE_CONFIG_DIRS=~/.claude-work:~/.claude-personal`
on POSIX, `;`-separated on Windows. Precedence is
CLAUDE_CONFIG_DIRS > CLAUDE_CONFIG_DIR > ~/.claude. Empty entries
in the list are skipped, duplicates are deduped on resolved path,
and a missing or unreadable dir does not abort the scan of the
others. If the user explicitly set CLAUDE_CONFIG_DIRS but every
listed entry is unreadable, a one-line stderr hint identifies the
attempted paths and the platform's expected delimiter, so a
Windows user typing the POSIX `:` does not get a silent zero-row
result. `~` is now also expanded in CLAUDE_CONFIG_DIR for
consistency.
Implementation is intentionally narrow: only `claude.ts` changes,
plus a small parser-cache key update so a stale cache from one
config does not bleed into a run with a different config (matters
for the macOS menubar and GNOME extension which run as long-lived
processes). The merge happens for free in
`src/parser.ts:scanProjectDirs`, which keys ProjectSummary entries
by canonical cwd (or the sanitized slug as a fallback). Two
SessionSource entries with the same `project` field land under the
same key and combine their sessions, regardless of which dir they
came from. No new fields on SessionSource / SessionSummary /
ProjectSummary, and no UI changes.
Tests: 12 fixture-based cases covering the unset path (default
~/.claude), single-dir override via CLAUDE_CONFIG_DIR, multi-dir
override via CLAUDE_CONFIG_DIRS, ~ expansion, dedup of repeated
entries, leading/trailing/doubled delimiters, missing dir
tolerated, file-not-directory entry tolerated, empty
CLAUDE_CONFIG_DIRS falls back to single-dir env, and two
parser-level integration tests asserting (a) two sessions from
two dirs sharing one cwd produce one ProjectSummary with combined
totals and no `account`/`accountPath` fields anywhere, and (b)
two sessions sharing a slug but with different canonical cwds
still merge by slug at the project-rollup layer (option 1
behavior pinned so a future refactor cannot quietly swap to
cwd-aware merging without an explicit opt-in).
Supersedes the alternative implementation in #227, which builds
per-account attribution (option 2) instead.
Closes#278.
Adds Charmbracelet Crush as a lazy-loaded provider:
- src/providers/crush.ts: walks ~/.local/share/crush/projects.json
(XDG_DATA_HOME and CRUSH_GLOBAL_DATA aware), opens each project's
crush.db read-only, queries root sessions where parent_session_id
IS NULL. Emits one ParsedProviderCall per session with real
prompt_tokens, completion_tokens, cost (dollars), and the
dominant model resolved from messages.model.
- src/providers/index.ts: register crush alongside cursor, goose,
opencode, antigravity, cursor-agent in the lazy import path.
- tests/providers/crush.test.ts: 10 fixture-based tests covering
discovery, parsing, missing-registry, malformed JSON, missing db,
child session exclusion, dominant model selection, dedup, and
array-shaped legacy registry.
Schema source: charmbracelet/crush@v0.66.1
internal/db/migrations/20250424200609_initial.sql, verified by
spawning a research agent against upstream. The schema *comments*
in that migration claim millisecond timestamps but every actual
INSERT/UPDATE uses strftime('%s', 'now') which returns Unix
seconds; the parser treats values as seconds. Tokscale's
parser (junhoyeo/tokscale#346) gets this wrong and is off by
1000x, plus its parser misses the prompt_tokens/completion_tokens
columns that exist in Crush's schema. Our integration uses both,
so Crush sessions get real per-model attribution.
Menubar:
- mac/Sources/CodeBurnMenubar/AppStore.swift: add .crush case to
ProviderFilter and its cliArg switch.
- mac/Sources/CodeBurnMenubar/Views/AgentTabStrip.swift: add
Crush color to the per-tab color extension. The visibleFilters
computed property already filters by detected providers, so the
Crush tab appears automatically when a user has Crush data.
README:
- Replace the provider table with an icon-led layout. Icons live
under assets/providers/<name>.<ext>. 14 icons sourced from
junhoyeo/tokscale (MIT) under nominative fair use, 4 sourced
separately: codex (OpenAI org avatar), cursor-agent (reuses the
Cursor icon), kiro (kiro.dev favicon, ico->png via sips), omp
(can1357/oh-my-pi icon.svg, MIT). Attribution line added.
- Add Crush row.
Docs:
- docs/providers/crush.md: full per-provider doc with verified
schema excerpt, the seconds-vs-milliseconds quirk, and a
"when fixing a bug here" checklist.
- docs/architecture.md: provider count 17 -> 18, test count
41 -> 42, and crush in the lazy list.
- docs/providers/README.md: add Crush row to the lazy index.
- CONTRIBUTING.md: bump test count to 568 (was 558).
All 568 tests pass locally; swift build clean.
The provider table now points each row at its docs/providers/<name>.md
file (added in #284) instead of repeating a one-line path that the
per-provider doc covers in full. The Data Location column is dropped;
the new Doc column links to the markdown that owns the path, storage
format, dedup key, and known quirks.
The trailing sentence is updated to reference the per-provider docs as
the source of truth for data locations.
A single dense table of every (provider, model) you have used in the
selected period, sorted by cost. Inspired by tokscale's per-model
output and ccusage's responsive cli-table3 layout, ported to plain
Node with no new runtime dependency.
Default view: one row per (provider, model) with a Top Task cell
showing the dominant task category and its cost share, e.g.
`Coding (42%)`.
`--by-task` explodes each model into one row per task type, with
provider/model cells blanked on subsequent rows of the same group
and a horizontal divider between groups so the sections read as
distinct units.
Output formats: table (Unicode box-drawn, default), markdown
(GitHub-flavored, copy-paste friendly), json, csv.
Filters: --period (today/week/30days/month/all, default 30days),
--from/--to, --provider, --task, --top, --min-cost, --no-totals.
The table renderer auto-sizes every column to its content (no fixed
widths leaving trailing whitespace) and drops cache columns as a
pair when the terminal is narrow, then input/output, then top-task,
in that order. Provider, model, total, and cost stay regardless.
Visible-width math uses strip-ansi (already a dependency) so styled
cells pad correctly. Cyan headers, yellow totals, dim provider name.
The aggregator walks every parsed turn and attributes each
assistant call to its (provider, model, task) bucket, computing
real input / output / cache_write / cache_read tokens and cost.
Output tokens include reasoning. Cached input tokens are folded
into cache_read so the column matches what users intuitively expect.
19 fixture-based tests cover aggregation correctness, byTask
grouping, taskFilter, topN/minCost filters, reasoning-as-output,
all four renderers (table/markdown/json/csv), narrow-terminal
column dropping, CSV/markdown escaping, totals row toggle, and
visible-width math under styled cells.
Adds a low-worth detector to codeburn optimize that flags expensive sessions with weak delivery signals (no edits, repeated retries, or no one-shot edits) when no git/gh delivery command is observed. Priority order is low-worth → context-bloat → outliers; each later detector excludes sessions named by an earlier one so the same session is never listed in three findings. Detection: floor, for no-edit, 3+ retries, regex matches git commit/push and gh pr create/merge but excludes commit-tree/commit-graph and dry-run. Three impact tiers consistent with #246. Token-savings uses full session tokens for no-edit sessions and the retry fraction for edit-with-retry sessions. Supersedes #241 with review fixes. Original implementation by @ozymandiashh.
Adds a context-bloat finding to codeburn optimize that flags sessions where effective input/cache tokens (cache-discounted via existing pricing constants) are large and disproportionate to output. Suggests starting fresh with a tightened context. Sessions flagged here are excluded from the cost-outlier finding to avoid double-listing. Growth-from-previous-session callouts are suppressed when the predecessor is more than 7 days back. Three impact tiers (low/medium/high). Supersedes #242 with review fixes from real-data probe. Original implementation by @ozymandiashh.
`getDateRange` was duplicated across `src/cli.ts` and `src/dashboard.tsx`
with conflicting semantics for `'all'`. The CLI intentionally bounded
`'all'` to the last 6 months (justified inline: keeps Codex/Cursor parses
responsive on sparse multi-year history). The dashboard returned
`new Date(0)` instead, so the same `--period all` flag silently meant
two different windows depending on which entry point you hit.
`Period`, `PERIODS`, `PERIOD_LABELS`, and `toPeriod` were duplicated as
well, and `cli-date.ts` already existed for date helpers
(`parseDateRangeFlags`) so the consolidation lives there.
Both call sites now go through a single `getDateRange(period: string)`
in `cli-date.ts` that returns `{ range, label }`. The dashboard wraps it
as `getPeriodRange(period: Period)` to keep the strict `Period` type at
the React boundary while letting the CLI continue to accept extras like
`'yesterday'`.
`PERIOD_LABELS.all` becomes `'6 Months'` (short, for the dashboard tab
strip; the previous `'All Time'` was misleading and the long-form
`'Last 6 months'` from `getDateRange().label` already drives CLI output).
Changes:
- src/cli-date.ts: add `Period`, `PERIODS`, `PERIOD_LABELS`, `toPeriod`,
`getDateRange`. Pull the existing 6-month rationale into a named
`ALL_TIME_MONTHS` constant.
- src/cli.ts: drop the local copies and import from cli-date.
- src/dashboard.tsx: drop the local copies, route through
`getPeriodRange`, alias the shared `getDateRange` import to
`getDateRangeShared` to avoid shadowing the wrapper.
- tests/cli-date.test.ts: 13 cases covering `'all'` regression guard
(must never silently fall back to `Date(0)`), CLI/dashboard agreement,
end-of-month clamping tolerance, `'yesterday'` support, and
unknown-input fallback.
- README.md, CHANGELOG.md: surface the bound and point heavy users at
`--from`/`--to` for unbounded windows.
The CLI flag `--period all` continues to be accepted; only the dashboard
window changes to match what the CLI was already doing. No public API
or schema change.
Refs #93
Replace providers hero image with honeycomb design. Add compare screenshot
to 2x2 grid. Consolidate all documentation into single README with provider
table showing data locations, full feature reference, reading the dashboard
guide, and credits section. Add bunx as alternative install option.
UserDefaults key CodeBurnMenubarCompact toggles a tighter menubar
display: no decimals, no leading space, variable width that hugs
the rendered text instead of the fixed 130pt slot.
Closes#129
Second merge of main since the PR was opened. Main moved 30+ commits
(0.8.5 bump, plan tracking feature, MiniMax pricing, menubar
prefetchAll walk-back, aicrowd cache rewrite revert) so the branch
needed another reconciliation before merging to main.
Two new conflicts resolved. Took main's text in both cases per the
policy of favoring main when the feature work is neutral:
README.md Kept main's Node 20+ / better-sqlite3
Requirements wording and main's shorter src/
tree listing. Added OMP to the Requirements
line.
src/providers/pi.ts Main dropped the discovery-cache snapshot and
the rich source-metadata fields as part of the
aicrowd revert. Took main's simpler structure
and only kept the providerName parameter so
OMP sources still report the correct provider
in the session source and dedup key.
Earlier fixups carried forward from the prior merge commit:
- Object.hasOwn guards in resolveAlias against prototype-pollution
via a model literally named '__proto__'.
- source.provider in the dedup key prefix so OMP rows no longer
stamp 'pi:'.
- Combined pi.js imports in providers/index.ts.
- Trailing newline on pi.ts.
- Unknown-model fallback in cursor-agent.ts from yesterday's PR #117
fixup (preserved via main).
353 tests pass (count dropped from 378 because main deleted the
parse-progress / parser-cache / provider-colors / source-cache test
files alongside the cache-rewrite revert).
Feature work by @cgrossde.
Discovers transcripts at ~/.cursor/projects/*/agent-transcripts/*.txt
and joins against ~/.cursor/ai-tracking/ai-code-tracking.db for model
attribution. Token counts are estimated from transcript character
length since the attribution DB does not carry them; the model label
surfaces the estimation with an (est.) suffix on every row.
Deduplication keys prefix cursor-agent: to stay disjoint from the
existing cursor: prefix so the two providers do not cross-dedupe
on shared conversationId namespaces.
Tests cover: empty ~/.cursor/projects/, single transcript, multiple
projects, missing ai-code-tracking.db, unrecognized transcript format
skip, non-UUID filename fallback, and sqlite metadata join.
Closes#55
Adds `codeburn plan set <id>` to configure a subscription plan (Claude Pro,
Claude Max, Cursor Pro, or custom). When set, the Overview panel renders
an API-equivalent progress bar against subscription price with a
projected month-end cost.
Closes the loudest demand signal on the repo: issue #11 ("Subscription
vs API Use") from two independent voices, plus the routing-decision use
case raised in #12.
- src/config.ts: extends CodeburnConfig with Plan, adds readPlan/savePlan/clearPlan
- src/plans.ts: presets (claude-pro $20, claude-max $200, cursor-pro $20)
- src/plan-usage.ts: getPlanUsage, resetDay-aware period math (1-28),
median-of-7-day-trailing projection
- src/cli.ts: `codeburn plan [show|set|reset]` subcommand, plan wired
into JSON outputs for report/today/month/status (only when active)
- src/dashboard.tsx: Plan row in Overview, color-coded (green under 80%,
orange near, red over), with days-until-reset
- README.md: Plans section with honest framing (API-equivalent vs
subscription price, not token allowance)
- tests/plan-usage.test.ts, tests/plans.test.ts, tests/cli-plan.test.ts:
period math, presets, CLI round-trip
Resets respect resetDay across month boundaries. Uses median daily spend
(not mean) so one huge day doesn't distort the month-end projection.
Fixes#11
Brings the PR branch up to the current main so the OMP provider and the
model-alias command can land cleanly. Resolves six merge conflicts and
applies a handful of small fixups alongside the resolution so the
feature matches the conventions set by the cursor-agent merge earlier
today.
Conflict resolutions:
README.md Combine cursor-agent and OMP rows in provider
list, Requirements, and data-location table;
take main's Node 22+ and node:sqlite text.
src/cli.ts Keep both new commands: model-alias and plan.
src/config.ts Add modelAliases alongside plan on the config
type.
src/providers/index.ts Keep the cursor-agent lazy-loader from main
and add omp to coreProviders. Fold the two
pi-module imports into one statement.
src/providers/pi.ts Keep the discovery-cache snapshot path from
main and the providerName parameterization
from the PR. Propagate providerName through
saveDiscoveryCache, loadDiscoveryCache, the
parserVersion tag, and the dedup key prefix
so OMP sources no longer stamp 'pi:' inside
their cache entries or dedup keys.
tests/models.test.ts Keep main's pricing-and-short-name tests and
add the PR's alias tests alongside, sharing a
single loadPricing setup and an afterEach
alias reset.
Fixups in the same commit:
src/models.ts Replace ?? chain in resolveAlias with
Object.hasOwn checks. The previous form
returned Object.prototype for a model named
'__proto__' and broke downstream
canonical.startsWith calls. Caught by the
existing prototype-pollution test suite.
src/providers/pi.ts Use source.provider in the dedup key prefix
and add a trailing newline to the file.
tests/providers/omp.test.ts Expect 'omp:' in the dedup key for OMP
sources, matching the fix above.
Feature work by @cgrossde.
Discovers transcripts at ~/.cursor/projects/*/agent-transcripts/*.txt
and joins against ~/.cursor/ai-tracking/ai-code-tracking.db for model
attribution. Token counts are estimated from transcript character
length since the attribution DB does not carry them; the model label
surfaces the estimation with an (est.) suffix on every row.
Deduplication keys prefix cursor-agent: to stay disjoint from the
existing cursor: prefix so the two providers do not cross-dedupe
on shared conversationId namespaces.
Tests cover: empty ~/.cursor/projects/, single transcript, multiple
projects, missing ai-code-tracking.db, unrecognized transcript format
skip, non-UUID filename fallback, and sqlite metadata join.
Closes#55
Adds `codeburn plan set <id>` to configure a subscription plan (Claude Pro,
Claude Max, Cursor Pro, or custom). When set, the Overview panel renders
an API-equivalent progress bar against subscription price with a
projected month-end cost.
Closes the loudest demand signal on the repo: issue #11 ("Subscription
vs API Use") from two independent voices, plus the routing-decision use
case raised in #12.
- src/config.ts: extends CodeburnConfig with Plan, adds readPlan/savePlan/clearPlan
- src/plans.ts: presets (claude-pro $20, claude-max $200, cursor-pro $20)
- src/plan-usage.ts: getPlanUsage, resetDay-aware period math (1-28),
median-of-7-day-trailing projection
- src/cli.ts: `codeburn plan [show|set|reset]` subcommand, plan wired
into JSON outputs for report/today/month/status (only when active)
- src/dashboard.tsx: Plan row in Overview, color-coded (green under 80%,
orange near, red over), with days-until-reset
- README.md: Plans section with honest framing (API-equivalent vs
subscription price, not token allowance)
- tests/plan-usage.test.ts, tests/plans.test.ts, tests/cli-plan.test.ts:
period math, presets, CLI round-trip
Resets respect resetDay across month boundaries. Uses median daily spend
(not mean) so one huge day doesn't distort the month-end projection.
Fixes#11
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
README gains a --from/--to example in the Usage block, a dedicated
'Date range filtering' subsection, and a note that JSON projects[]
now includes avgCostPerSession.
CHANGELOG opens an Unreleased section crediting @lfl1337 for PRs #78
and #80. Flags the projects.csv column-order shift (Avg/Session now
between Cost and Share) so consumers parsing by position read by
header instead.
Co-authored-by: AgentSeal <hello@agentseal.org>
Add package.json repository/bugs/homepage fields. Swap hardcoded
AgentSeal/codeburn URLs to getagentseal/codeburn across README,
mac README, macOS menubar star banner, and the menubar installer's
release-API endpoint. 301 redirects keep old URLs working, but
canonical links now point at the current org.
Co-authored-by: AgentSeal <hello@agentseal.org>
The prior rename commit moved the PNG but forgot to stage the matching
README edit, leaving the live image tag pointing at a path that no
longer existed. This fixes it.
Appends ?v=0.7.2 to the image URL so GitHub's Camo proxy re-fetches
the new 0.7.2 screenshot instead of serving its stale copy of the
SwiftBar-era one.
Sits between 'Reading the dashboard' (what the numbers mean) and
'How it reads data' (where the data comes from) so the feature lands
as the natural next step: here is how to act on the patterns you saw.
Adds two new repeatable flags to all commands (report, today, month, status, export):
- --project <name>: include only projects matching name (substring, case-insensitive)
- --exclude <name>: exclude projects matching name (substring, case-insensitive)
Both flags can be specified multiple times to match multiple projects.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add OMP provider reading from ~/.omp/agent/sessions (same JSONL
format as Pi, shared parser)
- Parameterize discoverSessionsInDir with provider name so sessions
carry correct provider field
- Add BUILTIN_ALIASES for proxy model name variants (anthropic--claude-*
double-dash format) that don't match LiteLLM keys
- Add model-alias CLI command for user-defined name mappings
- Wire setModelAliases into preAction after config load
- Add modelAliases field to CodeburnConfig
- Update README: OMP in provider table, model-alias section
Outputs full dashboard data as structured JSON to stdout, including:
overview, daily breakdown, projects, models with token counts,
activities with one-shot rates, core tools, MCP servers, and
shell commands.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Release notes cover the two merged PRs:
- #44: GitHub Copilot provider parsing ~/.copilot/session-state/ with
model tracking via session.model_change events. Adds fallback pricing
for six gpt/o3/o4 models. Copilot logs only output tokens, so cost
rows sit below actual API cost; documented in README and CHANGELOG.
- #51: All Time period (key 5, -p all), avg/s column in By Project,
and a new Top Sessions panel showing the five most expensive sessions
across all projects.
README: provider list updated (Copilot added, output-tokens-only caveat
alongside Cursor's Auto-mode estimation note), usage examples include
`-p all` and key `5`, provider filter list includes `copilot`.
CHANGELOG: 0.6.0 entry lists both features with contributor credits,
plus two fixes (longest-key-first model display sort and empty
firstTimestamp placeholder).
114 tests pass. Build succeeds at 132KB.
Lists common signals in the dashboard (cache hit, retry rate,
model mix, tool patterns) and what each typically means.
Points readers toward interpreting their own data without
overpromising automatic diagnosis.