Cut Claude Code token waste.
Blocks redundant file reads, injects a project map so Claude skips exploration, recommends cheaper models per prompt, and tracks cost honestly on a local dashboard.
hard-block duplicate reads · inject project map at session start · recommend haiku/sonnet/opus per task
Disclaimer: Independent community tool, not affiliated with Anthropic. Results depend on your usage — the dedupe and map features save measured tokens, but "how much money it saves you" is workload-dependent. The dashboard shows the raw trend separately from the directly-attributed deduper savings so you can judge for yourself. See What it does / what it doesn't do below for the honest scope.
Does:
- Hard-blocks redundant
Readtool calls in the same session — thePreToolUsehook returnspermissionDecision: "deny"so the re-read never happens and the file content never re-enters Claude's context. Every blocked read is counted on the dashboard. - Injects a project file-map at session start — the
SessionStarthook emits a markdown summary (directories, notable files, one-line descriptions) so Claude doesn't burn 50–200k tokens on "let me explore this repo first." - Recommends a cheaper model per prompt — classifies your prompt (search/edit/debug/plan/architecture) and renders a routing box suggesting haiku/sonnet/opus. Injected as a hint to subagent dispatches; for the main conversation it's advisory.
- Nudges subagent dispatches — when a
Task/Agenttool call uses a more expensive model than needed, the hook injects a "this should have been sonnet" message so the parent agent learns. - Tracks cost honestly — per-day real token counts from
~/.claude/stats-cache.json(not hardcoded per-call guesses). The dashboard has a "Cost since install" chart with an install-date marker.
Doesn't:
- Swap the model on the main conversation. Claude Code's hook protocol has no field for this;
UserPromptSubmitonly supportsadditionalContext/decision/systemMessage. Our routing box is a suggestion, not an override. Anthropic's Advisor Tool is the native API-level solution for real executor/advisor pairing — when Claude Code adopts it, this tool will defer to it. - Talk to Anthropic's servers. Everything runs locally.
- Replace
claude /cost. We pull the same data and show it in more views.
git clone https://github.com/imwebdev/claude-token-tracker.git
cd claude-token-tracker
node bin/cli.js initNo npm install needed. Zero dependencies. Seriously — zero.
Then restart Claude Code (exit completely and relaunch). Hooks do not take effect until you restart.
When a new version is released, run this from the repo folder:
cd claude-token-tracker
node bin/cli.js updateThis pulls the latest code and restarts the dashboard. No reinstall needed.
Verify everything is working:
node bin/cli.js doctorAll checks should pass. If any fail, the output tells you exactly what to fix.
After install, a small routing box appears in your terminal every time you send a prompt:
- - - - - - - - - - - - - - - - - - - -
TOKEN COACH search_read (low, high conf)
model: haiku simple lookup -- haiku is 15x cheaper than opus
action: > redirect to haiku subagent
session: ~$0.45 (12 prompts)
- - - - - - - - - - - - - - - - - - - -
That is it. You do not need to learn any commands. Just use Claude Code as you always have — the hooks run in the background, the dashboard records what they did.
Four Claude Code hooks do the work. None of them can swap the main model (the hook API doesn't allow it), but each does something measurable:
SessionStart
+-- getOrGenerate(project-map) --> injects markdown file tree + one-liners
into context; first-session-in-repo gets
cached for 24h at ~/.token-coach/project-maps/
UserPromptSubmit
+-- classifyTask(prompt) --> search_read / code_edit / debug /
+-- recommendModel() review / plan / architecture
+-- inject additionalContext --> "TOKEN COACH haiku (low) ..." banner
+ session cost ($X.XX) + warnings
PreToolUse (Read)
+-- lookup(sessionId, filePath) --> cache hit? emit
permissionDecision: "deny"
-> Claude cannot re-read the file
-> context unchanged, tokens saved
PreToolUse (Agent / Task)
+-- classify the subagent's prompt --> if subagent model > recommended,
+-- inject "use sonnet next time" log suboptimal dispatch
PostToolUse (Write / Edit / MultiEdit)
+-- invalidate(sessionId, filePath) --> next Read is allowed again
The router uses keyword pattern matching (no LLM call) to classify prompts. The file-map walker is also heuristic (first meaningful comment/line per file). Zero dependencies, sub-50ms hook budget. The learner tracks which model actually succeeded for each task family and adjusts recommendations over time.
| No cloud | Runs entirely on your computer |
| No account | No API key, no sign-up, nothing |
| No telemetry | Zero analytics, zero phone-home |
| Offline | Works without internet after install |
| Your data | Stays in ~/.token-coach/ on your machine |
- Node.js 18 or newer
- Claude Code installed and signed in
- PM2 (optional, for the web dashboard):
npm install -g pm2
cd claude-token-tracker
node bin/cli.js uninstallRemoves hooks from Claude Code, stops the dashboard, and removes global commands. It will ask before deleting your data.
Then restart Claude Code (exit and relaunch).
To also delete the repo folder afterward: rm -rf claude-token-tracker
Does this slow down Claude Code?
No. The hooks run in under 50ms. You will not notice any delay.
Does this change how Claude Code works?
Partially, and only in specific ways. The
PreToolUse hook will block a redundant Read tool call on a file already read in the current session — Claude gets a "you already read this" message instead of the file contents. That's the deliberate token-saving behavior, and it's the one place we mechanically intervene. Everything else is additive: routing suggestions, session cost display, project-map context injection. We don't modify responses, don't intercept your conversations, and can't swap the main model (the hook API doesn't support it). You can disable deduping with read_dedupe: false in ~/.token-coach/config.json.
Why can't it just route my prompt to a cheaper model?
Claude Code's hook API has no field to override the model for the current turn.
UserPromptSubmit hooks can inject context, block the turn, or set a warning banner — but they can't pick a different model. Anthropic's Advisor Tool is the native API-level answer (cheap executor + smart advisor in one request), but it's an /v1/messages feature, not a Claude Code feature. When Claude Code adopts it, this tool will defer to it.
Does this actually save me money?
Two parts to the answer. Directly attributed: yes — every blocked redundant read is a measurable byte of context that didn't get sent. The dashboard counts those. Overall cost trend: depends on your workload. We show both separately on the "Cost since install" chart so you're not misled; raw spend trends reflect how much you're using Claude, not how well this tool worked.
Can I turn it off temporarily?
Yes. Open
~/.claude/settings.json and remove the hooks entries. Run node bin/cli.js init at any time to re-install them.
Where is my data stored?
Everything is in
~/.token-coach/ on your machine. Change the location with the TOKEN_COACH_HOME environment variable.
Does this work with Claude Code for teams?
Yes. Installed per-machine. Does not interact with Anthropic's servers or your team's configuration.
Everything below is optional. You do not need any of this to use Token Tracker.
Commands, configuration, dashboard, and more
All commands work as node bin/cli.js <command> from the repo folder, or as claude-tokens <command> after running npm link.
Setup and health
node bin/cli.js init # First-time setup (default port 6099)
node bin/cli.js init --port 8080 # First-time setup on custom port
node bin/cli.js doctor # Health check -- verify hooks, data dir, dashboard
node bin/cli.js update # Pull latest updates, restart dashboard
node bin/cli.js regenerate-map # Force-rebuild the SessionStart project map for cwdAnalytics
node bin/cli.js # Token usage summary
node bin/cli.js costs # Cost breakdown by model
node bin/cli.js insights # Actionable recommendations
node bin/cli.js learn # What the router has learned from your usage
node bin/cli.js audit # Waste audit (over-routing, unnecessary escalations)
node bin/cli.js benchmark # Benchmark data from recorded runs
node bin/cli.js dashboard # Start the web dashboard (uses configured port, default 6099)Configuration
node bin/cli.js config # View all settings
node bin/cli.js config routing_preference 20 # Set cost preference (0-100)
node bin/cli.js config daily_alert 5 # Warn when daily spend hits $5
node bin/cli.js config daily_cap 20 # Alert when daily spend hits $20
node bin/cli.js config dashboard_port 8080 # Change dashboard port
node bin/cli.js config read_dedupe false # Disable PreToolUse Read blocking
node bin/cli.js config session_start_map false # Disable SessionStart project-map injectionTask execution (advanced)
# Route a task -- shows recommendation but does not execute
node bin/cli.js run "search for duplicate route definitions"
# Route AND execute via Claude CLI
node bin/cli.js run --execute "fix the failing import in app.ts"
# Execute with unrestricted permissions (use with caution)
node bin/cli.js run --execute --unsafe "deploy to staging"When executing, Token Tracker snapshots files before and after, spawns claude -p with the recommended model, validates the result, and escalates through the fallback chain (haiku to sonnet to opus) if the task fails.
Control the cost vs. quality tradeoff with a number from 0 to 100:
node bin/cli.js config routing_preference 35| Range | Mode | Behavior |
|---|---|---|
| 0-25 | Max savings | Aggressively uses haiku and sonnet. Opus only for architecture. |
| 26-50 | Cost-conscious (default: 35) | Sonnet-heavy. Opus for architecture and multi-file only. |
| 51-75 | Balanced | Opus for complex debug, review, and planning tasks. |
| 76-100 | Max quality | Opus for anything medium complexity or higher. |
node bin/cli.js config daily_alert 5 # Yellow warning at $5/day
node bin/cli.js config daily_cap 20 # Red alert at $20/dayAlerts appear in the routing box on every prompt once a threshold is reached.
| Family | Example prompts | Default model |
|---|---|---|
search_read |
"find all TODO comments", "where is the config" | haiku |
question |
"what does this function do", "explain the routing" | haiku |
code_edit |
"fix the typo", "add error handling" | sonnet |
command |
"run npm test", "build the project" | sonnet |
review |
"review the PR", "audit the security" | sonnet |
plan |
"plan the migration", "design the API" | sonnet |
debug |
"debug the 500 error", "why is this failing" | sonnet/opus |
multi_file |
"refactor across all files", "rewrite the auth system" | opus |
architecture |
"design the system architecture", "database schema" | opus |
The router learns from your usage over time. Tracks success rates per task family and model, then adjusts recommendations.
node bin/cli.js learnA dashboard (default port 6099) shows:
- Today's task count by model, delegation rate, and estimated cost
- Every classified prompt with model, family, project, and status
- Actionable recommendations based on usage patterns
- Per-session cost estimates with model breakdown
- Success rates per task family and model
- Tool and agent token consumption
- Hourly activity heatmap
node bin/cli.js init starts the dashboard automatically via PM2, binds it to all interfaces (0.0.0.0), and registers it with systemd so it survives reboots. Access it at:
http://<your-server-ip>:6099
If you're running Claude Code locally (not on a remote server), use http://localhost:6099.
To make it survive reboots on a fresh machine, init will print one sudo command to run — copy-paste it once and it's done:
node bin/cli.js init # prints the sudo startup command if neededManual dashboard commands (only needed if not using PM2):
node bin/cli.js dashboard # start on default port
node bin/cli.js dashboard --port 8080 # override portThe routing box also warns about:
- Long sessions (20+ prompts) — suggests
/compactor starting fresh - Budget thresholds — when daily spend reaches your alert or cap
- Vague prompts — flags long prompts classified as "unknown"
- Suboptimal dispatches — when a subagent uses a more expensive model than needed
Token Tracker records per prompt: task classification, model recommendation, first 200 chars of prompt (for analytics), subagent dispatches, tool call names.
It does NOT record: full prompt text, file contents, API keys, or tool input/output payloads.
bin/
cli.js CLI entrypoint
hook-router.js Claude Code hook handler (all events)
src/
router.js Task classification and model recommendation
learner.js Adaptive learning from historical data
config.js User configuration (preference, alerts, feature flags)
init-command.js Setup wizard and health check
install-meta.js Records install date for the cost-since-install chart
read-cache.js Per-session file-read cache (powers the Read deduper)
project-map.js SessionStart file-map generator + 24h cache
run-command.js Task execution with file snapshots
validator.js Execution result validation
escalation.js Fallback chain (haiku -> sonnet -> opus)
events.js Event logging, session costs, dedupe stats
ledger.js Run persistence to ~/.token-coach/
parser.js Reads Claude Code data from ~/.claude/
calculator.js Token cost math + per-day series
insights.js Actionable recommendations
server.js Dashboard HTTP server
data-home.js Path resolution for ~/.token-coach/
public/
index.html Dashboard UI (single file, zero dependencies)
test/
classifier-benchmark.js Router accuracy (172 labeled cases)
read-cache.test.js Per-session cache
project-map.test.js Project-map generator
install-cost.test.js Install-date marker + daily cost
dedupe-stats.test.js Aggregator for read_deduped events
MIT