
Clawdbot Cost Tracker
- 37 installs
- 638 repo stars
- Updated March 7, 2026
- sundial-org/awesome-openclaw-skills
Helps with ai & agent building tasks during AI-assisted development.
About
clawdbot-cost-tracker is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- clawdbot-cost-tracker
- AI & Agent Building
- AI-coding skill
Clawdbot Cost Tracker by the numbers
- 37 all-time installs (skills.sh)
- Ranked #8,545 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/sundial-org/awesome-openclaw-skills --skill clawdbot-cost-trackerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 37 |
|---|---|
| repo stars | ★ 638 |
| Last updated | March 7, 2026 |
| Repository | sundial-org/awesome-openclaw-skills ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Clawdbot Cost Tracker
Track token usage and estimate API costs across all Clawdbot sessions.
Quick Start
Get Current Usage
# Use sessions_list to get token data
sessions_list --limit 20 --messageLimit 0Extract totalTokens and model from each session.
Calculate Cost
Model pricing (USD per million tokens):
| Model | Input | Output | Avg Ratio |
|---|---|---|---|
| claude-opus-4-5 | $15 | $75 | 30/70 |
| claude-sonnet-4 | $3 | $15 | 30/70 |
| codex-mini-latest | $1 | $5 | 30/70 |
| gpt-4o | $2.5 | $10 | 30/70 |
| gpt-4o-mini | $0.15 | $0.6 | 30/70 |
Cost formula (assuming 30% input, 70% output):
cost = tokens * (0.3 * input_price + 0.7 * output_price) / 1,000,000Daily Tracking
Save Usage Snapshot
Store daily snapshots in memory/usage/YYYY-MM-DD.json:
{
"date": "2026-01-29",
"timestamp": "2026-01-29T08:20:00+08:00",
"sessions": {
"session_key": {
"model": "claude-opus-4-5",
"totalTokens": 123456,
"channel": "discord"
}
},
"summary": {
"totalTokens": 250000,
"byModel": {
"claude-opus-4-5": 220000,
"codex-mini-latest": 30000
}
}
}Calculate Daily Cost
Compare consecutive days to get daily usage:
daily_tokens = today.totalTokens - yesterday.totalTokens
daily_cost = estimate_cost(daily_tokens, model)Scripts
scripts/snapshot-usage.js
Creates a usage snapshot from current session data.
node scripts/snapshot-usage.js [output-dir]
# Default output: memory/usage/YYYY-MM-DD.jsonscripts/calculate-cost.js
Calculates cost for a date range.
node scripts/calculate-cost.js [date]
# Default: today
# Output: JSON with token delta and estimated costIntegration with Daily Report
Add to HEARTBEAT.md: 1. Call sessions_list to get current tokens 2. Load previous day's snapshot from memory/usage/ 3. Calculate delta and estimate cost 4. Include in daily report format:
💰 **Clawdbot Cost** (yesterday)
• Used: 45.2k tokens
• Estimated: ~$1.23Color Conventions (Chinese Style)
For financial displays in Chinese context:
- 🔴 Red = Up/Increase
- 🟢 Green = Down/Decrease
#!/usr/bin/env node
/**
* Clawdbot Cost Calculator
*
* Calculates daily API cost by comparing consecutive usage snapshots.
* Compares today's snapshot with yesterday's to determine token delta.
*
* Usage:
* node calculate-cost.js [date] [usage-dir]
*
* Arguments:
* date - Target date (YYYY-MM-DD), defaults to today
* usage-dir - Directory containing snapshots, defaults to ~/clawd/memory/usage
*
* Examples:
* node calculate-cost.js # Today's cost
* node calculate-cost.js 2026-01-29 # Specific date
* node calculate-cost.js 2026-01-29 ./usage # Custom directory
*
* Output:
* JSON object with token counts, deltas, and estimated costs
*
* @author Clawdbot
* @license MIT
*/
const fs = require('fs');
const path = require('path');
// Model pricing in USD per million tokens
// Based on public API pricing as of 2026-01
const MODEL_PRICING = {
'claude-opus-4-5': { input: 15, output: 75, avgRatio: 0.3 },
'claude-sonnet-4': { input: 3, output: 15, avgRatio: 0.3 },
'codex-mini-latest': { input: 1, output: 5, avgRatio: 0.3 },
'gpt-4o': { input: 2.5, output: 10, avgRatio: 0.3 },
'gpt-4o-mini': { input: 0.15, output: 0.6, avgRatio: 0.3 },
};
/**
* Get date string for N days ago
* @param {number} daysAgo - Number of days in the past (0 = today)
* @returns {string} Date string in YYYY-MM-DD format
*/
function getDateString(daysAgo = 0) {
const d = new Date();
d.setDate(d.getDate() - daysAgo);
return d.toISOString().split('T')[0];
}
/**
* Load a usage snapshot from disk
* @param {string} usageDir - Directory containing snapshots
* @param {string} date - Date string (YYYY-MM-DD)
* @returns {object|null} Snapshot data or null if not found
*/
function loadSnapshot(usageDir, date) {
const filePath = path.join(usageDir, `${date}.json`);
if (!fs.existsSync(filePath)) return null;
try {
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch (e) {
return null;
}
}
/**
* Get the previous day's date string
* @param {string} dateStr - Date string (YYYY-MM-DD)
* @returns {string} Previous day's date string
*/
function getPreviousDate(dateStr) {
const d = new Date(dateStr);
d.setDate(d.getDate() - 1);
return d.toISOString().split('T')[0];
}
/**
* Estimate cost for a given number of tokens and model
* @param {number} tokens - Token count
* @param {string} model - Model identifier
* @returns {number} Estimated cost in USD
*/
function estimateCost(tokens, model) {
const pricing = MODEL_PRICING[model] || MODEL_PRICING['claude-sonnet-4'];
const inputTokens = tokens * pricing.avgRatio;
const outputTokens = tokens * (1 - pricing.avgRatio);
return (inputTokens * pricing.input + outputTokens * pricing.output) / 1_000_000;
}
/**
* Format token count for human readability
* @param {number} tokens - Token count
* @returns {string} Formatted string (e.g., "45.2k", "1.5M")
*/
function formatTokens(tokens) {
if (tokens >= 1_000_000) {
return `${(tokens / 1_000_000).toFixed(1)}M`;
} else if (tokens >= 1_000) {
return `${(tokens / 1_000).toFixed(1)}k`;
}
return tokens.toString();
}
/**
* Main function - calculates cost for the target date
*/
function main() {
const targetDate = process.argv[2] || getDateString();
const usageDir = process.argv[3] || path.join(process.env.HOME, 'clawd/memory/usage');
// Load today's and yesterday's snapshots
const today = loadSnapshot(usageDir, targetDate);
const prevDate = getPreviousDate(targetDate);
const yesterday = loadSnapshot(usageDir, prevDate);
// Validate that we have today's data
if (!today) {
console.log(JSON.stringify({
status: 'error',
error: `No snapshot found for ${targetDate}`,
hint: 'Run snapshot-usage.js first to create a snapshot'
}, null, 2));
process.exit(1);
}
// Initialize result structure
const result = {
date: targetDate,
previousDate: yesterday ? prevDate : null,
tokens: {
total: today.summary?.totalTokens || 0,
delta: 0,
byModel: {}
},
cost: {
estimated: 0,
byModel: {}
},
formatted: {}
};
// Get token counts by model
const todayByModel = today.summary?.byModel || {};
const yesterdayByModel = yesterday?.summary?.byModel || {};
// Calculate totals and deltas for each model
for (const [model, tokens] of Object.entries(todayByModel)) {
const prevTokens = yesterdayByModel[model] || 0;
const delta = tokens - prevTokens;
result.tokens.byModel[model] = {
total: tokens,
previous: prevTokens,
delta: delta
};
result.tokens.delta += delta;
// Calculate cost only for positive deltas
if (delta > 0) {
const cost = estimateCost(delta, model);
result.cost.byModel[model] = Math.round(cost * 100) / 100;
result.cost.estimated += cost;
}
}
result.cost.estimated = Math.round(result.cost.estimated * 100) / 100;
// Create human-readable formatted output
result.formatted = {
tokens: formatTokens(result.tokens.delta),
cost: `$${result.cost.estimated.toFixed(2)}`,
summary: `${formatTokens(result.tokens.delta)} tokens (~$${result.cost.estimated.toFixed(2)})`
};
// Handle case where no previous snapshot exists (cumulative mode)
if (!yesterday) {
result.note = 'No previous snapshot - showing cumulative totals';
result.cost.estimated = today.estimatedCost?.totalUSD || result.cost.estimated;
result.formatted.cost = `$${result.cost.estimated.toFixed(2)}`;
result.formatted.summary = `${formatTokens(result.tokens.total)} tokens (~$${result.cost.estimated.toFixed(2)}) [cumulative]`;
}
console.log(JSON.stringify(result, null, 2));
}
main();
#!/usr/bin/env node
/**
* Clawdbot Usage Snapshot
*
* Creates a daily snapshot of token usage from Clawdbot sessions.
* Reads session data from stdin (JSON format from sessions_list).
*
* Usage:
* cat sessions.json | node snapshot-usage.js [output-dir]
* node snapshot-usage.js [output-dir] < sessions.json
*
* Output:
* Creates memory/usage/YYYY-MM-DD.json with usage data
*
* @author Clawdbot
* @license MIT
*/
const fs = require('fs');
const path = require('path');
// Model pricing in USD per million tokens
// Based on public API pricing as of 2026-01
const MODEL_PRICING = {
'claude-opus-4-5': { input: 15, output: 75, avgRatio: 0.3 },
'claude-sonnet-4': { input: 3, output: 15, avgRatio: 0.3 },
'codex-mini-latest': { input: 1, output: 5, avgRatio: 0.3 },
'gpt-4o': { input: 2.5, output: 10, avgRatio: 0.3 },
'gpt-4o-mini': { input: 0.15, output: 0.6, avgRatio: 0.3 },
};
/**
* Get current date as YYYY-MM-DD string
* @returns {string} Date string
*/
function getDateString() {
const d = new Date();
return d.toISOString().split('T')[0];
}
/**
* Get current timestamp in ISO format
* @returns {string} ISO timestamp
*/
function getTimestamp() {
return new Date().toISOString();
}
/**
* Estimate cost for a given number of tokens and model
* Assumes 30% input tokens, 70% output tokens (typical for chat)
*
* @param {number} tokens - Total token count
* @param {string} model - Model identifier
* @returns {number} Estimated cost in USD
*/
function estimateCost(tokens, model) {
const pricing = MODEL_PRICING[model] || MODEL_PRICING['claude-sonnet-4'];
const inputTokens = tokens * pricing.avgRatio;
const outputTokens = tokens * (1 - pricing.avgRatio);
return (inputTokens * pricing.input + outputTokens * pricing.output) / 1_000_000;
}
/**
* Main function - reads session data and creates usage snapshot
*/
async function main() {
let input = '';
// Check if running interactively (no piped input)
if (process.stdin.isTTY) {
console.error('Usage: cat sessions.json | node snapshot-usage.js [output-dir]');
console.error('Or: node snapshot-usage.js [output-dir] < sessions.json');
process.exit(1);
}
// Read JSON from stdin
for await (const chunk of process.stdin) {
input += chunk;
}
const data = JSON.parse(input);
const sessions = data.sessions || [];
// Initialize snapshot structure
const snapshot = {
date: getDateString(),
timestamp: getTimestamp(),
sessions: {},
summary: {
totalTokens: 0,
byModel: {}
},
estimatedCost: {}
};
// Process each session and aggregate data
for (const session of sessions) {
const key = session.key;
const model = session.model || 'unknown';
const tokens = session.totalTokens || 0;
snapshot.sessions[key] = {
model,
totalTokens: tokens,
channel: session.channel || 'unknown'
};
snapshot.summary.totalTokens += tokens;
snapshot.summary.byModel[model] = (snapshot.summary.byModel[model] || 0) + tokens;
}
// Calculate estimated costs per model
let totalCost = 0;
for (const [model, tokens] of Object.entries(snapshot.summary.byModel)) {
const cost = estimateCost(tokens, model);
snapshot.estimatedCost[model] = {
tokens,
estimatedUSD: Math.round(cost * 100) / 100
};
totalCost += cost;
}
snapshot.estimatedCost.totalUSD = Math.round(totalCost * 100) / 100;
// Determine output path
const outputDir = process.argv[2] || path.join(process.env.HOME, 'clawd/memory/usage');
const outputFile = path.join(outputDir, `${snapshot.date}.json`);
// Ensure output directory exists
fs.mkdirSync(outputDir, { recursive: true });
// Write snapshot to file
fs.writeFileSync(outputFile, JSON.stringify(snapshot, null, 2));
// Output result summary
console.log(JSON.stringify({
status: 'ok',
file: outputFile,
summary: snapshot.summary,
estimatedCost: snapshot.estimatedCost
}, null, 2));
}
main().catch(err => {
console.error('Error:', err.message);
process.exit(1);
});