tokensniff
v0.1.1
Published
Claude Code telemetry proxy and live terminal status line HUD. Real-time token tracking, API costs, TTFT, and calendar heatmap dashboard. Zero dependencies.
Maintainers
Readme
tokensniff
Local telemetry sidecar for AI coding CLIs.
Track every token, every turn, every dollar — live in your terminal and on a calendar heatmap dashboard. Zero runtime dependencies.
What Is tokensniff?
tokensniff is a transparent HTTP reverse proxy and local telemetry sidecar designed specifically for the Claude Code CLI harness running alongside the local antigravity-claude-proxy.
By default, tokensniff orchestrates and connects to antigravity-claude-proxy to route Claude Code API requests through Google Antigravity / Cloud Code, allowing you to utilize your Antigravity Gemini quota directly inside Claude Code.
⚠️ Important Notice: Use At Your Own Risk & Account Warning
[!CAUTION] Use at your own risk. By default, tokensniff routes traffic through
antigravity-claude-proxy, which accesses Google Antigravity / Cloud Code endpoints using unofficial proxying techniques.
- Risk of Account Suspension / Bans: Google actively monitors and enforces Terms of Service (ToS) restrictions. Accounts connected to unofficial Cloud Code and Antigravity reverse proxies risk being shadow-banned, quota-restricted, or permanently banned.
- No Guarantees & Zero Liability: The creators and maintainers of
tokensniffprovide no guarantees or warranties of any kind, express or implied. We are not responsible or liable for any account bans, suspensions, quota penalties, data loss, or any other consequences resulting from the use of this software.- Safety Recommendation: Do not use your primary, personal, or corporate Google account. If you choose to use this integration, use a dedicated burner/disposable Google account.
- Learn More: Read the upstream antigravity-claude-proxy GitHub Repository and its Safety, Usage, and Risk Notices to understand how the underlying authentication and proxying operate.
It captures every API turn flowing through it and gives you:
- Per-turn token counts — input, output, cache-read, cache-write, thinking tokens
- Real-time cost tracking — per turn, per session, per day (in USD)
- Performance metrics — Time to First Token (TTFT), tokens per second (TPS), turn duration
- Live terminal status line — a single-line HUD rendered directly inside Claude Code's status bar
- Calendar heatmap dashboard — a beautiful, self-contained HTML page showing your daily token spend over the entire year
- Multi-terminal session management — run multiple terminals against the same proxy without conflicts
- Tool call tracking — which tools the model called, how many times, argument token sizes
- Context window monitoring — how full your context is, with color-coded warnings (green → yellow → red)
All of this happens transparently. Your AI tool doesn't know tokensniff exists. It just thinks it's talking to the normal API. tokensniff forwards every byte with zero latency overhead, while quietly recording the telemetry.
How It Works
flowchart TD
CLI["Claude Code CLI<br/><code>ANTHROPIC_BASE_URL:4000</code>"]
TS["tokensniff<br/><code>Reverse Proxy :4000</code>"]
Proxy["antigravity-claude-proxy<br/><code>Local Upstream :8085</code>"]
Google["Google Cloud Code API<br/><code>Gemini Backend / Quota</code>"]
subgraph Telemetry["Telemetry Engine"]
T1["latest.json"]
T2["totals.json"]
T3["history.ndjson"]
T4["/dashboard (HTML)"]
end
Statusline["Claude Code Statusline HUD"]
Dashboard["Live Calendar Heatmap<br/><code>http://localhost:4000/dashboard</code>"]
CLI <-->|"1. Anthropic API Requests / Streams"| TS
TS <-->|"2. Forward"| Proxy
TS -->|"3. Telemetry (Async)"| Telemetry
Proxy <-->|"4. Protocol Translation"| Google
T1 --> Statusline
T4 --> Dashboard- Harness Redirection: You point Claude Code to
http://localhost:4000by settingANTHROPIC_BASE_URLin~/.claude/settings.json. Claude Code continues sending standard Anthropic Messages API requests normally. - Upstream Proxy Startup: When launched, tokensniff checks port 8085 and automatically starts the local upstream proxy command (
npx antigravity-claude-proxy@latest start) if it is not already running. - Protocol & Quota Translation: The local
antigravity-claude-proxyreceives the Anthropic-formatted request, authenticates with your Google Antigravity / Cloud Code OAuth credentials, translates the schema to Google Generative AI format, and submits it to Google Cloud Code's backend to consume your Antigravity Gemini quota. - Streaming Response Pass-Through: As Google's response streams back,
antigravity-claude-proxytransforms it into Anthropic-compatible SSE events or buffered JSON. tokensniff instantly relays every raw byte back to Claude Code (res.write(chunk)) with zero latency overhead. - Telemetry Extraction: Concurrently and non-blockingly, tokensniff's parser inspects the response payload. It extracts Google's
usageMetadata(input, output, cache-read, cache-write, and thinking/reasoning tokens), measures Time to First Token (TTFT) and token generation speed (TPS), and tracks turn duration. - Live Pricing Calculation: tokensniff queries live pricing from OpenRouter's model catalog, computing turn cost, session cumulative spend, and daily totals.
- Statusline HUD & Calendar Heatmap: Telemetry snapshots are written atomically to disk (
latest.json,totals.json,history.ndjson). Claude Code's status bar runstokensniff-statusto display the live single-line HUD, and tokensniff serves an interactive calendar heatmap dashboard athttp://localhost:4000/dashboard.
Quick Start
1. Install
npm install -g tokensniffOr with pnpm:
pnpm add -g tokensniff2. Initialize Configuration
tokensniff initThis creates a configuration file at ~/.tokensniff/config.json with sensible defaults:
{
"upstreamCommand": "npx antigravity-claude-proxy@latest start",
"upstreamHost": "localhost",
"upstreamPort": 8085,
"listenPort": 4000,
"harnessCommand": "claude"
}Default Upstream: Out of the box, tokensniff is pre-configured to launch
antigravity-claude-proxyon port8085, allowing you to route Claude Code prompts through your Antigravity Gemini quota. Please review the Risk & Terms of Service Warning before running with this configuration.
3. Configure Claude Code
Add the following to your ~/.claude/settings.json file:
{
"env": {
"ANTHROPIC_BASE_URL": "http://localhost:4000"
},
"statusLine": {
"type": "command",
"command": "tokensniff-status",
"padding": 0
}
}This does two things:
ANTHROPIC_BASE_URL— Tells Claude Code to send all API requests through tokensniff's proxy on port 4000 instead of directly to AnthropicstatusLine— Tells Claude Code to runtokensniff-statusand display its output as a live status bar at the bottom of the terminal
4. Run
tokensniffThat's it. tokensniff will:
- Start the upstream proxy (if configured)
- Start the telemetry proxy on port 4000
- Launch Claude Code (or whatever harness command you configured)
- Show you a live status line and dashboard URL
Open the dashboard in your browser:
http://localhost:4000/dashboardCLI Commands
tokensniff
Runs the full telemetry pipeline: starts the upstream proxy, starts the tokensniff proxy, and launches your AI coding tool.
tokensnifftokensniff init
Generates the global configuration file at ~/.tokensniff/config.json and prints the Claude Code settings.json instructions.
tokensniff inittokensniff dashboard
Prints the URL of the live calendar heatmap dashboard.
tokensniff dashboard
# Output: [tokensniff] live heatmap dashboard: http://127.0.0.1:4000/dashboardtokensniff-status
This is the statusline renderer. You don't run this directly — Claude Code runs it automatically via the statusLine setting. It reads the latest telemetry snapshot from disk and outputs a formatted single-line status bar.
If you want to test it manually:
echo '{}' | tokensniff-statusTo get raw JSON output instead of the formatted status line:
TOKENSNIFF_JSON=1 echo '{}' | tokensniff-statusThe Status Line
When running inside Claude Code, you'll see a live status line at the bottom of your terminal that looks like this:
Wide terminals (≥ 180 columns) — single line:
turn 3 [3.8-flash] | ctx: 38.5k/1M (3.9%) [cache: 25k (64.9%)] | input: +4.5k tok, output: 42 tok, think: 180 tok | ttft: 1.2s, 110 tok/s | cost: turn $0.0042, sess $0.058, today $0.245Standard terminals (< 180 columns) — clean 2-line stack:
turn 3 [3.8-flash] | ctx: 38.5k/1M (3.9%) [cache: 25k (64.9%)]
input: +4.5k tok, output: 42 tok, think: 180 tok | ttft: 1.2s, 110 tok/s | cost: turn $0.0042, sess $0.058, today $0.245What Each Segment Means
| Segment | Example | Meaning |
|---------|---------|---------|
| Turn | turn 3 | Which turn number this is in the current session |
| Model | [3.8-flash] | The AI model being used (vendor prefix stripped for readability) |
| [bg] | [bg] | Shown when this is a background agent turn (via x-app: cli-bg header) |
| Context | ctx: 38.5k/1M (3.9%) | Current context usage / max window size (percentage full) |
| Cache | [cache: 25k (64.9%)] | How many tokens were served from cache and the cache hit ratio |
| Input | input: +4.5k tok | New tokens added to context this turn (delta). Shows freed when context shrinks |
| Output | output: 42 tok | Tokens generated by the model this turn |
| Thinking | think: 180 tok | Reasoning/thinking tokens used (for models with extended thinking) |
| Tool | tool: Read (45 tok) | Which tool was called and how many argument tokens it used |
| TTFT | ttft: 1.2s | Time to First Token — how long before the model started generating |
| Speed | 110 tok/s | Generation velocity in tokens per second |
| Turn Cost | turn $0.0042 | How much this specific turn cost in USD |
| Session Cost | sess $0.058 | Total spend for this entire session |
| Today Cost | today $0.245 | Total spend across all sessions today (resets at local midnight) |
| [idle] | [idle] | Shown when the last turn was more than 120 seconds ago |
Color Coding
The context percentage is color-coded based on how full your context window is:
- 🟢 Green — Under 60% (plenty of room)
- 🟡 Yellow — 60-80% (getting full, consider starting a new session)
- 🔴 Red — Over 80% (context is nearly full, model may start forgetting earlier context)
These thresholds are configurable via warnPct and critPct.
The Dashboard
tokensniff serves a live calendar heatmap dashboard directly on the proxy port. Open it in any browser:
http://localhost:4000/dashboardThe dashboard shows:
- Total Spend — cumulative USD spent across all sessions
- Total Tokens — cumulative token volume processed
- Cache Ratio — what percentage of tokens were served from cache
- Total Turns — how many API turns have been recorded
- Calendar Heatmap — a GitHub-contributions-style grid showing daily token volume across the year
Heatmap Tiers
The calendar tiles are colored using a 5-tier emerald luminosity scale:
| Tier | Daily Volume | Color | |------|-------------|-------| | 0 | No activity | Dark (nearly invisible) | | 1 | < 5M tokens | Dark emerald | | 2 | 5M – 25M tokens | Medium emerald | | 3 | 25M – 100M tokens | Bright emerald | | 4 | > 100M tokens | Vivid emerald (glowing) |
Hover over any tile to see a detailed tooltip with exact token counts, cost, cache leverage, and turns logged for that day.
Dashboard API
There's also a JSON API endpoint for programmatic access:
curl http://localhost:4000/api/dailyReturns the raw daily rollup data as JSON.
Configuration
tokensniff uses a strict hierarchical configuration system:
Environment Variables > Config File > Embedded Defaults
(highest) (medium) (lowest)Config File Location
~/.tokensniff/config.jsonYou can override this path with the TOKENSNIFF_CONFIG environment variable:
TOKENSNIFF_CONFIG=/path/to/custom/config.json tokensniffAll Configuration Options
| Config Key | Env Variable | Default | Description |
|-----------|-------------|---------|-------------|
| listenPort | TOKENSNIFF_PORT | 4000 | Port the tokensniff proxy listens on |
| listenHost | TOKENSNIFF_HOST | 127.0.0.1 | Host/IP the proxy binds to |
| upstreamHost | TOKENSNIFF_UPSTREAM_HOST | localhost | Hostname of the upstream API server |
| upstreamPort | TOKENSNIFF_UPSTREAM_PORT | 8085 | Port of the upstream API server |
| upstreamTimeoutMs | TOKENSNIFF_UPSTREAM_TIMEOUT_MS | 300000 (5 min) | Timeout for upstream requests in milliseconds (range: 1,000 – 3,600,000) |
| maxBodyBytes | TOKENSNIFF_MAX_BODY_BYTES | 10485760 (10 MB) | Maximum request/response body size. Requests exceeding this get a 413 error (range: 1,024 – 104,857,600) |
| statusDirs | TOKENSNIFF_STATUS_DIRS | ~/.tokensniff/status | Comma-separated list of directories where telemetry snapshots are written |
| maxSessions | TOKENSNIFF_MAX_SESSIONS | 50 | Maximum number of tracked sessions before oldest are evicted (range: 1 – 1,000) |
| deadSessionMs | TOKENSNIFF_DEAD_SESSION_MS | 259200000 (72 hrs) | How long to keep stale session files before pruning (range: 1 hour minimum) |
| staleAfterS | TOKENSNIFF_STALE_AFTER_S | 120 | Seconds of inactivity before a session shows [idle] in the status line (range: 5 – 86,400) |
| labelMaxIn | TOKENSNIFF_LABEL_MAX_IN | 2000 | Maximum input tokens for a turn to be classified as a micro-label |
| labelMaxOut | TOKENSNIFF_LABEL_MAX_OUT | 60 | Maximum output tokens for a turn to be classified as a micro-label |
| warnPct | TOKENSNIFF_WARN_PCT | 60 | Context utilization % threshold for yellow warning color (range: 1 – 99) |
| critPct | TOKENSNIFF_CRIT_PCT | 80 | Context utilization % threshold for red critical color (range: 2 – 100) |
| color | TOKENSNIFF_COLOR | true | Enable/disable ANSI color output. Automatically disabled when NO_COLOR env var is set (per no-color.org) |
| upstreamCommand | TOKENSNIFF_UPSTREAM_CMD | npx antigravity-claude-proxy@latest start | Shell command to start the upstream proxy server |
| upstreamStopCommand | TOKENSNIFF_UPSTREAM_STOP_CMD | (empty) | Shell command to stop the upstream proxy on shutdown |
| harnessCommand | TOKENSNIFF_HARNESS_CMD | claude | The AI coding tool to launch (e.g., claude, codex, or any executable) |
Example Config File
{
"listenPort": 4000,
"listenHost": "127.0.0.1",
"upstreamHost": "localhost",
"upstreamPort": 8085,
"upstreamCommand": "npx antigravity-claude-proxy@latest start",
"upstreamStopCommand": "",
"harnessCommand": "claude",
"maxSessions": 50,
"staleAfterS": 120,
"warnPct": 60,
"critPct": 80,
"color": true
}Environment Variable Examples
# Change the proxy port
TOKENSNIFF_PORT=5000 tokensniff
# Point to a different upstream
TOKENSNIFF_UPSTREAM_HOST=api.anthropic.com TOKENSNIFF_UPSTREAM_PORT=443 tokensniff
# Disable colors
NO_COLOR=1 tokensniff
# Use a custom config file
TOKENSNIFF_CONFIG=./my-config.json tokensniff
# Write status to multiple directories
TOKENSNIFF_STATUS_DIRS="/path/a,/path/b" tokensniffMulti-Terminal Support
tokensniff supports multiple terminal sessions running simultaneously against the same proxy. This is how it works:
- When you run
tokensniff, it first checks if a proxy is already running on port 4000 - If yes, it attaches to the existing proxy (no duplicate servers) and just launches your harness
- Each terminal session registers itself in
~/.tokensniff/sessions/with a PID lock file - When you close a terminal (Ctrl+C or exit):
- If other terminals are still active → only the local harness is terminated; the proxy stays alive
- If this was the last terminal → the proxy and upstream are cleanly shut down
- Dead PID lock files (from crashed terminals) are automatically pruned
This means you can have 5 Claude Code windows all routing through the same tokensniff proxy, and the telemetry stays unified. Session costs are tracked independently, but today cost accumulates across all sessions.
Supported Providers
tokensniff's parser understands multiple API response formats:
| Provider | Format | Detection |
|----------|--------|-----------|
| Anthropic (Claude) | SSE streams (text/event-stream) | event: message_start framing |
| Anthropic (Claude) | Buffered JSON (application/json) | usage.input_tokens / usage.output_tokens |
| Google Gemini (Antigravity) | Buffered JSON | candidates[].content.parts[] + usageMetadata |
The parser automatically detects the format from the response content-type and payload structure. You don't need to configure anything.
Pricing
tokensniff fetches live per-token pricing from OpenRouter's public model catalog. This means:
- Pricing is always up to date — no hardcoded rate tables to maintain
- Any model listed on OpenRouter is automatically priced correctly
- Pricing includes prompt, completion, cache-read, and cache-write tiers
- Context window sizes are also pulled dynamically from the catalog
If a model isn't found on OpenRouter, costs default to $0.00 (zero-rate boundary) rather than guessing wrong. The context window defaults to 128K tokens for unknown models.
The pricing cache is populated on-demand (first turn using a new model triggers a background fetch) and persists in memory for the lifetime of the proxy process.
Telemetry Data Files
tokensniff stores all telemetry in ~/.tokensniff/status/:
| File | Format | Purpose |
|------|--------|---------|
| latest.json | JSON | Most recent telemetry snapshot (any session) |
| latest-<session_id>.json | JSON | Most recent snapshot for a specific session |
| totals.json | JSON | Cumulative spend per session |
| history.ndjson | Newline-delimited JSON | Append-only turn-by-turn ledger (feeds the heatmap) |
latest.json Schema (v1)
{
"v": 1,
"session_id": "abc-123",
"turn_index": 5,
"ts": 1726056000000,
"model": "gemini-3.8-flash-tiered",
"is_bg": false,
"ctx": 38500,
"window": 1000000,
"pct": 3.9,
"cache_read": 25000,
"cache_create": 0,
"delta_in": 4500,
"in_tokens": 13500,
"out_tokens": 42,
"thinking": true,
"thinking_tokens": 180,
"tool": "Read",
"tool_tk": 45,
"tools_summary": [{ "name": "Read", "count": 1, "arg_tk": 45 }],
"stop_reason": "end_turn",
"is_label": false,
"label": "",
"ttft_ms": 1200,
"tps": 110,
"dur_s": 1.6,
"cost_turn": 0.0042,
"cost_session": 0.058,
"cost_today": 0.245,
"error": null,
"status": 200,
"quota_pct": null,
"quota_reset": null,
"tier": null
}history.ndjson Record Format
Each line is a compact JSON object:
{"d":"2026-09-11","ts":1726056000000,"s":"abc-123","t":5,"m":"gemini-3.8-flash","tk":38542,"c":0.0042,"cr":25000,"th":180}| Field | Meaning |
|-------|---------|
| d | Local calendar date (YYYY-MM-DD) |
| ts | Unix timestamp in milliseconds |
| s | Session ID |
| t | Turn number |
| m | Model name |
| tk | Total tokens (context + output) |
| c | Cost in USD |
| cr | Cache-read tokens |
| th | Thinking tokens |
Programmatic API
tokensniff exports its entire engine as a library. You can use it in your own Node.js projects:
npm install tokensniffStart the Proxy Programmatically
import { startProxy } from 'tokensniff';
const server = startProxy({
listenPort: 4000,
listenHost: '127.0.0.1',
upstreamHost: 'localhost',
upstreamPort: 8085,
});
// server is a standard Node.js http.Server
server.on('listening', () => {
console.log('tokensniff proxy is running');
});Calculate Costs
import { costFor, ratesFor, resolveModelRates } from 'tokensniff/pricing';
// Synchronous (from cache, or zero if not yet fetched)
const rates = ratesFor('claude-3-7-sonnet');
// Async (fetches from OpenRouter if needed)
const rates2 = await resolveModelRates('gemini-2.5-pro');
// Calculate cost
const cost = costFor(rates, {
input: 10000,
output: 500,
cacheRead: 8000,
cacheCreate: 0,
});
console.log(`Turn cost: $${cost.toFixed(4)}`);Use the Schema
import { buildLatest, isTokenSniffLatest, SCHEMA_VERSION } from 'tokensniff/schema';
// Build a telemetry snapshot with safe defaults
const snapshot = buildLatest({
session_id: 'my-session',
model: 'gemini-3.8-flash',
ctx: 25000,
window: 1000000,
pct: 2.5,
});
// Validate unknown data
if (isTokenSniffLatest(someData)) {
console.log('Valid telemetry snapshot');
}Full API Exports
import {
// CLI Orchestrator
runCli,
countActiveSessions,
getSessionsDir,
isPortActive,
isProcessAlive,
registerSession,
waitForTcp,
writeInitFile,
printClaudeInstructions,
// Configuration
loadConfig,
getGlobalDir,
getGlobalConfigPath,
// Proxy Server
startProxy,
// Dashboard & Analytics
importCapturesDirectory,
loadDailyRollup,
renderHeatmapHtml,
// Statusline Renderer
formatStatus,
formatTokenCount,
formatToolSegment,
runStatusRenderer,
readStdin,
pickLatest,
extractModel,
// Pricing Engine
costFor,
ratesFor,
resolveModelRates,
normalizeModelName,
syncOpenRouterCatalog,
// Schema & Types
buildLatest,
isTokenSniffLatest,
extractCleanLabel,
SCHEMA_VERSION,
} from 'tokensniff';Sub-path Exports
// Just the schema types and guards
import { buildLatest, isTokenSniffLatest } from 'tokensniff/schema';
// Just the pricing engine
import { costFor, resolveModelRates } from 'tokensniff/pricing';Architecture
tokensniff/
├── bin/
│ ├── tokensniff.js # CLI entrypoint → dist/cli.js
│ └── tokensniff-status.js # Statusline entrypoint → dist/status.js
├── src/
│ ├── index.ts # Public API facade (re-exports everything)
│ ├── cli/
│ │ └── run.ts # Master CLI orchestrator & multi-terminal lifecycle
│ ├── collector/
│ │ ├── config.ts # Hierarchical config loader (env > file > defaults)
│ │ ├── index.ts # HTTP reverse proxy server & telemetry capture
│ │ ├── parse.ts # SSE stream & JSON payload parser (multi-provider)
│ │ └── store.ts # Atomic file persistence engine (Windows-safe)
│ ├── dashboard/
│ │ └── heatmap.ts # Calendar heatmap HTML renderer & capture importer
│ ├── renderer/
│ │ ├── format.ts # Responsive statusline formatter
│ │ └── index.ts # Statusline CLI renderer (stdin consumer)
│ └── shared/
│ ├── pricing.ts # Dynamic pricing engine (OpenRouter catalog sync)
│ └── schema.ts # Domain schemas, type guards, label extraction
└── test/
├── fixtures.ts # Synthetic SSE/JSON payload generators
├── collector.test.ts # Integration: proxy, streaming, 502, 413, dashboard
├── format.test.ts # Statusline formatting & responsive layouts
├── heatmap.test.ts # Daily rollups, capture import, HTML rendering
├── parse.test.ts # SSE/JSON parsing, multi-provider, tool grouping
├── pricing.test.ts # Cost math, OpenRouter sync, model normalization
├── run.test.ts # CLI routing, TCP probing, session lifecycle
├── schema.test.ts # Type guards, buildLatest, label extraction
└── store.test.ts # Atomic writes, totals, history, pruning, configKey Design Decisions
Zero runtime dependencies — The entire package uses only Node.js built-in modules (
http,fs,net,path,os,child_process). No Express, no Axios, no anything. This keeps the install tiny and avoids supply chain risk.Atomic file writes — All file persistence uses a temp-file + OS rename pattern. This means readers (the statusline renderer) never see a half-written JSON file. On Windows, retries with exponential backoff handle EPERM/EBUSY file lock contention.
Streaming-first proxy — Response bytes are forwarded to the client as they arrive (
res.write(chunk)). tokensniff never buffers the full response before forwarding. This means zero latency overhead. The telemetry parsing happens on the buffered copy.LRU-bounded memory — Internal maps (context history, turn indices) are capped at 500 entries using LRU eviction. The proxy can run for weeks without leaking memory.
Defensive parsing — The parser never throws. Corrupt payloads, truncated SSE streams, binary noise — everything returns a safe fallback result. This is critical because the proxy sits in the hot path of your AI tool.
Development
Prerequisites
- Node.js ≥ 22.0.0
- pnpm 11.x
Setup
git clone https://github.com/neerajsahu0306/tokensniff.git
cd tokensniff
pnpm installBuild
pnpm buildRun Tests
pnpm testType Check
pnpm typecheckLint
pnpm lintAuto-fix Lint Issues
pnpm lint:fixWatch Mode (Development)
pnpm devValidate Package Structure
pnpm check:packageTroubleshooting
"waiting for first turn..."
The status line shows this message when tokensniff hasn't received any API requests yet. Make sure:
- Your
ANTHROPIC_BASE_URLis set tohttp://localhost:4000in~/.claude/settings.json - The tokensniff proxy is actually running (check terminal output)
- You've made at least one prompt in Claude Code
Port 4000 is already in use
Another tokensniff instance (or another program) is using port 4000. Either:
- Let tokensniff attach to it (it will do this automatically if the existing proxy is tokensniff)
- Change the port:
TOKENSNIFF_PORT=5000 tokensniff - Kill the existing process: find and terminate whatever is using port 4000
Upstream proxy failed health check
tokensniff couldn't connect to the upstream API server. Check that:
- Your
upstreamCommandis valid and the upstream server starts correctly - The
upstreamHostandupstreamPortmatch where the upstream is listening - The upstream server is not firewalled or blocked
tokensniff will continue running even if the upstream health check fails — downstream requests will get 502 errors until the upstream becomes available.
Costs showing $0.0000
This means tokensniff couldn't find pricing for the model you're using on OpenRouter. This can happen if:
- The model is brand new and not yet listed on OpenRouter
- The OpenRouter API was unreachable when tokensniff tried to fetch pricing
- You're using a custom/private model that isn't publicly listed
The proxy and telemetry still work perfectly — only the cost calculation defaults to zero.
Status line not appearing in Claude Code
Make sure your ~/.claude/settings.json has the exact statusLine block:
{
"statusLine": {
"type": "command",
"command": "tokensniff-status",
"padding": 0
}
}Also verify that tokensniff-status is accessible in your PATH (it should be if you installed tokensniff globally).
Requirements
- Node.js ≥ 22.0.0
- OS: Windows, macOS, or Linux
- Terminal: Any terminal that supports ANSI colors (for the status line color coding)
License
MIT © 2026 tokensniff contributors
