
Token Guard
- 31 installs
- 82 repo stars
- Updated August 2, 2026
- aaaaqwq/claude-code-skills
token-guard is a Claude Code skill that monitors AI agent token usage, sets daily budgets, and auto-downgrades the model when a spending limit is exceeded.
About
token-guard monitors an AI agent's token usage and costs, sets daily budgets, and auto-downgrades the model when a hard limit is hit. A developer running an agent around the clock uses it to cap spend and avoid burning Opus-level tokens overnight. It ships a shell script for status, budget-setting, cost estimation, and usage history.
- Monitors AI agent token usage and estimates cost from model pricing
- Sets daily budgets with threshold alerts and hard-limit auto-downgrade
- Recommends model routing (Opus/Sonnet/Haiku tiers) to cut spend
Token Guard by the numbers
- 31 all-time installs (skills.sh)
- Ranked #9,100 of 16,556 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
token-guard capabilities & compatibility
Free; requires bash 4+, python3, and curl
- Capabilities
- cost monitoring · budget enforcement · model routing · token optimization
- Use cases
- token optimization · orchestration
- Pricing
- Free
What token-guard says it does
Monitor and control OpenClaw token usage and costs. Set daily budgets, track spending, auto-downgrade models when limits hit. Stop burning money while you sleep.
Hard limits with auto-model-downgrade
npx skills add https://github.com/aaaaqwq/claude-code-skills --skill token-guardAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 31 |
|---|---|
| repo stars | ★ 82 |
| Last updated | August 2, 2026 |
| Repository | aaaaqwq/claude-code-skills ↗ |
What it does
Track an AI agent's token spend, enforce a daily budget, and auto-downgrade the model when the limit is hit.
Who is it for?
Capping and monitoring token spend on a long-running or 24/7 AI agent
Skip if: Tasks unrelated to token cost tracking or model routing
When should I use this skill?
You need to track agent token spend or enforce a daily budget with model downgrade
What you get
Token usage tracked against a daily budget with automatic model downgrade when the limit is hit.
- Usage/cost status and history
- An enforced daily budget with model-downgrade rule
By the numbers
- Default 80% warning threshold
- Model cost table across 6 models
Files
Token Guard 💰
Stop burning money while you sleep.
Your AI agent runs 24/7. Opus costs $75/M output tokens. One overnight coding session can burn $50+ before you wake up. Token Guard watches your spend and acts before your wallet notices.
The Problem
Real costs from real users:
| Scenario | Model | Cost |
|---|---|---|
| "Let the agent run overnight" | Opus | $50-100 |
| "Register an email + X account" | Opus | $55 (one task!) |
| First week exploring | Opus | $100+ |
| Daily heartbeat checks | Opus | $2-5/day for nothing |
Most users don't realize they're burning Opus-level tokens on tasks that Haiku could handle.
What Token Guard Does
Monitor
- Track token usage per day/model
- Estimate costs from model pricing
- Show usage history and trends
Budget
- Set daily spending limits
- Warning alerts at configurable threshold (default 80%)
- Hard limits with auto-model-downgrade
Optimize
- Model cost comparison at a glance
- Routing recommendations (Opus for reasoning, Haiku for background)
- Per-task cost estimation before running
Quick Start
# See current usage and model costs
bash scripts/token-guard.sh status
# Set a $10/day budget with warnings
bash scripts/token-guard.sh set-budget 10
# Set a hard limit: auto-downgrade to Haiku when exceeded
bash scripts/token-guard.sh set-budget 10 80 true claude-haiku-3-5
# Estimate cost before running a task
bash scripts/token-guard.sh estimate claude-opus-4 50000 10000 10
# Check usage history
bash scripts/token-guard.sh history 7Model Cost Comparison
| Model | Input $/1M | Output $/1M | Relative |
|---|---|---|---|
| Claude Opus 4 | $15.00 | $75.00 | 100x |
| Claude Sonnet 4 | $3.00 | $15.00 | 20x |
| Claude Haiku 3.5 | $0.80 | $4.00 | 5x |
| GPT-4o | $2.50 | $10.00 | 13x |
| Gemini Flash | $0.075 | $0.30 | 1x |
| DeepSeek | $0.27 | $1.10 | 1.5x |
Recommended Routing
Tier 1 (Reasoning/Creative): claude-opus-4 → Use sparingly
Tier 2 (Daily work): claude-sonnet-4 → Primary model
Tier 3 (Background/Subagent): claude-haiku-3-5 → Subagent model
Tier 4 (Bulk/Heartbeat): gemini-2.0-flash → Heartbeat/cronSavings: Routing background tasks to Haiku instead of Opus = 95% cost reduction on those tasks.
For AI Agents
Add to your heartbeat or cron:
bash /path/to/token-guard/scripts/token-guard.sh monitorWhen budget is exceeded with hard limit enabled, the script automatically downgrades the primary model.
Install
clawdhub install token-guard
# or: git clone https://github.com/jzOcb/token-guardRequirements
bash4+python3curl
Related
- config-guard — Config validation and auto-rollback
- upgrade-guard — Safe upgrades with snapshot and auto-rollback
- agent-guardrails — Code-level enforcement for AI agents
MIT License
Copyright (c) 2026 jzOcb
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Token Guard 💰
🇺🇸 English
  
别让 AI 睡觉的时候烧你的钱。
Agent 7×24 跑着,Opus $75/百万 token。算算账吧。
有人一个任务花了 $55(注册邮箱+X账号)。有人第一周探索就烧了 $100+。Token Guard 帮你盯着账单。
快速开始
# 当前用量 + 成本
bash scripts/token-guard.sh status
# 设置每日 $10 预算
bash scripts/token-guard.sh set-budget 10
# 硬限制:超预算自动降级到 Haiku
bash scripts/token-guard.sh set-budget 10 80 true claude-haiku-3-5
# 跑之前先估算
bash scripts/token-guard.sh estimate claude-opus-4 50000 10000
# 历史用量
bash scripts/token-guard.sh history功能
- 预算预警 — 80% 提醒,100% 报警
- 自动降级 — 超预算自动切便宜模型
- 成本预估 — 跑贵任务前先算一算
- 用量历史 — 按天按模型看明细
- 模型对比 — 一眼看出哪个贵哪个便宜
真实省钱效果
| 改什么 | 月省多少 |
|---|---|
| sub-agent 改用 Haiku | ~70% |
| heartbeat 改用 Flash | ~95% |
| 设每日预算 + 自动降级 | 防止账单爆炸 |
| heartbeat 调到 55 分钟(卡缓存窗口) | ~30% |
依赖
bash4+,python3,curl
🛡️ AI Agent 安全套件
| 工具 | 防止什么 |
|---|---|
| [agent-guardrails](https://github.com/jzOcb/agent-guardrails) | AI 重写已验证代码、泄露密钥、绕过标准 |
| [config-guard](https://github.com/jzOcb/config-guard) | AI 写错配置、搞崩网关 |
| [upgrade-guard](https://github.com/jzOcb/upgrade-guard) | 版本升级破坏依赖、无法回滚 |
| [token-guard](https://github.com/jzOcb/token-guard) | Token 费用失控、预算超支 |
| [process-guardian](https://github.com/jzOcb/process-guardian) | 后台进程悄悄死掉、无自动恢复 |
📖 完整故事: 我审计了自己的 AI agent 系统,发现漏洞百出
许可
MIT
Token Guard 💰
🇨🇳 中文文档
  
Stop burning money while you sleep.
Your agent runs 24/7. Opus costs $75/M tokens. Do the math.
One user spent $55 on a single task (registering an email + X account). Another burned $100 in a week just exploring. Token Guard watches your spend so you don't have to.
Quick Start
# Current usage + costs
bash scripts/token-guard.sh status
# Set $10/day budget
bash scripts/token-guard.sh set-budget 10
# Hard limit: auto-downgrade to Haiku when exceeded
bash scripts/token-guard.sh set-budget 10 80 true claude-haiku-3-5
# Estimate before running
bash scripts/token-guard.sh estimate claude-opus-4 50000 10000
# Usage history
bash scripts/token-guard.sh historyFeatures
- Budget alerts — warning at 80%, critical at 100%
- Auto-downgrade — hit budget → auto-switch to cheaper model
- Cost estimation — estimate before running expensive tasks
- Usage history — daily breakdown by model
- Model comparison — see real cost differences at a glance
The Real Savings
| What you change | Monthly savings |
|---|---|
| Route subagents to Haiku | ~70% |
| Route heartbeat to Flash | ~95% |
| Set daily budget + downgrade | prevents blowouts |
| Cache-aware heartbeat (55min) | ~30% |
Requirements
bash4+,python3,curl
🛡️ Part of the AI Agent Security Suite
| Tool | What It Prevents |
|---|---|
| [agent-guardrails](https://github.com/jzOcb/agent-guardrails) | AI rewrites validated code, leaks secrets, bypasses standards |
| [config-guard](https://github.com/jzOcb/config-guard) | AI writes malformed config, crashes gateway |
| [upgrade-guard](https://github.com/jzOcb/upgrade-guard) | Version upgrades break dependencies, no rollback |
| [token-guard](https://github.com/jzOcb/token-guard) | Runaway token costs, budget overruns |
| [process-guardian](https://github.com/jzOcb/process-guardian) | Background processes die silently, no auto-recovery |
📖 Read the full story: I audited my own AI agent system and found it full of holes
License
MIT
🛡️ Part of the OpenClaw Security Suite
| Guard | Purpose | Protects Against |
|---|---|---|
| [agent-guardrails](https://github.com/jzOcb/agent-guardrails) | Pre-commit hooks + secret detection | Code leaks, unsafe commits |
| [config-guard](https://github.com/jzOcb/config-guard) | Config validation + auto-rollback | Gateway crashes from bad config |
| [upgrade-guard](https://github.com/jzOcb/upgrade-guard) | Safe upgrades + watchdog | Update failures, cascading breaks |
| [token-guard](https://github.com/jzOcb/token-guard) | Usage monitoring + cost alerts | Budget overruns, runaway costs |
📚 Full writeup: 4-Layer Defense System for AI Agents
#!/usr/bin/env bash
# token-guard.sh — Monitor and control OpenClaw token usage & costs
# Stop burning money while you sleep.
#
# Usage:
# token-guard.sh status # Current usage summary
# token-guard.sh monitor # Check usage vs budget (for cron)
# token-guard.sh set-budget <USD> # Set daily budget
# token-guard.sh set-model-rules # Configure auto model switching
# token-guard.sh history [days] # Usage history
# token-guard.sh alert # Check if budget exceeded
set -euo pipefail
# --- Config ---
CONFIG_FILE="${CONFIG_FILE:-$HOME/.clawdbot/clawdbot.json}"
[[ ! -f "$CONFIG_FILE" ]] && CONFIG_FILE="$HOME/.openclaw/openclaw.json"
STATE_DIR="${STATE_DIR:-$HOME/.openclaw/token-guard}"
BUDGET_FILE="$STATE_DIR/budget.json"
USAGE_LOG="$STATE_DIR/usage-log.jsonl"
GATEWAY_PORT="${GATEWAY_PORT:-18789}"
GATEWAY_URL="http://127.0.0.1:${GATEWAY_PORT}"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
info() { echo -e "${BLUE}ℹ${NC} $*"; }
ok() { echo -e "${GREEN}✔${NC} $*"; }
warn() { echo -e "${YELLOW}⚠${NC} $*"; }
fail() { echo -e "${RED}✖${NC} $*"; }
cost() { echo -e "${CYAN}💰${NC} $*"; }
mkdir -p "$STATE_DIR"
# ============================================================
# Model pricing database (USD per 1M tokens)
# ============================================================
get_model_cost() {
local model="$1"
# Returns "input_cost output_cost" per 1M tokens
case "$model" in
*opus*4*|*claude-opus-4*) echo "15.00 75.00" ;;
*opus*) echo "15.00 75.00" ;;
*sonnet*4*|*claude-sonnet-4*) echo "3.00 15.00" ;;
*sonnet*3.5*|*sonnet-3-5*) echo "3.00 15.00" ;;
*haiku*3.5*|*haiku-3-5*) echo "0.80 4.00" ;;
*haiku*) echo "0.25 1.25" ;;
*gpt-4o*) echo "2.50 10.00" ;;
*gpt-4-turbo*) echo "10.00 30.00" ;;
*gpt-4*) echo "30.00 60.00" ;;
*gpt-3.5*|*gpt-35*) echo "0.50 1.50" ;;
*o1-mini*) echo "3.00 12.00" ;;
*o1*) echo "15.00 60.00" ;;
*gemini*pro*) echo "1.25 5.00" ;;
*gemini*flash*) echo "0.075 0.30" ;;
*deepseek*) echo "0.27 1.10" ;;
*kimi*|*moonshot*) echo "0.00 0.00" ;; # Free tier
*) echo "3.00 15.00" ;; # Default to Sonnet-level
esac
}
# ============================================================
# STATUS — current usage snapshot
# ============================================================
cmd_status() {
echo "━━━ Token Guard Status ━━━"
echo ""
# Current model
local model
model=$(python3 -c "
import json
with open('$CONFIG_FILE') as f:
cfg = json.load(f)
m = cfg.get('agents', {}).get('primaryModel', cfg.get('primaryModel', 'unknown'))
print(m)
" 2>/dev/null || echo "unknown")
info "Current model: $model"
local costs
costs=$(get_model_cost "$model")
local input_cost output_cost
input_cost=$(echo "$costs" | cut -d' ' -f1)
output_cost=$(echo "$costs" | cut -d' ' -f2)
info "Pricing: \$${input_cost}/1M input, \$${output_cost}/1M output"
# Budget
if [[ -f "$BUDGET_FILE" ]]; then
local daily_budget
daily_budget=$(python3 -c "import json; print(json.load(open('$BUDGET_FILE')).get('daily_usd', 'not set'))" 2>/dev/null)
cost "Daily budget: \$${daily_budget}"
else
warn "No budget set (use 'token-guard.sh set-budget <USD>')"
fi
# Today's usage from log
local today
today=$(date -u +%Y-%m-%d)
if [[ -f "$USAGE_LOG" ]]; then
local today_stats
today_stats=$(python3 -c "
import json
total_input = 0
total_output = 0
total_cost = 0.0
count = 0
with open('$USAGE_LOG') as f:
for line in f:
try:
d = json.loads(line.strip())
if d.get('date', '').startswith('$today'):
total_input += d.get('input_tokens', 0)
total_output += d.get('output_tokens', 0)
total_cost += d.get('estimated_cost', 0.0)
count += 1
except:
pass
print(f'{total_input} {total_output} {total_cost:.4f} {count}')
" 2>/dev/null || echo "0 0 0.0000 0")
local t_in t_out t_cost t_count
t_in=$(echo "$today_stats" | cut -d' ' -f1)
t_out=$(echo "$today_stats" | cut -d' ' -f2)
t_cost=$(echo "$today_stats" | cut -d' ' -f3)
t_count=$(echo "$today_stats" | cut -d' ' -f4)
echo ""
info "Today ($today):"
info " Requests: $t_count"
info " Input tokens: $t_in"
info " Output tokens: $t_out"
cost " Estimated cost: \$$t_cost"
# Budget check
if [[ -f "$BUDGET_FILE" ]]; then
local daily_budget
daily_budget=$(python3 -c "import json; print(json.load(open('$BUDGET_FILE')).get('daily_usd', 999))" 2>/dev/null)
local pct
pct=$(python3 -c "print(f'{($t_cost / $daily_budget * 100):.1f}')" 2>/dev/null || echo "0")
if python3 -c "exit(0 if $t_cost > $daily_budget else 1)" 2>/dev/null; then
fail " ❌ OVER BUDGET! ($pct% of \$$daily_budget)"
elif python3 -c "exit(0 if $t_cost > $daily_budget * 0.8 else 1)" 2>/dev/null; then
warn " ⚠️ $pct% of daily budget used"
else
ok " ✅ $pct% of daily budget"
fi
fi
else
info "No usage data yet"
fi
# Model routing config
echo ""
info "Model routing:"
python3 -c "
import json
with open('$CONFIG_FILE') as f:
cfg = json.load(f)
primary = cfg.get('agents', {}).get('primaryModel', 'not set')
# Check for subagent model
sub_model = cfg.get('agents', {}).get('defaults', {}).get('subagents', {}).get('model', 'same as primary')
sub_thinking = cfg.get('agents', {}).get('defaults', {}).get('subagents', {}).get('thinking', 'not set')
print(f' Primary: {primary}')
print(f' Subagent: {sub_model}')
print(f' Subagent thinking: {sub_thinking}')
" 2>/dev/null || echo " Could not read config"
# Cost comparison
echo ""
info "💡 Cost comparison (per 1M output tokens):"
echo " Opus 4: \$75.00 ██████████████████████████████"
echo " Sonnet 4: \$15.00 ██████"
echo " Haiku 3.5: \$4.00 ██"
echo " Gemini Flash:\$0.30 ▏"
echo " DeepSeek: \$1.10 ▍"
}
# ============================================================
# LOG — record usage data point
# ============================================================
cmd_log() {
local input_tokens="${1:-0}"
local output_tokens="${2:-0}"
local model="${3:-unknown}"
local source="${4:-manual}"
local costs
costs=$(get_model_cost "$model")
local input_cost output_cost
input_cost=$(echo "$costs" | cut -d' ' -f1)
output_cost=$(echo "$costs" | cut -d' ' -f2)
local est_cost
est_cost=$(python3 -c "
input_c = $input_tokens / 1000000 * $input_cost
output_c = $output_tokens / 1000000 * $output_cost
print(f'{input_c + output_c:.6f}')
" 2>/dev/null)
local entry
entry=$(python3 -c "
import json
from datetime import datetime
print(json.dumps({
'date': datetime.utcnow().isoformat() + 'Z',
'model': '$model',
'input_tokens': $input_tokens,
'output_tokens': $output_tokens,
'estimated_cost': $est_cost,
'source': '$source'
}))
" 2>/dev/null)
echo "$entry" >> "$USAGE_LOG"
ok "Logged: ${input_tokens}in/${output_tokens}out on $model ≈ \$$est_cost"
}
# ============================================================
# MONITOR — check usage vs budget (for cron/heartbeat)
# ============================================================
cmd_monitor() {
if [[ ! -f "$BUDGET_FILE" ]]; then
info "No budget set. Skipping monitor."
return 0
fi
local daily_budget
daily_budget=$(python3 -c "import json; print(json.load(open('$BUDGET_FILE')).get('daily_usd', 999))" 2>/dev/null)
local today
today=$(date -u +%Y-%m-%d)
local today_cost
today_cost=$(python3 -c "
import json
total = 0.0
with open('$USAGE_LOG') as f:
for line in f:
try:
d = json.loads(line.strip())
if d.get('date', '').startswith('$today'):
total += d.get('estimated_cost', 0.0)
except:
pass
print(f'{total:.4f}')
" 2>/dev/null || echo "0")
local pct
pct=$(python3 -c "print(f'{(float(\"$today_cost\") / $daily_budget * 100):.0f}')" 2>/dev/null || echo "0")
# Check thresholds
local action
action=$(python3 -c "
import json
budget = json.load(open('$BUDGET_FILE'))
cost = float('$today_cost')
daily = budget.get('daily_usd', 999)
warn_pct = budget.get('warn_pct', 80)
hard_limit = budget.get('hard_limit', False)
downgrade_model = budget.get('downgrade_model', '')
if cost >= daily:
if hard_limit and downgrade_model:
print(f'DOWNGRADE {downgrade_model}')
else:
print('ALERT_OVER')
elif cost >= daily * warn_pct / 100:
print('ALERT_WARN')
else:
print('OK')
" 2>/dev/null || echo "OK")
case "$action" in
OK)
ok "Budget OK: \$$today_cost / \$$daily_budget ($pct%)"
;;
ALERT_WARN)
warn "⚠️ Budget warning: \$$today_cost / \$$daily_budget ($pct%)"
;;
ALERT_OVER)
fail "❌ OVER BUDGET: \$$today_cost / \$$daily_budget ($pct%)"
;;
DOWNGRADE*)
local new_model
new_model=$(echo "$action" | cut -d' ' -f2)
fail "❌ OVER BUDGET: \$$today_cost / \$$daily_budget ($pct%)"
warn "⚡ Auto-downgrading to $new_model"
_switch_model "$new_model"
;;
esac
}
# ============================================================
# SET-BUDGET
# ============================================================
cmd_set_budget() {
local daily_usd="${1:?Usage: set-budget <daily_usd> [warn_pct] [hard_limit] [downgrade_model]}"
local warn_pct="${2:-80}"
local hard_limit="${3:-false}"
local downgrade_model="${4:-}"
python3 -c "
import json
budget = {
'daily_usd': float('$daily_usd'),
'warn_pct': int('$warn_pct'),
'hard_limit': '$hard_limit' == 'true',
'downgrade_model': '$downgrade_model',
'set_at': '$(date -u +%Y-%m-%dT%H:%M:%SZ)'
}
with open('$BUDGET_FILE', 'w') as f:
json.dump(budget, f, indent=2)
" 2>/dev/null
ok "Budget set:"
cost " Daily: \$$daily_usd"
info " Warning at: ${warn_pct}%"
if [[ "$hard_limit" == "true" ]]; then
warn " Hard limit: ON → auto-downgrade to ${downgrade_model:-haiku}"
else
info " Hard limit: OFF (alert only)"
fi
}
# ============================================================
# SET-MODEL-RULES — configure model routing
# ============================================================
cmd_set_model_rules() {
echo "━━━ Model Routing Configuration ━━━"
echo ""
echo "Current config:"
python3 -c "
import json
with open('$CONFIG_FILE') as f:
cfg = json.load(f)
primary = cfg.get('agents', {}).get('primaryModel', 'not set')
sub = cfg.get('agents', {}).get('defaults', {}).get('subagents', {}).get('model', 'same as primary')
print(f' Primary model: {primary}')
print(f' Subagent model: {sub}')
" 2>/dev/null
echo ""
echo "Recommended routing for cost savings:"
echo ""
echo " Tier 1 (Reasoning): claude-opus-4 (\$75/M out)"
echo " Tier 2 (Daily work): claude-sonnet-4 (\$15/M out) ← primary"
echo " Tier 3 (Background): claude-haiku-3-5 (\$4/M out) ← subagents"
echo " Tier 4 (Bulk): gemini-2.0-flash (\$0.30/M) ← heartbeat"
echo ""
echo "To apply:"
echo " Primary: openclaw config set agents.primaryModel <model>"
echo " Subagent: openclaw config set agents.defaults.subagents.model <model>"
}
# ============================================================
# HISTORY — usage history
# ============================================================
cmd_history() {
local days="${1:-7}"
if [[ ! -f "$USAGE_LOG" ]]; then
info "No usage history yet"
return 0
fi
echo "━━━ Usage History (last $days days) ━━━"
echo ""
python3 -c "
import json
from datetime import datetime, timedelta
from collections import defaultdict
daily = defaultdict(lambda: {'input': 0, 'output': 0, 'cost': 0.0, 'count': 0, 'models': defaultdict(int)})
cutoff = (datetime.utcnow() - timedelta(days=$days)).strftime('%Y-%m-%d')
with open('$USAGE_LOG') as f:
for line in f:
try:
d = json.loads(line.strip())
date = d.get('date', '')[:10]
if date >= cutoff:
daily[date]['input'] += d.get('input_tokens', 0)
daily[date]['output'] += d.get('output_tokens', 0)
daily[date]['cost'] += d.get('estimated_cost', 0.0)
daily[date]['count'] += 1
daily[date]['models'][d.get('model', '?')] += 1
except:
pass
total_cost = 0
for date in sorted(daily.keys()):
d = daily[date]
total_cost += d['cost']
bar_len = min(int(d['cost'] * 10), 40)
bar = '█' * bar_len
models = ', '.join(f'{m}({c})' for m, c in sorted(d['models'].items(), key=lambda x: -x[1]))
print(f\" {date} \${d['cost']:>7.2f} {d['count']:>4} reqs {bar}\")
print(f\" {d['input']:>8} in / {d['output']:>8} out [{models}]\")
print(f\"\n Total: \${total_cost:.2f}\")
" 2>/dev/null || echo " Error reading usage log"
}
# ============================================================
# ESTIMATE — estimate cost for a task
# ============================================================
cmd_estimate() {
local model="${1:-claude-sonnet-4}"
local input_tokens="${2:-10000}"
local output_tokens="${3:-5000}"
local runs="${4:-1}"
local costs
costs=$(get_model_cost "$model")
local input_cost output_cost
input_cost=$(echo "$costs" | cut -d' ' -f1)
output_cost=$(echo "$costs" | cut -d' ' -f2)
python3 -c "
ic = $input_tokens / 1000000 * $input_cost * $runs
oc = $output_tokens / 1000000 * $output_cost * $runs
total = ic + oc
print(f'Model: $model')
print(f'Input: {$input_tokens:,} tokens × $runs runs = \${ic:.4f}')
print(f'Output: {$output_tokens:,} tokens × $runs runs = \${oc:.4f}')
print(f'Total: \${total:.4f}')
print()
# Compare with other models
for name, ip, op in [
('claude-opus-4', 15.0, 75.0),
('claude-sonnet-4', 3.0, 15.0),
('claude-haiku-3-5', 0.8, 4.0),
('gemini-flash', 0.075, 0.30),
]:
t = ($input_tokens/1e6*ip + $output_tokens/1e6*op) * $runs
marker = ' ← current' if name.replace('-','').lower() in '$model'.replace('-','').lower() else ''
print(f' {name:20s} \${t:.4f}{marker}')
" 2>/dev/null
}
# ============================================================
# Helper: switch model
# ============================================================
_switch_model() {
local new_model="$1"
warn "Switching primary model to: $new_model"
# Use gateway API to patch config
curl -sf -X POST "${GATEWAY_URL}/api/config" \
-H "Content-Type: application/json" \
-d "{\"agents\":{\"primaryModel\":\"$new_model\"}}" \
>/dev/null 2>&1 && ok "Model switched to $new_model" || fail "Failed to switch model"
}
# ============================================================
# Main
# ============================================================
case "${1:-help}" in
status) cmd_status ;;
log) cmd_log "${2:-0}" "${3:-0}" "${4:-unknown}" "${5:-manual}" ;;
monitor) cmd_monitor ;;
set-budget) cmd_set_budget "${2:-}" "${3:-80}" "${4:-false}" "${5:-}" ;;
set-model-rules) cmd_set_model_rules ;;
history) cmd_history "${2:-7}" ;;
estimate) cmd_estimate "${2:-claude-sonnet-4}" "${3:-10000}" "${4:-5000}" "${5:-1}" ;;
help|--help|-h)
echo "token-guard.sh — Monitor and control OpenClaw token usage & costs"
echo ""
echo "Commands:"
echo " status Current usage summary + budget check"
echo " monitor Check budget (for cron/heartbeat)"
echo " set-budget <USD> Set daily budget"
echo " Options: [warn_pct] [hard_limit:true/false] [downgrade_model]"
echo " set-model-rules Show model routing recommendations"
echo " history [days] Usage history (default: 7 days)"
echo " estimate <model> <in> <out> [runs] Estimate cost"
echo " log <in> <out> <model> [source] Record usage"
echo ""
echo "Examples:"
echo " token-guard.sh set-budget 10 # \$10/day, alert only"
echo " token-guard.sh set-budget 10 80 true haiku-3-5 # \$10/day, auto-downgrade at limit"
echo " token-guard.sh estimate claude-opus-4 50000 10000 10"
echo ""
echo "Environment:"
echo " GATEWAY_PORT Gateway port (default: 18789)"
;;
*)
fail "Unknown command: $1 (try 'help')"
exit 1
;;
esac