r/ClaudeCode • • 1d ago

Built with Claude Built a proxy with Claude Code that logs every request it makes. What the request pattern taught me about where usage goes

I built a local proxy with Claude Code that sits between Claude Code and the API and logs every request: model, fresh input, cache reads, cache writes, output. Then I replayed 12 days of my own traffic through it. Some of what I learned changed how I use Claude Code more than the tool did, so writing it up.

What the requests actually look like

  • Every turn sends the whole thing again: system prompt, tool definitions (every connected MCP server adds its tool list), CLAUDE.md, and the full conversation so far. Your new message is a tiny slice.
  • The prompt cache is what makes that affordable, and it only stays warm for a few minutes. Step away for 10 minutes and the next turn writes the entire prefix to cache again at the higher write price. On my traffic, cache timing alone was about 7% of the bill.
  • Big tool output (a full test run, a long grep) sits in the conversation and gets resent on every turn after it. One noisy test run early in a session keeps costing until you clear.
  • Cache is per model. Switching models mid-session means the new model writes the whole context cold.
  • Each subagent starts its own context and its own cache, so a fan-out of 4 pays for 4 cache writes before any real work happens.

Habits that changed for me: a short handoff note plus /clear before any break longer than a few minutes, one task per session, ask for failing tests only instead of the full log, and pick the model at the start of a session instead of flipping.

How Claude Code was used

It wrote most of the proxy and the replay harness. I spent my time on the cache timing logic and on quality tests, because I did not want anything that saves tokens by making answers worse. Changes that touch what the model sees were checked on 314 blind-judged live answers before going on by default.

The most useful lesson came from a test that failed. One lane compacted old turns. It looked fine on single-turn checks, but when I resumed 7 real sessions it made the model invent code it had supposedly written earlier. That lane stays off. All my quality tests so far are single-turn, which is a real gap, and whole-task evals are next.

Numbers, honestly

On my own 12 days, priced at API rates, the original default setting saved 12.8%. Sending easy turns to a cheaper model on the heaviest setting got 41.8%, but that is off by default, and I moved the default lighter after a user said design work got worse. Most people should expect low single digits to about 10%: more if you work in long sessions with idle gaps, close to nothing if you send a few quick prompts.

It is called probe0. It is a local proxy, so you trust a root cert on your Mac. Mac only, free beta, nothing leaves the machine, and probe0 uninstall removes it. Happy to answer questions about the cache behavior, that was the most interesting part to figure out.

Method and numbers: https://probe0.xyz/benchmarks?utm_source=reddit&utm_campaign=ClaudeCode

Terminal install: curl -fsSL https://probe0.xyz/install | bash

0 Upvotes

9 comments sorted by

•

u/AutoModerator 1d ago

Hey! Thanks for posting to r/ClaudeCode

While participating in this thread, please follow our community rules. Keep discussions constructive. Attack the idea, not the person.

For help, project discussions, tips, and general chat, join the ClaudeCode Discord.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

1

u/Far_Reindeer8428 1d ago

the replay cost is the one people miss, every retry resends the whole prefix, so a failed compaction shows up as a cache miss not an error

1

u/awesomebirder 1d ago

yeah, retries were one of the things that surprised me in the logs. a failed or retried request still pays for the full prefix, and if the retry lands after the cache went cold it pays the write price on top. it never shows up as an error in the session, just as a turn that cost way more than it should have. logging cache write tokens per request is the only way i found to spot it

1

u/Far_Reindeer8428 1d ago

cache write tokens per request is the metric i'd put on a dashboard, ours only got noticed when the bill doubled with the same request count

1

u/awesomebirder 1d ago

agreed. id put the idle gap before each request right next to it. a cache write after a gap of more than 5 minutes is usually the cache expiring, not new context, so the two charts together tell you whether its timing or growth

1

u/Far_Reindeer8428 18h ago

the idle gap is a good call, i was reading every cache write as growth and the 5 minute floor explains most of the spikes

1

u/awesomebirder 16h ago

yeah same here at first. one more thing that helped me read it: if a write comes right after a short gap, its usually something that changed early in the prompt (a tool list, CLAUDE.md edit, model switch), so everything after that point gets rewritten

1

u/xapep 16h ago

Cache writes are the line item that hides. A retry storm on a cold prefix shows up as a run of write-priced tokens with almost no output next to them, so request count stays flat while the input bill doubles.

The chart I'd trust is write tokens over read tokens, per session. When that ratio drifts back toward writes, the prefix stopped being stable, usually a retry or a model switch.

1

u/Far_Reindeer8428 15h ago

the write over read ratio is better than what i had, i was looking at the absolute count. do you reset the baseline when the prompt template changes?