Agent Token Usage

Other

Summarize daily LLM token usage per OpenClaw agent from trajectory logs, showing input, output, cache reads/writes, total, and optional billable token estima...

Install

openclaw skills install agent-token-usage

agent-token-usage 📊

Accurately attribute LLM token consumption across all OpenClaw agents for a given day.

📊 button next to Control UI search

Modal with per-agent token breakdown

Ships two things in one skill:

  1. CLIscripts/agent_token_usage.py, always works, zero setup
  2. UI button — optional apply-ui.sh injects a 📊 button into Control UI's header next to Search; clicking shows today's per-agent table in a modal

Why this exists

sessions_list returns each session's totalTokens field which is the last context window size, NOT the cumulative consumption across all LLM calls in that session. For long-running sessions, real consumption can be 100×+ larger. This skill reads trajectory.jsonl (the authoritative source) and sums real usage objects per agent.

Quick start (CLI)

# default = today, local date
python ~/.openclaw/workspace/skills/agent-token-usage/scripts/agent_token_usage.py

# specific date
python …/agent_token_usage.py --date 2026-05-20

# equivalent billable (cacheRead × 0.1 + cacheWrite × 1.25 + input + output)
python …/agent_token_usage.py --date 2026-05-20 --billable

# JSON
python …/agent_token_usage.py --format json

Optional: 📊 button in Control UI

bash ~/.openclaw/workspace/skills/agent-token-usage/apply-ui.sh

Then refresh the Control UI tab. The button appears next to Search; clicking shows the modal.

Uninstall:

bash ~/.openclaw/workspace/skills/agent-token-usage/remove-ui.sh

Per-browser toggle:

localStorage.setItem('milly.tokenUsageBtn', 'off')
localStorage.removeItem('milly.tokenUsageBtn')

How the UI part works

launchd (5min)  →  refresh-data.sh  →  <ui>/data/agent-token-usage.json
                                              │ same-origin fetch
                                              ▼
                                    Control UI bundle (patched IIFE)
                                       📊 button → modal table

CSP-friendly (connect-src 'self') because data is served from the UI's own origin. No extra daemon, no extra port. After openclaw update overwrites dist/control-ui/*, just re-run apply-ui.sh — idempotent.

Column semantics

FieldMeaningBilling weight
inputnew, non-cached prompt tokens1.0×
outputmodel-generated tokens1.0× (typically 5× input price)
cacheReadprompt tokens served from prompt cache~0.1×
cacheWriteprompt tokens written to cache~1.25×
totalsum of all four (real LLM throughput)
~billweighted billable-equivalent tokens

Use total to see "who's burning the most LLM compute"; use ~bill to see "who's actually most expensive". High-cacheRead agents look huge but are cheap; high-input agents look small but cost more.

How it works

  1. Walk ~/.openclaw/agents/<agent>/sessions/*.trajectory.jsonl
  2. For each line, check ts startswith target date
  3. DFS-search the data field for a usage dict with token counters
  4. Sum per agent; also track session count and models used

Caveats

  • Only counts LLM calls (events with a usage object) — non-LLM tool calls excluded by design
  • Cache multipliers are Anthropic ballpark numbers; adjust for other providers mentally
  • Does NOT compute USD cost — use the model-usage skill for $ amounts
  • --date matches ISO timestamps in trajectory (UTC); late-night events can shift by a day for non-UTC users
  • UI auto-refresh job (launchd) is macOS only; on Linux, run scripts/refresh-data.sh via cron/systemd timer

Files

FilePurpose
scripts/agent_token_usage.pyCLI aggregator
scripts/refresh-data.shWrites JSON into every patched Control UI dist
scripts/token-usage-button.iife.jsUI patch payload (button + modal + same-origin fetch)
apply-ui.shInject IIFE, cache-bust, install launchd refresh job
remove-ui.shRestore bundle, remove launchd job, delete data dir