workspace/skills/token-tracker/SKILL.md
Track token consumption, enforce session budgets, and display cost for every NetClaw interaction.
npx skillsauth add automateyournetwork/netclaw token-trackerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Track and display token consumption and cost for every NetClaw interaction. Enforce per-session spending caps and tool-call depth limits to prevent runaway API costs. Serialize MCP server responses in GCF format to reduce token usage by 40-60% on tabular network data.
Without this skill, a single casual phone question can trigger unbounded agentic tool chains that silently burn $10+ in API costs. This skill ensures:
This skill uses the netclaw_tokens shared library (src/netclaw_tokens/):
| Module | Function | Purpose | |--------|----------|---------| | counter.py | count_tokens() | Count tokens via Anthropic API (fallback: len/4 estimate) | | counter.py | count_message_tokens() | Count tokens for full message arrays | | cost_calculator.py | calculate_cost() | Calculate USD cost with model-aware pricing | | cost_calculator.py | get_pricing() | Look up model pricing (with env var override) | | budget_policy.py | BudgetPolicy | Per-session budget configuration | | budget_policy.py | resolve_session_config() | Load policy from config + interface detection | | session_ledger.py | SessionLedger | Cumulative tracking + enforcement | | footer.py | format_footer() | Format mandatory token/cost footer | | gcf_serializer.py | serialize_response() | Serialize data to GCF with JSON fallback | | gcf_wrapper.py | wrap_json_response() | Convert JSON responses to GCF |
resolve_session_config(config, session_key) to get the
BudgetPolicy for this session — accounts for interface type (mobile/desktop/discord),
per-agent overrides, and environment variable overrides.SessionLedger(budget=policy) — enforcement is now active.session_ledger.new_turn() — resets tool-call counter for
this turn.session_ledger.check_budget() → returns (should_halt, reason).
should_halt is True: STOP. Return session_ledger.get_halt_message() to the
user. Do NOT execute the tool. Do NOT make another API call.session_ledger.record_tool_call() to increment the per-turn
counter.count_tokens() or read the API response usage block.calculate_cost() with the active model.session_ledger.record() with tool name, token count, cost,
and GCF savings.format_footer() — now includes budget status.session_ledger.override_budget().
tool_limit: resets the tool-call counter (free, no dollar increase).cost_cap: extends budget by override_increment_usd AND resets tools.total_cost >= session_budget_usd, no further API
calls or tool invocations are permitted until the operator explicitly continues.tool_calls_this_turn >= max_tool_calls_per_turn,
the agent pauses, presents findings so far, and asks permission to continue.openclaw.json, enforcement
activates with: $5 session cap, 20 tool calls per turn, override allowed (+$2 increments).Works out of the box with safe defaults. No configuration required.
{
"agents": {
"defaults": {
"budget": {
"sessionBudgetUsd": 5.0,
"maxToolCallsPerTurn": 20,
"contextWarningTokens": 100000,
"allowOverride": true,
"overrideIncrementUsd": 2.0
},
"interfaceDefaults": {
"openai": { "model": "anthropic/claude-haiku-4-5", "thinkingLevel": "medium" },
"n2n": { "model": "anthropic/claude-haiku-4-5", "thinkingLevel": "medium" },
"discord": { "model": "anthropic/claude-haiku-4-5", "thinkingLevel": "low" }
}
}
}
}
export NETCLAW_SESSION_BUDGET_USD=2.0 # Overrides config, takes effect next session
| Variable | Required | Description |
|----------|----------|-------------|
| ANTHROPIC_API_KEY | Yes | API key for Anthropic token counting (already used by NetClaw) |
| NETCLAW_TOKEN_PRICING_OVERRIDE | No | JSON string to override default model pricing |
| NETCLAW_SESSION_BUDGET_USD | No | Override session cost cap (default: 5.0) |
| Model | Input (per 1M) | Output (per 1M) | |-------|-----------------|------------------| | Claude Opus 4.6 | $5.00 | $25.00 | | Claude Sonnet 4.6 | $3.00 | $15.00 | | Claude Haiku 4.5 | $1.00 | $5.00 |
Prompt caching discount: 90% off cached input tokens.
from netclaw_tokens import (
count_tokens, calculate_cost, format_footer,
SessionLedger, BudgetPolicy, resolve_session_config,
)
from netclaw_tokens.gcf_serializer import serialize_response
# ── Session start ──────────────────────────────────────────────
config = load_openclaw_config() # Your config loader
session_key = "agent:main:openai:abc-123" # From gateway
policy = resolve_session_config(config, session_key)
# → BudgetPolicy(session_budget_usd=5.0, model="anthropic/claude-haiku-4-5", ...)
ledger = SessionLedger(budget=policy)
# ── Each user message ──────────────────────────────────────────
ledger.new_turn()
# ── Before each tool call ──────────────────────────────────────
should_halt, reason = ledger.check_budget()
if should_halt:
return ledger.get_halt_message() # Return to user, stop processing
ledger.record_tool_call()
# ── After model response ──────────────────────────────────────
tc = count_tokens("show BGP peers on router R1")
cost = calculate_cost(tc.input_tokens, 382, model=policy.model or "claude-sonnet-4-6")
ledger.record("pyats_show_bgp", tc, cost)
# ── Footer (every response) ──────────────────────────────────
footer = format_footer(tc, cost, session_summary=ledger.get_summary())
# Output: Tokens: 8/382/390 | Cost: $0.01 | Session: $0.84/$5.00 (17%) | Tools: 6/20
| Metric | Type | Labels | Description |
|--------|------|--------|-------------|
| netclaw_session_budget_trips_total | Counter | agent, reason, interface | Budget halt events |
| netclaw_model_cost_usd_total | Counter | agent, model, provider | Cumulative API cost |
| netclaw_model_calls_total | Counter | agent, model | API call count |
| netclaw_session_tool_calls_total | Counter | agent, interface | Tool invocations |
Token summaries (including budget status and any halt events) are automatically
included in GAIT session logs via SessionLedger.get_gait_summary(), providing
an immutable audit trail of token consumption and budget enforcement per session.
When contextAutoSummarize: true is configured and context exceeds the warning
threshold, old tool results will be automatically summarized into a compact form
before being re-sent as context. This keeps long sessions viable without constant
"start a new session" friction. (Documented hook — implementation tracked separately.)
Per-session caps protect against single-session runaways. A process-level daily
aggregate cap (dailyBudgetUsd) is the next logical layer for protecting against
many concurrent sessions or rapid session cycling. Not in scope for this version
but the SessionLedger architecture supports it (add a shared process-level counter).
tools
Zoom meeting intelligence — correlates a live or referenced Zoom meeting discussion against NetClaw's historical meeting record (via the official Zoom Meetings MCP) and today's actual network state. Use when someone in a Zoom meeting references a past discussion or incident ('didn't we have this issue before?'), or asks to search prior meetings for a topic. Does not itself recognize live in-meeting questions — that happens automatically inside zoom-rtms-mcp's own extractor (spec 118) before this skill is ever invoked.
tools
Manage Lantronix out-of-band (OOB) infrastructure via Percepxion central management platform: device inventory, serial port inspection via SLC CLI, firmware compliance, config management, security auditing, and closed-loop incident remediation. Use during outages, maintenance windows, compliance cycles, and AI-assisted automation workflows.
tools
Federate your NetClaw with other NetClaw operators over the BGP mesh — exchange capability inventories and ask your claw what a peer can do. (US1; remote invocation and chat land in later phases.)
tools
Review current and historical problems from Zabbix — severity, which host, when it started, how long it has been active, and whether anyone has acknowledged it. Use when someone asks what is broken right now, how long something has been broken, or what happened during a window that has already passed.