A local HTML dashboard for multi-provider AI token usage that auto-recalculates on refresh from local session data. Supports Codex, Claude, PI Coding Agent, and DeepSeek Harness.
- Provider toggle filtered to providers present on the system (
Combined,Codex,Claude,PI,DeepSeek Harness) - Range-aware stats cards for total, days, sessions, highest day, explicit input/output/total token totals, and cost totals
- Today + calendar-week rollups
- Activity Rhythm heatmap + time-of-day summary for the selected provider and date range
- Daily breakdown table with sessions, input, output, cached, total token, and total cost columns
- Range-scoped breakdown table grouped by
Agent CLI+Model, including cost totals - Horizontal bar chart (with rank, total tokens, and session count) above the table
- Auto-recalc on browser refresh and every 5 minutes via local
localhostendpoint - Compact tmux status rendering for Today/MTD total tokens, MTD cost, and ChatGPT subscription quota/reset information via
scripts/render_tmux_status.py, aligned to 5-minute refresh boundaries
dashboard/index.html: Dashboard UIscripts/ai_usage_recalc_server.py: Thin local HTTP recalc service (/health,/recalc)scripts/dashboard_core/config.py: Runtime config/env resolutionscripts/dashboard_core/chatgpt_subscription.py: Credential-safe Codex app-server adapter for ChatGPT plan and quota datascripts/dashboard_core/collectors.py: Codex/Claude/PI/DeepSeek Harness usage ingestionscripts/dashboard_core/aggregation.py: Daily aggregation + date window logicscripts/dashboard_core/render.py: HTML rewrite + dataset injectionscripts/dashboard_core/pipeline.py: End-to-end recalc orchestrationscripts/dashboard_core/pricing.py: Built-in rate card + optional pricing override loaderscripts/dashboard_core/tmux_status.py: Compact status snapshot + string formatting helpers for tmuxscripts/render_tmux_status.py: Cache-aware tmux status renderer that refreshes dashboard data on demandscripts/run_local.sh: Convenience launcher for local developmentscripts/tests/test_harness_contracts.py: Deterministic pipeline/harness invariantslaunchd/*.plist.example: Optional macOS LaunchAgent templatedocs/harness-engineering-adoption.md: Harness-engineering rationale + validation loop
- macOS or Linux
- Python 3.9+
- Local Codex session logs in
~/.codex/sessions - Codex CLI signed in with ChatGPT for subscription quota display (optional; token and cost status still works without it)
- Local Claude project logs in
~/.claude/projects(optional; dashboard still works without Claude data) - Local PI agent state in
~/.pi/agent(optional; dashboard still works without PI data) - Local DeepSeek Harness state in
~/.dsh(optional; dashboard still works without DSH data) - For compressed DSH logs: Python 3.14+ with
compression.zstd, azstdexecutable, or Node.js 22+ (a normal DSH installation already requires Node.js)
- Start the local recalc service:
cd /path/to/ai-token-usage-dashboard
chmod +x scripts/run_local.sh
./scripts/run_local.sh- Open the dashboard:
open http://127.0.0.1:8765/- Refresh the page.
- On refresh, the dashboard calls
/recalcon the same localhost server - By default, the service rewrites
tmp/index.runtime.html(untracked), so git-trackeddashboard/index.htmlstays unchanged - The page reloads with fresh values after recalc completes
- On refresh, the dashboard calls
Environment variables:
AI_USAGE_SERVER_HOST(default:127.0.0.1)AI_USAGE_SERVER_PORT(default:8765)AI_USAGE_CODEX_SESSIONS_ROOT(default:~/.codex/sessions)AI_USAGE_CLAUDE_PROJECTS_ROOT(default:~/.claude/projects)AI_USAGE_PI_AGENT_ROOT(default:~/.pi/agent)AI_USAGE_DSH_HOME(default:~/.dsh; sessions are read from itssessionsdirectory)AI_USAGE_ZSTD_BIN(optional path to azstdexecutable used when Python lackscompression.zstd; common Homebrew paths and Node.js are automatic fallbacks)AI_USAGE_DASHBOARD_HTML(default viascripts/run_local.sh:<repo>/tmp/index.runtime.html, seeded from<repo>/dashboard/index.html)AI_USAGE_PRICING_FILE(optional JSON rate-card override file merged over the built-in pricing table)AI_USAGE_PARSE_CACHE_FILE(persistent observed-session history and parse cache; default:<repo>/tmp/recalc_parse_cache.json)AI_USAGE_RECALC_LOG_FILE(optional JSONL file for persistent/recalctiming/error logs; default:<repo>/tmp/recalc_timings.jsonl)AI_USAGE_CHATGPT_USAGE(autooroff; default:auto)AI_USAGE_CODEX_BIN(Codex executable used for the app-server account API; default:codex)AI_USAGE_CHATGPT_TIMEOUT_SECONDS(overall account/quota request timeout; default:3)
You can surface a compact AI usage pulse directly in tmux.
Compact ChatGPT subscription format at the recommended 96-character budget:
GPT Pro · 5h 72% ↻2h 14m · 7d 61% ↻2d 17h 39m · Today 13.3M · MTD 934.7M · $753
Where:
GPT Prois the detected ChatGPT plan; it is omitted for API-key, Bedrock, signed-out, or disabled account usage5hand7dare the primary and weekly Codex quota windows, expressed as percent remaining- a fully reset, inactive five-hour window remains visible as
5h 100% ↻nowwhen the Codex endpoint temporarily omits it; an active value is never replaced with this fallback ↻shows how long remains until each quota resets, using compact days, hours, and minutes such as2d 17h 39m,4h 55m, or42m; zero-value units are omitted, and resets less than one minute away shownow- the complete five-hour quota/reset segment is prioritized at every usable width, and both active reset countdowns remain visible in the normal 96-character presentation
TodayandMTDare total tokens across the selected local scope; the defaultcombinedscope includes Codex, Claude, PI, and DeepSeek Harness, while input/output details are intentionally omitted- the amount after the MTD token total is the locally derived month-to-date cost estimate, not an additional ChatGPT subscription charge
- middle dots consistently separate plan, quota, token, and cost values
- healthy status text is omitted;
partial,stale, orerrorappears only when attention is needed
- tmux redraws the status every few seconds
scripts/render_tmux_status.pyonly recalculates when crossing a 5-minute boundary (:00,:05,:10, ...)- in
automode, the renderer uses the stable Codex app-serveraccount/readandaccount/rateLimits/readmethods; it never reads OAuth credentials directly - the status renderer caches normalized local metrics and quota data in
tmp/tmux_status.json - a quota request has a hard timeout; the last successful quota remains visible as stale data without breaking token/cost status
- a more constrained named model quota is added only when it is tighter than the general Codex quota
- if neither provider data nor a usable ChatGPT quota is available, it falls back to
AI unavailable
The tmux config supports enabling/disabling the AI segment with a user option and key binding:
set -g @ai_token_usage_status 1→ enabledset -g @ai_token_usage_status 0→ disabledPrefix + Atoggles it live
Example command to preview the segment outside tmux:
python3 scripts/render_tmux_status.py --refresh-interval-minutes 5 --max-width 96Disable ChatGPT account lookups while retaining total tokens and MTD cost:
python3 scripts/render_tmux_status.py --chatgpt-usage off --max-width 96Show only native DeepSeek Harness usage:
python3 scripts/render_tmux_status.py --scope dsh --chatgpt-usage off --max-width 96- Copy and edit the template:
cp launchd/com.user.ai-token-usage-dashboard-recalc.plist.example \
~/Library/LaunchAgents/com.user.ai-token-usage-dashboard-recalc.plist-
Replace placeholder absolute paths.
-
Load it:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.user.ai-token-usage-dashboard-recalc.plist
launchctl kickstart -k gui/$(id -u)/com.user.ai-token-usage-dashboard-recalc- Verify:
curl http://127.0.0.1:8765/health- The dashboard is designed for local use and reads local session logs from Codex, Claude, PI, and DeepSeek Harness when present.
- Daily rows in the injected dataset include
sessions,input_tokens,output_tokens,cached_tokens,total_tokens,input_cost_usd,output_cost_usd,cached_cost_usd,total_cost_usd,cost_complete, andbreakdown_rowsgrouped by(agent_cli, model). - A built-in versioned pricing table is used for derived costs and can be overridden via
AI_USAGE_PRICING_FILE. DSH first checks adshrate-card entry, then reuses known PI, Claude, or Codex model-family rates; an unmapped DSH model is reported as partial cost rather than trusted zero. - Codex usage keeps the latest
token_countsnapshot per session, extractsoriginator/sourcefor the CLI bucket, uses the latest observedturn_context.payload.modelwhen present, and prices uncached input separately from cached tokens. - ChatGPT subscription status is fetched through the Codex app server, and only normalized plan/quota/reset/credit metadata is cached. Email addresses, account IDs, and OAuth tokens are neither returned nor persisted by the dashboard.
- Claude request usage is deduplicated by
(sessionId, requestId), keeps the highest observed token values for the request, computescached_tokens = cache_creation_input_tokens + cache_read_input_tokens, and derives cost from the model rate card. - Claude-style context attribution is extracted when transcript events expose it: Skills from
<command-message>slash commands, Agents/Subagents fromAgent/Tasktool calls, MCP servers frommcp__server__methodtools, Tools fromtool_useblocks, and Plugins / Extensions from namespaced slash commands plus plugin/extension metadata or tool namespaces. Attribution token/cost shares are estimated from the session totals for matching transcript events. - PI usage is read from
~/.pi/agent/sessions/**/*.jsonl, tracks the active model viamodel_changeevents, computescached_tokens = cacheRead + cacheWrite, prefers nativemessage.usage.cost.*when present, and resumes parsing from the last verified byte offset when a session log grows append-only. - DeepSeek Harness usage is read from
$DSH_HOME/sessions/**/session.jsonl.zstdor uncompressedsession.jsonl. The collector excludes inherited fork seed prefixes, followsrequest/headerprovider/model changes, uses the final provider-reported usage per(turn, step)without double-counting its earlier usage chunk, retains usage-only interrupted steps, includes persistedcompaction/summarymodel calls, and computescached_tokens = cacheReadTokens + cacheWriteTokens. Only calls whose provider usage is persisted can be counted; current DSH title-generation records describe the request but do not persist its usage result. - Once a Codex, Claude, PI, or DSH session has been observed, its last recorded usage remains in the persistent parse history if the source session log is later deleted. To reset history that no longer has a source log, stop the service, delete
AI_USAGE_PARSE_CACHE_FILE, and restart; sessions deleted before the dashboard first observed them cannot be recovered. - Unmapped provider/model pricing is surfaced as partial cost in the API/UI instead of silently treated as trusted zero cost.
/recalcresponses exposeServer-Timingheaders andtimings_msin the JSON payload, and the dashboard hero shows the latest refresh timing summary for quick diagnosis.- No third-party services are required.
Run the full local harness checks:
python3 -m unittest discover -s scripts/testsThis repo is skill-ready and includes:
SKILL.md(trigger metadata + workflow instructions)agents/openai.yaml(skill UI metadata)
mkdir -p ~/.codex/skills
ln -sfn /absolute/path/to/ai-token-usage-dashboard \
~/.codex/skills/ai-token-usage-dashboardRestart Codex after installation.
Ask with the skill name, for example:
Use $ai-token-usage-dashboard to recalc and update my usage dashboard.
