Skip to content

feat: add cost tracking dashboard#347

Merged
asheshgoplani merged 17 commits intoasheshgoplani:mainfrom
BestSithInEU:feat/cost-tracking-dashboard
Mar 18, 2026
Merged

feat: add cost tracking dashboard#347
asheshgoplani merged 17 commits intoasheshgoplani:mainfrom
BestSithInEU:feat/cost-tracking-dashboard

Conversation

@BestSithInEU
Copy link
Copy Markdown
Contributor

Summary

Real-time token usage and cost tracking for all AI agent sessions with TUI dashboard, web dashboard, and CLI tools.

What's included

  • Cost collection: Claude Code hook integration reads transcript files for token usage on each turn
  • Pricing system: Hardcoded defaults for 9 models (Claude Opus/Sonnet/Haiku, Gemini Pro/Flash, GPT-4o/4.1, o3, o4-mini). Daily cache refresh, user overrides via config.toml
  • Budget enforcement: Configurable daily/weekly/monthly/per-group/per-session limits with 80% warning and 100% hard stop (untested)
  • TUI: Cost in header stats bar. $ key opens full cost dashboard
  • Web dashboard (/costs): Chart.js charts, group drill-down, session detail views, SSE live updates, CSV/JSON export
  • CLI: agent-deck costs sync (backfill from transcripts), agent-deck costs summary
  • Storage: cost_events table in existing statedb with microdollar integer arithmetic

Test plan

  • 27 unit tests in internal/costs/ pass with -race
  • 2 config parsing tests pass
  • go vet clean, build compiles
  • costs sync backfills from 4 Claude sessions (610 events)
  • TUI $ key shows cost dashboard with data
  • Web /costs page renders charts, groups, session detail views
  • Hook-based real-time tracking verified with Claude Code sessions
  • Budget enforcement with configured limits
  • Gemini/Codex output parsing (implemented, untested)

Add cost tracking fields to Home struct with atomic counters for
today/week totals. Header stats show today's cost when data exists.
Press $ to open a full cost dashboard showing daily/weekly/monthly
totals, token breakdown, top sessions by cost, and per-model costs.
Cost totals refresh every tick via the existing tick handler.
…page

Add handlers_costs.go with six API endpoints (summary, daily, sessions,
models, export, stream SSE) and a costs HTML page handler. Register
routes and cost subscriber infrastructure in server.go. Include Chart.js
UMD bundle and a dark-themed costs.html dashboard with live SSE updates.
Hook payload doesn't include token usage data. Instead, on Stop
events, read the last line of the Claude transcript JSONL file
to extract model, input/output/cache tokens. Includes debug
logging to ~/.agent-deck/cost-debug.log for validation.
agent-deck costs sync — scans managed Claude sessions' transcript
files and backfills historical cost_events. Handles both assistant
turns and progress entries (subagent Haiku/Sonnet usage).

agent-deck costs summary — prints cost totals, top sessions, and
model breakdown to stdout.
Go's time.Time.UTC() stored as "2026-03-16 21:06:37 +0000 UTC"
which SQLite's date() can't parse. Format as RFC3339 instead.
Add DailyBySession and CostByModelForSession query methods for
the session detail web view.
Groups tab with per-group cost totals and drill-down. Clickable
sessions show daily spend chart, model breakdown, and token
counts. Breadcrumb navigation between views. New API endpoints:
/api/costs/groups and /api/costs/session?id=.
Copilot AI review requested due to automatic review settings March 16, 2026 22:03
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end cost tracking (collection → storage → pricing/budgets → dashboards) to Agent Deck, exposing live token/cost visibility in both the TUI and the web UI.

Changes:

  • Introduces internal/costs package for parsing usage, pricing, storage, retention, and budget checking.
  • Adds web /costs dashboard with supporting API endpoints + SSE stream.
  • Wires cost tracking into the TUI header/dashboard, hook handler, and CLI subcommands.

Reviewed changes

Copilot reviewed 34 out of 35 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
internal/web/static/styles.css Adds styling for the web “Costs” nav button
internal/web/static/index.html Adds “💰 Costs” link to /costs
internal/web/static/costs.html New web cost dashboard UI (charts/tables/SSE/export)
internal/web/server.go Registers /costs + cost APIs; adds cost store/subscriber fields
internal/web/handlers_costs.go Implements cost summary/daily/sessions/models/groups/detail/export + SSE handlers
internal/ui/home.go Adds cost totals to TUI header and $ cost dashboard toggle
internal/ui/help.go Adds $ help entry for cost dashboard
internal/ui/cost_dashboard.go New TUI cost dashboard view
internal/statedb/statedb.go Bumps schema + adds cost_events table and indexes
internal/session/userconfig_cost_test.go Adds tests for [costs] config parsing/defaults
internal/session/userconfig.go Adds CostsSettings (budgets/pricing/timezone/retention)
internal/costs/watcher_test.go Tests filesystem watcher for incoming cost events
internal/costs/watcher.go Implements fsnotify-based cost event directory watcher
internal/costs/sync.go Adds transcript backfill (costs sync) for Claude JSONL transcripts
internal/costs/store_test.go Adds store/query/retention/format tests
internal/costs/store.go Implements SQLite persistence + aggregation queries
internal/costs/pricing_test.go Tests pricing defaults, overrides, normalization, cache I/O
internal/costs/pricing.go Implements hardcoded pricing + cache + overrides + cost computation
internal/costs/poller_test.go Tests tmux-output polling deduplication
internal/costs/poller.go Adds deduplicating poller for non-hook tools
internal/costs/parser_test.go Tests Claude/Gemini/OpenAI parsing and collector behavior
internal/costs/parser_openai.go Adds OpenAI/Codex output parser
internal/costs/parser_gemini.go Adds Gemini output parser + comma-int parsing
internal/costs/parser_claude.go Adds Claude Stop-hook JSON parser
internal/costs/fetcher_test.go Tests pricing fetcher cache behavior
internal/costs/fetcher.go Adds daily pricing “fetcher” (currently writes defaults to cache)
internal/costs/costs.go Defines cost event/summary types + USD formatting
internal/costs/collector.go Routes tool outputs to parsers and applies pricing
internal/costs/budget_test.go Adds unit tests for budget checker thresholds
internal/costs/budget.go Implements budget evaluation (global/session/group) helpers
cmd/agent-deck/main.go Initializes cost store/pricer/budgets/watcher; wires to TUI + web server
cmd/agent-deck/hook_handler.go Writes per-turn cost event files by reading Claude transcripts on Stop hooks
cmd/agent-deck/costs_cmd.go Adds `agent-deck costs sync
README.md Documents new cost tracking features + config snippet

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

- Fix token auth on /costs page and Costs nav link
- Fix CachePath double-join (dir vs file path)
- Fix readLastLine for files without trailing newline
- Fix XSS in inline onclick handlers (use data attrs)
- Fix TotalByDateRange timestamp format consistency
- Throttle refreshCostTotals to every 10s
- Add error handling in session detail handler
- Gate debug logging behind AGENTDECK_DEBUG env var
- Remove misleading comment in sync.go
- Fix implicit event object in showTab
- Close storage in CLI cost commands
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-to-end cost tracking (token usage → priced cost events → budgets) across Agent Deck sessions, surfaced via a new TUI dashboard, a web dashboard, and CLI utilities, with persistence in the existing SQLite state DB.

Changes:

  • Introduces a cost_events SQLite table (+ store/query layer) and wiring to ingest cost events from Claude hooks and transcript backfill.
  • Adds pricing (hardcoded defaults + cache + config overrides) and budget checking primitives.
  • Adds UI surfaces: TUI $ cost dashboard and a web /costs dashboard with APIs, SSE updates, and export.

Reviewed changes

Copilot reviewed 35 out of 36 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
internal/web/static/styles.css Adds styling for a “Costs” header button in web UI.
internal/web/static/index.html Adds navigation link to /costs.
internal/web/static/costs.html New standalone cost dashboard page (charts, tables, SSE, exports).
internal/web/static/app.js Appends auth token to the /costs link when present.
internal/web/server.go Registers cost APIs/routes; adds cost store + subscriber plumbing.
internal/web/handlers_costs.go Implements cost summary/daily/model/session/group/export APIs + SSE stream + /costs page handler.
internal/ui/home.go Wires cost tracking into TUI header and $ key behavior; shows TUI cost dashboard.
internal/ui/help.go Documents $ as “Cost Dashboard” in help overlay.
internal/ui/cost_dashboard.go New TUI cost dashboard view (summary + top sessions + model breakdown).
internal/statedb/statedb.go Bumps schema version; creates cost_events table + indices.
internal/session/userconfig_cost_test.go Tests parsing of new [costs] config sections.
internal/session/userconfig.go Adds CostsSettings (budgets, pricing overrides, retention, timezone).
internal/costs/watcher_test.go Tests fsnotify-based cost event watcher behavior.
internal/costs/watcher.go New directory watcher for JSON cost event files emitted by hooks.
internal/costs/sync.go Adds transcript backfill (Claude JSONL parsing) into cost_events.
internal/costs/store_test.go Tests for store writes/queries, retention purge, formatting.
internal/costs/store.go SQLite store implementation for inserting/querying cost events + aggregates.
internal/costs/pricing_test.go Tests hardcoded pricing, cost computation, cache IO, overrides, normalization.
internal/costs/pricing.go Pricing resolver (override > cache > defaults) + cost computation.
internal/costs/poller_test.go Tests dedup behavior for polling-based collectors.
internal/costs/poller.go Adds deduped polling entrypoint for non-hook tools.
internal/costs/parser_test.go Tests Claude hook parsing + Gemini/OpenAI output parsing + collector.
internal/costs/parser_openai.go Parses OpenAI/Codex CLI “Tokens used …” output.
internal/costs/parser_gemini.go Parses Gemini CLI “Token count …” output.
internal/costs/parser_claude.go Parses Claude Code Stop hook payload usage.
internal/costs/fetcher_test.go Tests pricing cache age and writing cache file.
internal/costs/fetcher.go Daily pricing cache writer (currently writes defaults).
internal/costs/costs.go Defines core cost event/summary structs + USD formatting helper.
internal/costs/collector.go Routes tool output to parsers and applies pricing + IDs/timestamps.
internal/costs/budget_test.go Tests budget checker warning/stop behavior and session limits.
internal/costs/budget.go Budget checker (global/session/group; warn at 80%, stop at 100%).
cmd/agent-deck/main.go Initializes cost store/pricer/budgets/watcher; wires store into web server.
cmd/agent-deck/hook_handler.go Writes cost event JSON files on Claude Stop hooks by reading transcript usage.
cmd/agent-deck/costs_cmd.go Adds agent-deck costs sync and agent-deck costs summary.
README.md Documents cost tracking, config options, and $ shortcut.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

- Format timestamps as RFC3339 in transactional queries
- Fix watcher: delete file only after successful enqueue, close channel on exit
- Use math.Round for float-to-microdollar budget conversion
- Remove unused cost subscriber path from SSE handler
- Propagate errors in budget checker instead of ignoring
- Add fetch error handling in web dashboard
@BestSithInEU
Copy link
Copy Markdown
Contributor Author

All done except:
Budget enforcement with configured limits
Gemini/Codex output parsing (implemented, untested) (I dont have.)

@asheshgoplani asheshgoplani merged commit 75ee403 into asheshgoplani:main Mar 18, 2026
@BestSithInEU
Copy link
Copy Markdown
Contributor Author

@asheshgoplani I realized now can you change $ keybinding to something else? It's conflicted to current filter.

@asheshgoplani
Copy link
Copy Markdown
Owner

Good catch @BestSithInEU. The $ key currently opens the cost dashboard when cost tracking is active, which makes the error filter unreachable since costStore is always non-nil when the DB exists.

We should move the cost dashboard to a different key (e.g. C for Costs) and keep $ for the error filter. I'll open an issue to track this.

@asheshgoplani
Copy link
Copy Markdown
Owner

@BestSithInEU Fixed! Cost dashboard is now on C (uppercase C) and $ is restored for the error filter. The fix is on main and will ship in the next release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants