Install
openclaw skills install usage-costsReport AI token usage and estimated costs. Use when: owner asks about costs today/yesterday/this week, per session, or per model. Shows main session, cron jobs, and subagents. Answers: 'how much did today cost?', 'how much was this session?', 'what was last week's spend?'
openclaw skills install usage-costsReports token usage and estimated costs from OpenClaw sessions.
CONTEXT_FILE="/opt/ocana/openclaw/workspace/skills/usage-costs/.context"
[ -f "$CONTEXT_FILE" ] && source "$CONTEXT_FILE"
# Provides: $OWNER_PHONE, $PRICING_INPUT, $PRICING_OUTPUT, $PRICING_CACHE_READ
openclaw status --deep (current token counts per session)/opt/ocana/openclaw/cron/runs/*.jsonl (usage field per run)/opt/ocana/openclaw/workspace/data/token-history.jsonl (daily aggregates)| Type | Price |
|---|---|
| Input | $3.00 / 1M tokens |
| Output | $15.00 / 1M tokens |
| Cache read | $0.30 / 1M tokens |
| Cache write | $3.75 / 1M tokens |
# Get current session token counts
openclaw status --deep 2>/dev/null | grep -E "agent:main|direct|cached" | head -20
Parse output: each row has session_key | kind | age | model | tokens.
#!/usr/bin/env python3
import json, glob, os
from datetime import datetime, timezone, timedelta
def get_cron_usage(days_back=1):
cutoff = datetime.now(timezone.utc) - timedelta(days=days_back)
cutoff_ts = cutoff.timestamp() * 1000
total_input = 0
total_output = 0
runs = []
for f in glob.glob('/opt/ocana/openclaw/cron/runs/*.jsonl'):
job_name = os.path.basename(f).replace('.jsonl', '')
with open(f) as fh:
for line in fh:
try:
d = json.loads(line)
if d.get('ts', 0) >= cutoff_ts and 'usage' in d:
inp = d['usage'].get('input_tokens', 0)
out = d['usage'].get('output_tokens', 0)
total_input += inp
total_output += out
runs.append({
'job': d.get('name', job_name),
'input': inp,
'output': out,
'ts': d['ts']
})
except:
pass
return total_input, total_output, runs
inp, out, runs = get_cron_usage(days_back=1)
cost = (inp / 1_000_000 * 3) + (out / 1_000_000 * 15)
print(f"Cron tokens (last 24h): {inp:,} in / {out:,} out")
print(f"Estimated cost: ${cost:.2f}")
print(f"Runs: {len(runs)}")
📊 Cost Report — 2026-04-04
Main session: ~276K tokens (100% cached)
Cron runs: 25 runs | X in / Y out tokens
Subagents: N sessions | X tokens
Estimated total: ~$Z
(Cron: $A | Subagents: $B | Main session: estimated $C)
Note: Main session cost is estimated — cache reduces actual cost by ~90%.
/opt/ocana/openclaw/workspace/data/token-history.jsonlopenclaw status --deepagent:main:main row → tokens fieldAppend to /opt/ocana/openclaw/workspace/data/token-history.jsonl:
{"date": "2026-04-04", "input": 133, "output": 17376, "cache_read": 900000, "cost_usd": 0.54, "cron_runs": 25, "subagent_runs": 4}
This is the authoritative method for extracting real costs — works for Anthropic/Claude models:
python3 -c "
import json, glob, os
from datetime import datetime, timezone
sessions_dir = '/opt/ocana/openclaw/agents/main/sessions'
files = glob.glob(f'{sessions_dir}/*.jsonl')
today = datetime.now(timezone.utc).date()
total_cost = 0
total_cache_write = 0
total_cache_read = 0
sessions_today = 0
for fpath in files:
mtime = datetime.fromtimestamp(os.path.getmtime(fpath), tz=timezone.utc).date()
if mtime != today:
continue
sessions_today += 1
with open(fpath) as f:
for line in f:
try:
l = json.loads(line)
if l.get('type') == 'message' and l.get('message',{}).get('role') == 'assistant':
u = l['message'].get('usage',{})
total_cost += u.get('cost',{}).get('total',0)
total_cache_write += u.get('cacheWrite',0)
total_cache_read += u.get('cacheRead',0)
except: pass
print(f'Today: {sessions_today} sessions — \${total_cost:.2f}')
print(f'Cache writes: {total_cache_write:,} tokens')
print(f'Cache reads: {total_cache_read:,} tokens')
"
⚠️ Provider compatibility:
"how much did today cost?" "how much was this session?" "how much this week?" "show me costs"