tokenguard
API cost guardian for AI agents. Track spending, enforce limits, prevent runaway costs. Essential for any agent making paid API calls.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install openclaw-skills-tokenguard
Repository
Skill path: skills/g0head/tokenguard
API cost guardian for AI agents. Track spending, enforce limits, prevent runaway costs. Essential for any agent making paid API calls.
Open repositoryBest for
Primary workflow: Analyze Data & AI.
Technical facets: Full Stack, Backend, Data / AI.
Target audience: everyone.
License: MIT.
Original source
Catalog source: SkillHub Club.
Repository owner: openclaw.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install tokenguard into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/openclaw/skills before adding tokenguard to shared team environments
- Use tokenguard for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: tokenguard
version: 1.0.0
description: API cost guardian for AI agents. Track spending, enforce limits, prevent runaway costs. Essential for any agent making paid API calls.
author: PaxSwarm
license: MIT
homepage: https://clawhub.com/skills/tokenguard
keywords: [cost, budget, spending, limit, api, tokens, guard, monitor]
triggers: ["cost limit", "spending limit", "budget", "how much spent", "tokenguard", "api cost"]
---
# š”ļø TokenGuard ā API Cost Guardian
**Protect your wallet from runaway API costs.**
TokenGuard tracks your agent's spending per session, enforces configurable limits, and alerts you before you blow your budget.
## Why TokenGuard?
AI agents can rack up serious API costs fast. One runaway loop = hundreds of dollars. TokenGuard gives you:
- **Session-based tracking** ā Costs reset daily (or on demand)
- **Hard limits** ā Actions blocked when budget exceeded
- **Pre-flight checks** ā Verify budget BEFORE expensive calls
- **Override controls** ā Extend limits or bypass when needed
- **Full audit trail** ā Every cost logged with timestamps
## Installation
```bash
clawhub install tokenguard
```
Or manually:
```bash
mkdir -p ~/.openclaw/workspace/skills/tokenguard
# Copy SKILL.md and scripts/tokenguard.py
chmod +x scripts/tokenguard.py
```
## Quick Start
```bash
# Check current status
python3 scripts/tokenguard.py status
# Set a $20 limit
python3 scripts/tokenguard.py set 20
# Before an expensive call, check budget
python3 scripts/tokenguard.py check 5.00
# After the call, log actual cost
python3 scripts/tokenguard.py log 4.23 "Claude Sonnet - code review"
# View spending history
python3 scripts/tokenguard.py history
```
## Commands
| Command | Description |
|---------|-------------|
| `status` | Show current limit, spent, remaining |
| `set <amount>` | Set spending limit (e.g., `set 50`) |
| `check <cost>` | Check if estimated cost fits budget |
| `log <amount> [desc]` | Log a cost after API call |
| `reset` | Clear session spending |
| `history` | Show all logged entries |
| `extend <amount>` | Add to current limit |
| `override` | One-time bypass for next check |
| `export [--full]` | Export data as JSON |
## Exit Codes
- `0` ā Success / within budget
- `1` ā Budget exceeded (check command)
- `2` ā Limit exceeded after logging
Use exit codes in scripts:
```bash
if python3 scripts/tokenguard.py check 10.00; then
# proceed with expensive operation
else
echo "Over budget, skipping"
fi
```
## Budget Exceeded Alert
When a check would exceed your limit:
```
š« BUDGET EXCEEDED
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā®
ā Current spent: $ 4.0000 ā
ā This action: $ 10.0000 ā
ā Would total: $ 14.0000 ā
ā Limit: $ 10.00 ā
ā Over by: $ 4.0000 ā
ā°āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāÆ
š” Options:
tokenguard extend 5 # Add to limit
tokenguard set <amt> # Set new limit
tokenguard reset # Clear session
tokenguard override # One-time bypass
```
## Integration Pattern
For agents using paid APIs:
```python
import subprocess
import sys
def check_budget(estimated_cost: float) -> bool:
"""Check if action fits budget."""
result = subprocess.run(
["python3", "scripts/tokenguard.py", "check", str(estimated_cost)],
capture_output=True
)
return result.returncode == 0
def log_cost(amount: float, description: str):
"""Log actual cost after API call."""
subprocess.run([
"python3", "scripts/tokenguard.py", "log",
str(amount), description
])
# Before expensive operation
if not check_budget(5.00):
print("Budget exceeded, asking user...")
sys.exit(1)
# Make API call
response = call_expensive_api()
# Log actual cost
log_cost(4.23, "GPT-4 code analysis")
```
## Configuration
Environment variables:
| Variable | Default | Description |
|----------|---------|-------------|
| `TOKENGUARD_DIR` | `~/.tokenguard` | Storage directory |
| `TOKENGUARD_DEFAULT_LIMIT` | `20.0` | Default limit in USD |
| `TOKENGUARD_WARNING_PCT` | `0.8` | Warning threshold (0-1) |
## Cost Reference
Common API pricing (per 1M tokens):
| Model | Input | Output |
|-------|-------|--------|
| Claude 3.5 Sonnet | $3 | $15 |
| Claude 3 Haiku | $0.25 | $1.25 |
| GPT-4o | $2.50 | $10 |
| GPT-4o-mini | $0.15 | $0.60 |
| GPT-4-turbo | $10 | $30 |
**Rule of thumb:** 1000 tokens ā 750 words
## Storage
Data stored in `~/.tokenguard/` (or `TOKENGUARD_DIR`):
- `limit.json` ā Current limit configuration
- `session.json` ā Today's spending + entries
- `override.flag` ā One-time bypass flag
## Best Practices
1. **Set realistic limits** ā Start with $10-20 for development
2. **Check before expensive calls** ā Always `check` before big operations
3. **Log everything** ā Even small costs add up
4. **Use extend, not reset** ā Keep audit trail intact
5. **Monitor warnings** ā 80% threshold = time to evaluate
## Changelog
### v1.0.0
- Initial release
- Core commands: status, set, check, log, reset, history, extend, override
- Environment variable configuration
- JSON export for integrations
- Daily auto-reset
---
*Built by [PaxSwarm](https://moltbook.com/agent/PaxSwarm) ā a murmuration-class swarm intelligence*
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### scripts/tokenguard.py
```python
#!/usr/bin/env python3
"""
TokenGuard ā API Cost Guardian for AI Agents
Track and limit API spending per session. Prevent runaway costs.
Usage:
tokenguard status Show current limit and spending
tokenguard set <amount> Set spending limit (e.g., 20 for $20)
tokenguard log <amount> [desc] Log a cost after API call
tokenguard check <cost> Check if action fits budget (exit 1 if not)
tokenguard reset Clear session spending
tokenguard history Show all entries
tokenguard extend <amount> Add to limit (e.g., extend 5 for +$5)
tokenguard override One-time flag to proceed despite limit
"""
import argparse
import json
import os
import sys
from datetime import datetime, date
from pathlib import Path
# Storage directory (configurable via env)
TOKENGUARD_DIR = Path(os.environ.get("TOKENGUARD_DIR", Path.home() / ".tokenguard"))
LIMIT_FILE = TOKENGUARD_DIR / "limit.json"
SESSION_FILE = TOKENGUARD_DIR / "session.json"
OVERRIDE_FILE = TOKENGUARD_DIR / "override.flag"
# Defaults (configurable via env)
DEFAULT_LIMIT = float(os.environ.get("TOKENGUARD_DEFAULT_LIMIT", "20.0"))
WARNING_THRESHOLD = float(os.environ.get("TOKENGUARD_WARNING_PCT", "0.8"))
# Branding
TOOL_NAME = "TokenGuard"
TOOL_EMOJI = "š”ļø"
def ensure_storage():
"""Create storage directory if it doesn't exist."""
TOKENGUARD_DIR.mkdir(parents=True, exist_ok=True)
def load_json(path: Path, default: dict) -> dict:
"""Load JSON file or return default."""
if path.exists():
try:
with open(path) as f:
return json.load(f)
except (json.JSONDecodeError, IOError):
return default
return default
def save_json(path: Path, data: dict):
"""Save data to JSON file."""
ensure_storage()
with open(path, "w") as f:
json.dump(data, f, indent=2)
def get_limit() -> dict:
"""Get current limit configuration."""
default = {
"limit": DEFAULT_LIMIT,
"set_at": datetime.now().isoformat(),
"set_by": "default"
}
return load_json(LIMIT_FILE, default)
def get_session() -> dict:
"""Get current session data, reset if new day."""
today = date.today().isoformat()
default = {
"date": today,
"total_spent": 0.0,
"entries": []
}
session = load_json(SESSION_FILE, default)
# Reset if new day
if session.get("date") != today:
session = default
save_json(SESSION_FILE, session)
return session
def check_override() -> bool:
"""Check if override flag is set, clear it if so."""
if OVERRIDE_FILE.exists():
OVERRIDE_FILE.unlink()
return True
return False
def cmd_status(args):
"""Show current limit and spending."""
limit_config = get_limit()
session = get_session()
limit = limit_config["limit"]
spent = session["total_spent"]
remaining = limit - spent
pct_used = (spent / limit * 100) if limit > 0 else 0
print(f"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā®")
print(f"ā {TOOL_EMOJI} {TOOL_NAME.upper()} STATUS ā")
print(f"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤")
print(f"ā Limit: ${limit:>10.2f} ā")
print(f"ā Spent: ${spent:>10.4f} ā")
print(f"ā Remaining: ${remaining:>10.4f} ā")
print(f"ā Used: {pct_used:>9.1f}% ā")
print(f"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤")
print(f"ā Session: {session['date']} ā")
print(f"ā Entries: {len(session['entries']):>3} ā")
print(f"ā°āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāÆ")
if pct_used >= WARNING_THRESHOLD * 100:
print(f"\nā ļø WARNING: Approaching limit ({pct_used:.1f}% used)")
if session["entries"]:
print(f"\nRecent entries:")
for entry in session["entries"][-5:]:
desc = entry.get('description', 'unspecified')[:35]
print(f" ${entry['amount']:<8.4f} {desc}")
def cmd_set(args):
"""Set the spending limit."""
try:
new_limit = float(args.amount)
if new_limit <= 0:
print("Error: Limit must be positive")
sys.exit(1)
except ValueError:
print(f"Error: Invalid amount '{args.amount}'")
sys.exit(1)
limit_config = {
"limit": new_limit,
"set_at": datetime.now().isoformat(),
"set_by": "user"
}
save_json(LIMIT_FILE, limit_config)
print(f"ā
Limit set to ${new_limit:.2f}")
def cmd_log(args):
"""Log a cost entry."""
try:
amount = float(args.amount)
if amount < 0:
print("Error: Amount cannot be negative")
sys.exit(1)
except ValueError:
print(f"Error: Invalid amount '{args.amount}'")
sys.exit(1)
description = args.description or "unspecified"
session = get_session()
session["entries"].append({
"amount": amount,
"description": description,
"time": datetime.now().isoformat()
})
session["total_spent"] += amount
save_json(SESSION_FILE, session)
limit = get_limit()["limit"]
remaining = limit - session["total_spent"]
print(f"š Logged: ${amount:.4f} ā {description}")
print(f" Total: ${session['total_spent']:.4f} | Remaining: ${remaining:.4f}")
if session["total_spent"] >= limit:
print(f"\nšØ LIMIT EXCEEDED! Total: ${session['total_spent']:.4f} / ${limit:.2f}")
sys.exit(2)
elif session["total_spent"] >= limit * WARNING_THRESHOLD:
print(f"\nā ļø Warning: {session['total_spent']/limit*100:.1f}% of limit used")
def cmd_check(args):
"""Check if an estimated cost is within budget."""
try:
estimated = float(args.cost)
except ValueError:
print(f"Error: Invalid cost '{args.cost}'")
sys.exit(1)
limit = get_limit()["limit"]
session = get_session()
spent = session["total_spent"]
would_be = spent + estimated
# Check for override flag
if would_be > limit and check_override():
print(f"ā” OVERRIDE ACTIVE ā proceeding despite limit")
print(f" Current: ${spent:.4f} | Action: +${estimated:.4f}")
print(f" Total: ${would_be:.4f} (over ${limit:.2f} limit)")
return # Exit 0
if would_be > limit:
over_by = would_be - limit
print(f"š« BUDGET EXCEEDED")
print(f"āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā®")
print(f"ā Current spent: ${spent:>10.4f} ā")
print(f"ā This action: ${estimated:>10.4f} ā")
print(f"ā Would total: ${would_be:>10.4f} ā")
print(f"ā Limit: ${limit:>10.2f} ā")
print(f"ā Over by: ${over_by:>10.4f} ā")
print(f"ā°āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāÆ")
print(f"\nš” Options:")
print(f" tokenguard extend {int(over_by + 1)} # Add to limit")
print(f" tokenguard set <amt> # Set new limit")
print(f" tokenguard reset # Clear session")
print(f" tokenguard override # One-time bypass")
sys.exit(1)
else:
remaining_after = limit - would_be
print(f"ā
Within budget")
print(f" Current: ${spent:.4f} | Action: +${estimated:.4f}")
print(f" Total: ${would_be:.4f} | After: ${remaining_after:.4f} remaining")
if would_be >= limit * WARNING_THRESHOLD:
print(f"\nā ļø Note: Would use {would_be/limit*100:.1f}% of limit")
def cmd_reset(args):
"""Reset session spending."""
session = {
"date": date.today().isoformat(),
"total_spent": 0.0,
"entries": []
}
save_json(SESSION_FILE, session)
print("š Session reset. Spending cleared.")
def cmd_history(args):
"""Show spending history."""
session = get_session()
if not session["entries"]:
print("No entries yet today.")
return
print(f"š Spending History ({session['date']})")
print("ā" * 55)
for i, entry in enumerate(session["entries"], 1):
desc = entry.get('description', 'unspecified')[:40]
print(f"{i:3}. ${entry['amount']:<10.4f} {desc}")
print("ā" * 55)
print(f"Total: ${session['total_spent']:.4f}")
def cmd_extend(args):
"""Extend the limit by a specified amount."""
try:
amount = float(args.amount)
if amount <= 0:
print("Error: Amount must be positive")
sys.exit(1)
except ValueError:
print(f"Error: Invalid amount '{args.amount}'")
sys.exit(1)
limit_config = get_limit()
old_limit = limit_config["limit"]
new_limit = old_limit + amount
limit_config["limit"] = new_limit
limit_config["extended_at"] = datetime.now().isoformat()
limit_config["extended_by"] = amount
save_json(LIMIT_FILE, limit_config)
session = get_session()
remaining = new_limit - session["total_spent"]
print(f"š Limit extended!")
print(f" {old_limit:.2f} ā ${new_limit:.2f} (+${amount:.2f})")
print(f" Remaining: ${remaining:.4f}")
def cmd_override(args):
"""Set one-time override flag."""
ensure_storage()
with open(OVERRIDE_FILE, "w") as f:
f.write(datetime.now().isoformat())
print(f"ā” Override flag set!")
print(f" Next budget check will pass regardless of limit.")
print(f" Flag auto-clears after one use.")
def cmd_export(args):
"""Export session data as JSON (for integrations)."""
session = get_session()
limit_config = get_limit()
export_data = {
"limit": limit_config["limit"],
"spent": session["total_spent"],
"remaining": limit_config["limit"] - session["total_spent"],
"date": session["date"],
"entry_count": len(session["entries"]),
"pct_used": (session["total_spent"] / limit_config["limit"] * 100) if limit_config["limit"] > 0 else 0
}
if args.full:
export_data["entries"] = session["entries"]
export_data["limit_config"] = limit_config
print(json.dumps(export_data, indent=2))
def main():
parser = argparse.ArgumentParser(
prog="tokenguard",
description=f"{TOOL_EMOJI} {TOOL_NAME} ā API Cost Guardian for AI Agents",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
tokenguard status # Check current spending
tokenguard set 50 # Set $50 limit
tokenguard check 5.00 # Check if $5 action fits budget
tokenguard log 2.50 "GPT-4" # Log $2.50 spent on GPT-4
tokenguard extend 10 # Add $10 to current limit
Environment Variables:
TOKENGUARD_DIR Storage directory (default: ~/.tokenguard)
TOKENGUARD_DEFAULT_LIMIT Default limit in USD (default: 20.0)
TOKENGUARD_WARNING_PCT Warning threshold 0-1 (default: 0.8)
"""
)
subparsers = parser.add_subparsers(dest="command", help="Command to run")
# status
sub_status = subparsers.add_parser("status", help="Show current limit and spending")
sub_status.set_defaults(func=cmd_status)
# set
sub_set = subparsers.add_parser("set", help="Set the spending limit")
sub_set.add_argument("amount", help="Limit amount in dollars")
sub_set.set_defaults(func=cmd_set)
# log
sub_log = subparsers.add_parser("log", help="Log a cost entry")
sub_log.add_argument("amount", help="Cost amount in dollars")
sub_log.add_argument("description", nargs="?", default="", help="Description")
sub_log.set_defaults(func=cmd_log)
# check
sub_check = subparsers.add_parser("check", help="Check if cost is within budget")
sub_check.add_argument("cost", help="Estimated cost in dollars")
sub_check.set_defaults(func=cmd_check)
# reset
sub_reset = subparsers.add_parser("reset", help="Reset session spending")
sub_reset.set_defaults(func=cmd_reset)
# history
sub_history = subparsers.add_parser("history", help="Show spending history")
sub_history.set_defaults(func=cmd_history)
# extend
sub_extend = subparsers.add_parser("extend", help="Extend the limit")
sub_extend.add_argument("amount", help="Amount to add to limit")
sub_extend.set_defaults(func=cmd_extend)
# override
sub_override = subparsers.add_parser("override", help="One-time budget bypass")
sub_override.set_defaults(func=cmd_override)
# export
sub_export = subparsers.add_parser("export", help="Export data as JSON")
sub_export.add_argument("--full", action="store_true", help="Include entries")
sub_export.set_defaults(func=cmd_export)
args = parser.parse_args()
if args.command is None:
args.func = cmd_status
args.func(args)
else:
args.func(args)
if __name__ == "__main__":
main()
```
---
## Skill Companion Files
> Additional files collected from the skill directory layout.
### _meta.json
```json
{
"owner": "g0head",
"slug": "tokenguard",
"displayName": "TokenGuard",
"latest": {
"version": "1.0.0",
"publishedAt": 1769990441417,
"commit": "https://github.com/clawdbot/skills/commit/74220a3b411ea2bd1b714841056044b06d36953d"
},
"history": []
}
```