Local streaming reverse proxy between AI coding agents (Claude Code, Cursor, Codex) and model APIs (Anthropic, OpenAI, Gemini, MiniMax). Meters every token + USD cost, compacts bloated context to cut pay-per-token API spend, and runs shadow-eval to prove quality held. ccusage-style metering + live local dashboard.
tokdiet
Your AI agent is paying to send the same file dump five times. tokdiet is a local proxy that sits between your agent and the model API, meters every token, puts your bloated context on a diet โ and proves the answer didn't get worse.
ccusage that shrinks the bill โ without losing quality.
๐ Live demo (watch one request lose the weight): agiwhitelist.github.io/tokdiet ๐ Launch write-up + full benchmark methodology: I cut an AI agent's input tokens by 71% and quality held โ here's the 66-task benchmark
The proof (this is the whole point)
Every "context optimizer" cuts tokens. The scary question is the one they can't answer:
"If I cut the context, does the model get dumber?"
So we measured it. A 66-task A/B benchmark across 6 categories on a real model (MiniMaxโM3), each task run twice โ full context (baseline) vs through tokdiet (governed) โ graded against the known answer, repeated ร3 and majorityโvoted to cancel model noise:
baseline tokdiet
input tokens 5.07M โ 1.46M โ71%
quality (66 tasks) 64/66 63/66 โ parity (95โ97%)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
198 paired runs ยท LLM-judge 92% similarity ยท confirmed on a 2nd model (MiniMax-M2.5: โ72%)
โ71% tokens, quality on par with baseline. Real requests, real grading โ not a mock. The ~1โ2 task gap is model nondeterminism plus the model declining to echo a secret โ not context loss; the hardest "needle buried in junk" adversarial cases pass, because tokdiet doesn't delete blindly โ it pages cold context out recoverably and protects anything onโtopic. Reproduce it yourself: node bench/run.mjs (needs an API key in env).
How it compares
| | shows your bill | cuts the bill | proves quality held | |----------------------------------------------|:---------------:|:-------------:|:-------------------:| | eyeballing /cost, ccusage | โ
| โ | โ | | manual /compact, hand-pruning context | โ | โ
(blind) | โ | | tokdiet | โ
| โ
| โ
measured + auto safe-mode |
Everyone shows the bill or cuts it blind. tokdiet is the one that cuts it and proves the model didn't get dumber โ and stops cutting the moment it might.
Quick start
# 1. Start the proxy (and live dashboard) โ no install needed
npx tokdiet start
# 2. Point your agent at the proxy instead of the real API
export ANTHROPICBASEURL=http://localhost:7787
export OPENAIBASEURL=http://localhost:7787/v1
Now run your agent (Claude Code, Cursor, Codex, your own script) as usual. Traffic flows through tokdiet, gets metered and compacted, and is forwarded upstream unchanged in every way that matters.
Your API key stays with you. tokdiet reads x-api-key / Authorization only to forward them upstream. They are never written to SQLite and never written to any log. And it's failโopen: if anything inside the governor errors, it falls back to transparent passthrough โ the proxy will never break your request or surface its own 5xx.
Default ports: proxy7787, dashboard7878. Override with--port/--dashboard-port.
Install via Claude Code
tokdiet ships as a Claude Code plugin via its own marketplace:
/plugin marketplace add agiwhitelist/tokdiet
/plugin install tokdiet
What the plugin does โ and what it doesn't. The plugin ships a *lightweight metering hook* plus a /tokdiet command. The hook runs on every tool call (PreToolUse + PostToolUse) and logs tool I/O byte sizes to ~/.tokdiet/tool-meter.log. It does not save tokens by itself โ a plugin can't set ANTHROPICBASEURL for the Claude Code process, so it can't route your traffic through the compacting proxy.
The actual token savings come from the proxy. Start it and point Claude Code at it (this is what gives you the ~โ71% token reduction):
npx tokdiet start
export ANTHROPICBASEURL=http://localhost:7787 # then launch Claude Code from this shell
View metered tokens, cost, and savings any time with npx tokdiet report, or run /tokdiet inside Claude Code for these instructions.
Works with Claude Code (and it's careful about it)
Claude Code is the flagship use case, and it has two landmines a naive compacting proxy walks straight into. tokdiet handles both:
- Prompt caching. Claude Code marks a cached prefix with
cachecontrol; cached input costs ~10% of normal. Rewriting that prefix invalidates the cache and can make a request cost more.tokdietis cacheโaware โ it never touches content at or before acachecontrolbreakpoint. - Extended thinking. Claude Code sends signed
thinkingblocks that Anthropic requires returned verbatim; touching one is an instant400.tokdietis thinkingโsafe โ signed/thinking blocks are never surfaced or mutated.
tests/cc-compat.test.ts).
A note on honesty: the dollarโsavings story applies to payโperโtoken API keys (MiniMax, Anthropic API, OpenAI, โฆ). On a flat Claude subscription there are no perโtoken charges to cut, so the value there is metering, budgets, and the live dashboard โ not dollars.
How it works
tokdiet is a streaming reverse proxy. SSE responses are proxied incrementally (never buffered whole), so your agent's tokens still stream in real time.
tokdiet (localhost:7787)
agent โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโบ model API
(Claude request โโโโโโโโโโโโโ โโโโโโโโโ โโโโโโโโโโ โโโโโโโโโโโโโ (Anthropic /
Code, โโโโโโโโโโโบ โinterceptorโโโบโ meter โโโบโ budget โโโบโ compactor โโโโบ OpenAI /
Cursor, raw key โโโโโโโโโโโโโ โโโโโโโโโ โโโโโโโโโโ โโโโโโโฌโโโโโโ Gemini /
Codex, forwarded detect count session/ โ dedup / elision / MiniMax)
โฆ) provider, tokens day / repo โ mid-summarize
keep body & cost limits โผ
byte-faithful โโโโโโโโโโโโโโโโโ
response โ quality guard โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค shadow-eval + โ
streamed back, token-for-token โ safe-mode โ
โโโโโโโโโโโโโโโโ โโโโโโโโโฌโโโโโโโโ
โ store(SQLite)โโโโโโโโโโโโโ
โ + dashboard โ telemetry, savings, degradation
โโโโโโโโโโโโโโโโ
Context as virtual memory (the idea)
Blind compaction is "delete and pray." tokdiet treats your context like virtual memory: hot content (recent, pinned, relevant to the current question) stays resident; cold content (stale, redundant) is paged out to a local store as a recoverable stub โ not deleted. The full block is kept in SQLite keyed by an id, so it can be audited and (roadmap) paged back in on demand when the model actually needs it.
The 3 quality mechanisms
| Mechanism | What it does | |-----------|--------------| | Shadowโeval | Reโruns a sampled fraction of compacted requests against the unโcompacted baseline and scores the divergence (0 = identical, 100 = unrelated). This is the measurement that answers "did quality drop?" | | Quality budget | A hard ceiling on acceptable measured degradation (qualityBudget.maxDegradationPct, default 2%). As you approach it, the compactor restricts itself to its safest strategies. | | Safeโmode | If rolling degradation exceeds the budget, the offending strategy is disabled (perโstrategy) and a safe-mode event fires. Savings stop before quality does. |
Compaction strategies (safestโfirst)
- Dedup โ lossโfree. When the same large block is reโpasted across a conversation, keep the freshest copy verbatim and replace earlier copies with a pointer marker. Works on nearโduplicates too (a file reโpasted with a few lines changed), not just byteโidentical ones.
- Elision โ recoverable. Page out the bulk of old tool results (file dumps, command output), keeping a preview plus the salient lines (errors, ids,
KEY=VALUE, URLs, paths, numbers) and storing the full body for recovery. Recent, pinned, and questionโrelevant results are kept intact. - Midโsummarize (off by default) โ summarize midโhistory with a cheap model. Optโin (it costs money).
Commands
tokdiet <command> [flags] # alias: td
| Command | What it does | Key flags | |---------|--------------|-----------| | start | Run the proxy + live dashboard | --port, --dashboard-port, --no-dashboard, --config <path> | | report | Print a usage report (or export) | --since <days>, --json, --csv <file>, --config <path> | | init | Scaffold tokdiet.config.json in the cwd | --force | | install-claude-plugin | Install an idempotent Claude Code metering hook | --settings <path> |
Configuration
Run tokdiet init to create tokdiet.config.json, or pass one with --config. All fields are optional and merge over sensible defaults.
| Field | Default | Description | |-------|---------|-------------| | proxyPort / dashboardPort | 7787 / 7878 | Ports (both bound to loopback only). | | dashboardEnabled | true | Start the dashboard alongside the proxy. | | contextWindowTokens | "auto" | Window size for utilization %; "auto" infers from the model. | | contextUtilizationThreshold | 0.7 | Compaction triggers once input utilization reaches this fraction. | | onBudgetExceeded | "warn" | "warn" \| "compact" \| "block" when a spend budget is hit. | | budgets.perSessionUSD / perDayUSD / perRepoMonthlyUSD | 5 / 50 / 400 | Spend ceilings (any may be null). | | compaction.strategies.{elision,dedup,midSummarize} | true/true/false | Perโstrategy switches. | | compaction.keepRecentToolResults | 4 | Mostโrecent tool results always kept intact. | | compaction.minToolResultTokens | 500 | Only elide tool results at least this large. | | compaction.elisionPreviewChars / elisionSalientLines | 240 / 12 | How much of a pagedโout block to keep (head + salient lines). | | compaction.relevanceProtect | true | Shield blocks lexically onโtopic with the latest question. | | compaction.recoverable | true | Persist pagedโout blocks for recovery/audit (virtual memory). | | compaction.protectCachedPrefix | true | Never compact a provider cache (cache_control) prefix. | | compaction.semanticDedup | true | Collapse nearโduplicates, not just exact ones. | | qualityBudget.maxDegradationPct | 2.0 | Max measured degradation before safeโmode trips. | | shadowEval.enabled / sampleRate | true / 0.05 | Whether/how often to shadowโevaluate. | | shadowEval.judge | "heuristic" | "heuristic" \| "llm" ("embedding" reserved, falls back to heuristic). | | shadowEval.judgeModel | "claude-haiku-4" | Cheap model for the LLM judge / midโsummarize. | | pageFault | { enabled: true, maxReinjections: 1 } | Reโinject a pagedโout block if the model can't answer without it. | | safeMode | true | Autoโdisable a strategy when it exceeds the quality budget. | | dataDir | ~/.tokdiet | Where SQLite telemetry lives. | | pricingPath | null | Override path for pricing.json (null = bundled). |
Upstream overrides (point at a nonโdefault origin โ e.g. MiniMax):TOKDIETANTHROPICUPSTREAM,TOKDIETOPENAIUPSTREAM,TOKDIETGEMINIUPSTREAM(legacyCTXGOV*UPSTREAMstill read for backโcompat).
Dashboard
With the proxy running, open http://localhost:7878 โ a single selfโcontained page that streams live updates over SSE (loopback only; your cost data never leaves the machine):
โโ tokdiet โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ live ยท :7878 โโ
โ โ
โ SESSION claude-code โบ my-repo โบ MiniMax-M3 โ
โ context โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 64% 128,402 / 200,000 tok โ
โ โ
โ โโโ TODAY โโโโโโโโโโโโโโโโโ โโโ SAVED (cumulative) โโโโโโโโโโโโโโ โ
โ โ sent 1.43M tok โ โ $12.40 โโโโ
โโโ โ saving $1.07/h โ โ
โ โ saved 3.64M tok โ โ 3.6M tokens never left this box โ โ
โ โ spend $0.43 โ โ โ71.8% on real traffic โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ QUALITY GUARD measured degradation 0.4% โโโโโโโโโโโโ budget 2.0% โ
โ โโโโโโโโโโ 72 shadow-evals safe-mode โ ON ยท OK โ
โ โ
โ STRATEGY LEADERBOARD fires tokens saved ฮ quality โ
โ โธ dedup โโโโโโโโโโโ 312 1.91M +0.0% โ
โ โธ elision โโโโโโ 168 1.42M +0.6% โ
โ โธ midSummarize ยท off ยท 0 โ โ โ
โ โ
โ BY TOOL claude-code โโโโโโโโโโ $0.31 cursor โโโ $0.09 codex โ$03 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Five live screens: Live session, Savings, Quality (degradation + safeโmode status), By tool & repo, and Strategy leaderboard โ all updating in real time over SSE.
See the savings โ no API key required
npm run build && node scripts/demo.mjs
Stands up a mock Anthropic upstream on loopback, starts the real tokdiet proxy in front of it, and sends one realistic bloated agent request through the whole pipeline โ actual interceptor, tokenizer, compactor, pricing, telemetry, and shadowโeval. No external network, no real key. It prints a before/after table proving the input shrank while the answer stayed identical (so shadowโeval reports ~0% degradation). (The scenario is synthetic; your real savings depend on how much your own conversations repeat.)
Supported providers
| Provider | Endpoint detected | Base URL to set | |----------|-------------------|-----------------| | Anthropic | /v1/messages | ANTHROPICBASEURL=http://localhost:7787 | | OpenAI | /v1/chat/completions | OPENAIBASEURL=http://localhost:7787/v1 | | Gemini | :generateContent / /v1beta/โฆ | point the Gemini SDK base URL at the proxy | | MiniMax (and any OpenAI/Anthropicโcompatible API) | mimics OpenAI /v1 & Anthropic /anthropic | OPENAIBASEURL=http://localhost:7787/v1 + TOKDIETOPENAIUPSTREAM=https://api.minimax.io |
Prices come from pricing.json (USD per 1,000,000 tokens, dated, userโupdatable, hotโreloaded on start; exact match then longestโprefix).
Works with your agent
tokdiet needs no per-tool plugin. The rule is simple:
If your tool lets you override the model base URL and speaks Anthropic / OpenAI / Gemini, it works with tokdiet โ point it athttp://localhost:7787/v1(OpenAI) orhttp://localhost:7787(Anthropic) and run as usual.
Confirmed from each tool's official docs (2026-06-18):
| Tool | Where you set the base URL | |------|----------------------------| | Claude Code | ANTHROPICBASEURL env | | opencode | opencode.json โ provider.<id>.options.baseURL | | Aider | OPENAIAPIBASE / ANTHROPICAPIBASE env (model prefixed openai/ยทanthropic/) | | Continue.dev | config.yaml โ apiBase | | Cline / Roo Code / Kilo Code | GUI: "OpenAI Compatible" Base URL, or Anthropic "Use custom base URL" | | Goose | OPENAI_HOST env โ host root, no /v1 | | Zed | settings.json โ languagemodels.openaicompatible.<name>.api_url | | JetBrains AI Assistant | Settings โ AI Assistant โ third-party OpenAI-compatible URL | | Open Interpreter | --api_base flag | | llm (Datasette) | extra-openai-models.yaml โ api_base | | Crush (Charm) | crush.json โ providers.<id>.base_url (both formats) | | pi (earendil-works) ยท oh-my-pi | models.json / models.yml โ providers.<id>.baseUrl | | Hermes Agent (Nous) | ~/.hermes/config.yaml โ model.base_url |
โ ๏ธ Partial: Cursor (chat panel only โ agent/tab stay on Cursor's cloud), Codex CLI (Responses-API only now), gptme (OpenAI path only), openclaw (depends on its backend). โ Not a fit yet: Windsurf (no editable base URL), Inflection Pi (consumer app, not a coding agent).
Per-tool copy-paste setup, gotchas (/v1 vs bare host, dummy keys), and the partial/unsupported details โ docs/integrations.md.
Roadmap
- Pageโfault autoโreinjection โ when the model references a pagedโout id or signals it's missing content, restore it and retry automatically (partially shipped).
- Semantic dedup (shipped) โ nearโduplicate collapsing.
- Embedding judge โ local semantic scoring instead of the heuristic.
- Selfโcalibrating policy โ learn safe aggressiveness per repo from shadowโeval outcomes.
- Quality ledger โ auditable before/after + measuredโdegradation record.
docs/DESIGN-context-virtual-memory.md for the full design.
Limitations & honesty
- The default judge is a heuristic (word/char similarity), not a semantic oracle. Switch
shadowEval.judgeto"llm"for a modelโgraded score. Embedding judge isn't implemented yet. - Shadowโeval costs money โ it's a real extra upstream request, so it's sampled (5% default) and its cost is reported separately.
- Session inference is heuristic โ perโsession/perโrepo attribution is inferred from request metadata.
- Pageโfault recovery is limited for streaming responses.
- Cost figures are estimates โ only as accurate as your
pricing.json.
FAQ
How do I reduce Claude Code token usage and costs?
Point Claude Code at tokdiet instead of the model API directly. tokdiet is a local streaming reverse proxy that sits between your agent and the API, meters every token, and compacts bloated context before it hits the model:
npx tokdiet start # proxy :7787 + dashboard :7878 (loopback only)
export ANTHROPICBASEURL=http://localhost:7787
export OPENAIBASEURL=http://localhost:7787/v1
In our 66-task A/B benchmark on a real model (MiniMaxโM3), input tokens dropped from 5.07M to 1.46M (โ71%) while quality stayed at parity (baseline 64/66 vs governed 63/66). That is the mechanism behind claude code token optimization here: the proxy shrinks the context, not your workflow.
Note: there is also a Claude Code plugin (/plugin marketplace add agiwhitelist/tokdiet), but the plugin is only a metering hook โ it cannot set ANTHROPICBASEURL for the Claude Code process, so the plugin alone does not save tokens. The proxy is what cuts the bill.
Claude Code is too expensive โ will this actually save me money?
It depends on how you pay. Dollar savings apply to pay-per-token API keys (MiniMax, the Anthropic API, OpenAI), where fewer input tokens means a smaller bill. If you are on a flat Claude subscription there are no per-token charges to cut, so the value there is the metering, budgets, and live local dashboard โ you see exactly where tokens go, not a smaller invoice. For anyone hitting "claude code too expensive" on a metered API key, the context compression is where the cost-optimization comes from.
Is this a ccusage alternative?
Yes โ think of it as "ccusage that shrinks the bill." It does ccusage-style token and USD cost tracking, plus a live local dashboard, but it goes further: it is an active llm token cost proxy that compacts context to cut pay-per-token API spend, then runs shadow-eval to verify quality held. If you came looking for a ccusage alternative or a claude code usage monitor that does more than report, that is the difference โ measurement plus reduction.
Does compacting context make the model dumber?
In our testing, no โ quality held within model noise. The honest framing: this is "โ parity," not "lossless." On the 66-task benchmark, baseline scored 64/66 and governed 63/66; across 198 paired runs an LLM judge reported 92% similarity, and a second model (MiniMax-M2.5) confirmed โ72% tokens at parity. The ~1-2 task gap is model nondeterminism plus the model declining to echo a secret โ not context loss. The hardest "needle buried in junk" adversarial cases pass.
Three mechanisms keep it honest:
- shadow-eval re-runs a sampled fraction (5% by default) of compacted requests against the uncompacted baseline and scores divergence (0 = identical โฆ 100 = unrelated). This is the measurement.
- quality budget is a hard ceiling on measured degradation (default 2%); near it, the compactor restricts itself to the safest strategies.
- safe-mode disables any offending strategy per-strategy when rolling degradation exceeds budget. Savings stop before quality does.
Is the context compression lossless?
Not overall โ be precise here. Only dedup is loss-free: re-pasted blocks keep the freshest copy verbatim and replace earlier copies with a marker (it handles near-duplicates too). Elision is recoverable, not lossless: it pages out the bulk of old tool results to local SQLite while keeping a preview plus salient lines (errors, ids, KEY=VALUE pairs, URLs, paths, numbers), and stores the full body by id for recovery. We model context as virtual memory โ hot content (recent, pinned, question-relevant) stays resident; cold content is paged out as a recoverable stub, not deleted. A third strategy, mid-conversation summarize, is off by default and opt-in because it costs money.
Does it work with Cursor, Codex, and the Anthropic / OpenAI APIs?
Yes. tokdiet speaks the Anthropic Messages API, OpenAI Chat Completions, Gemini, and MiniMax โ plus any OpenAI-compatible or Anthropic-compatible API. Any tool that respects ANTHROPICBASEURL / OPENAIBASEURL works: Claude Code, Cursor, Codex, and custom scripts. So this doubles as a way to reduce Cursor token usage / track Cursor API cost and to do anthropic api cost reduce or openai api cost tracking, all through one self-hosted local proxy.
Will it break prompt caching or extended thinking?
No โ this is regression-tested. tokdiet is cache-aware: it never rewrites a cache_control prefix, so it won't break your Claude Code prompt cache. It is also thinking-safe: it never mutates signed/thinking blocks, so it won't trigger a 400 on extended thinking. Because it is a streaming reverse proxy, SSE is proxied incrementally โ tokens still stream live to your editor.
Do you store my API key?
No. API keys are forwarded only โ never written to SQLite and never written to any log. The proxy binds to loopback only (no external interface), and it is fail-open: if anything goes wrong in the pipeline, your request still reaches the API. It is self-hosted and local by design; the only thing persisted to SQLite is metering data and paged-out context bodies (kept by id for recovery), not credentials.
How is this different from LiteLLM or another LLM/AI gateway?
Most self-hosted llm api gateway / ai gateway tools route and log traffic. tokdiet is a litellm alternative focused on cost: it intercepts LLM API traffic as a reverse proxy, then actively does context compression and prompt compression to shrink llm context tokens, and proves the result with shadow-eval. The pipeline is: interceptor โ meter โ budget โ compactor โ quality guard โ store (SQLite) + dashboard. So it is a local llm proxy dashboard plus a context compression proxy in one, not just a passthrough router.
How do I verify the token savings myself?
Reproduce the benchmark: node bench/run.mjs (you need an API key in env). It runs a 66-task A/B across 6 categories, each task run twice โ full context (baseline) vs through tokdiet (governed) โ graded against the known answer, repeated x3 and majority-voted to cancel model noise. You will also see live token-usage and cost tracking on the dashboard at http://localhost:7878 as you work.
What are the known limitations?
Honest caveats: the default quality judge is a heuristic (an LLM judge is opt-in); shadow-eval costs money because it re-runs sampled requests; session detection is heuristic (inferred, not guaranteed); page-fault recovery is currently limited for streaming responses; and the per-request cost figures are estimates. tiktoken is used for token counting. tokdiet is MIT-licensed and built on TypeScript (Node 20+).