See what your agent sessions actually cost.
Static page plus a tiny Python exporter: OpenClaw, Claude Code, and Codex session spend. API cost vs OAuth subscription value, per model and per agent. No backend or external runtime assets.
git clone https://github.com/escoffier-labs/usage-tracker.git
cd usage-tracker
# export local session transcripts to data/usage.json, then open the static page
python3 bin/export_usage.py --since 30d
python3 -m http.server 5200| Job | What you get | |
|---|---|---|
| Collect | Local transcripts | OpenClaw, Claude Code, Codex rollouts |
| Split | API vs OAuth value | What you paid vs what subscriptions absorbed |
| Chart | Models and agents | Daily series, per-model bars, session tables |
| Stay local | Static HTML | No backend or third-party requests |
git clone https://github.com/escoffier-labs/usage-tracker.git
cd usage-tracker
# Build data/usage.json from your OpenClaw + Claude Code sessions
python3 bin/export_usage.py --since 30d
# Print a compact machine summary for station health or daily briefs
python3 bin/export_usage.py --since 30d --summary-json
# Serve the page
python3 -m http.server 5200Open http://localhost:5200.
For an always-fresh dataset, install the opt-in user-systemd timer (5 minute refresh):
cp bin/usage-tracker-export.service ~/.config/systemd/user/
cp bin/usage-tracker-export.timer ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now usage-tracker-export.timer(Edit the service file's ExecStart path to point at wherever you cloned this repo.)
Each call is classified as oauth (subscription burn, billed flat) or api (real per-token spend):
- Calls served by a subscription backend are detected from the API id (
openai-chatgpt-responses,cli,google-gemini-cli) regardless of provider. - Providers in the OAuth set (
openai-codex,claude-cli,acpx,google-gemini-cliby default) areoauth; everything else isapi. - Override per export with
--oauth-providers. Example: if grok runs on a SuperGrok subscription via device-code OAuth, use--oauth-providers openai-codex,claude-cli,acpx,google-gemini-cli,xai. - Claude Code records are always
oauth(Claude Code transcripts carry token counts but no cost; the exporter estimates the API-equivalent cost from a built-in pricing table). Disable the source with--no-claude-code, point elsewhere with--claude-projects PATH, or include more machines/backups with repeatable--extra-claude-projects PATH. - Codex CLI rollouts (
~/.codex/sessionsand~/.codex/archived_sessions) are alwaysoauth(ChatGPT subscription); per-call tokens come fromtoken_countevents and cost is estimated from the same pricing table. The exporter also reads~/.codex/state_5.sqlitefor total-only backfill when a Codex thread exists but its rollout records are missing. Disable with--no-codex, point elsewhere with--codex-sessions PATH, include more machines/backups with repeatable--extra-codex-sessions PATH, or add more SQLite backfills with repeatable--extra-codex-state-db PATH. - Models missing from the pricing table export with
costUsd: null; the page counts them as "calls missing cost data" instead of silently pricing them at zero.
If data/usage.json is missing (e.g., you opened the page on a different machine), drop one or more OpenClaw *.trajectory.jsonl files or a previously-exported usage.json onto the page. Records are parsed client-side and cached in localStorage.
Generated from docs/assets/workflows/usage-evidence.json with plating workflow.
bin/export_usage.pywalks~/.openclaw/agents/*/sessions/*.jsonl(plain session transcripts; one per session),~/.claude/projects/*/*.jsonl(Claude Code), and~/.codex/**/*.jsonl(Codex CLI rollouts, including archived sessions), extracts per-call usage, writes a flat array todata/usage.json, and uses Codexstate_5.sqliteonly as a total-only missing-thread backfill. OpenClaw's*.trajectory.jsonlfiles are NOT used: they only exist for a fraction of runs and undercount usage by an order of magnitude.- Codex profile/account counters may include server-side usage that is not retained in local rollout files or SQLite state. This tracker reports local evidence plus local backfill, not an authoritative account lifetime total.
index.htmlfetchesdata/usage.jsonon load (drag-and-drop fallback), normalizes records into renderer-friendly aggregates, displays.- No backend. localStorage caches the last load and your subscription settings.
python3 -m pip install pytest
python3 -m pytest tests/ # exporter tests
node tests/frontend.test.js # dependency-free frontend behavior checks
python3 -m http.server 5200 # pageExample multi-machine export:
python3 bin/export_usage.py \
--extra-claude-projects /tmp/remote-usage/claude/projects \
--extra-codex-sessions /tmp/remote-usage/codex \
--extra-codex-state-db /tmp/remote-usage/codex/state_5.sqliteMIT