I ran the same baseline Claude Code project through the VSCode extension, a VSCode-internal terminal, and a standalone terminal, then measur
---
title: "I Measured Claude Code's Prompt-Cache Cost Three Ways. 85% of It Wasn't Mine to Trim."
published: true
tags: claudecode, anthropic, llm, abotwrotethis
description: "I ran the same baseline Claude Code project through the VSCode extension, a VSCode-internal terminal, and a standalone terminal, then measur"
---
> *AI disclosure: This is an adapted English version of an essay I first wrote in Japanese, on Qiita. I worked with AI to shape and translate the piece; the script, the measurements, and the conclusions are my own.*
I ran the same empty Claude Code project through three launch paths and read the cache tokens off the session log after every turn. One of those paths never touched the shared server-side cache at all — `cache_read` stayed at 0 on every run.
**TL;DR: the launch path (VSCode extension, VSCode-internal terminal, or a standalone terminal like iTerm2) decides whether Claude Code hits Anthropic's shared prompt cache. And even after trimming CLAUDE.md files, skills, and hooks, roughly 85% of the remaining `cache_creation` cost turned out to be Claude Code's own fixed overhead — not anything I control.**
Claude Code writes a JSONL log for every session under `~/.claude/projects/<project-key>/`, and each assistant turn in that log carries a `usage` object with `cache_creation_input_tokens` and `cache_read_input_tokens`. To see what was actually happening turn by turn instead of guessing from the monthly bill, I wrote a short script that reads the newest session log for the current project directory and prints those two numbers per turn.
#!/usr/bin/env python3
import json, os
from pathlib import Path
project_key = os.getcwd().replace("/", "-")
project_dir = Path.home() / ".claude/projects" / project_key
jsonl_files = sorted(project_dir.glob("*.jsonl"), key=lambda f: f.stat().st_mtime, reverse=True)
jsonl_path = jsonl_files[0]
turn = 0
for line in jsonl_path.read_text().splitlines():
try:
e = json.loads(line)
usage = e.get("message", {}).get("usage", {})
role = e.get("message", {}).get("role", "")
if usage and role == "assistant":
turn += 1
print(f"turn {turn}: input={usage.get('input_tokens',0)} cache_create={usage.get('cache_creation_input_tokens',0)} cache_read={usage.get('cache_read_input_tokens',0)}")
if turn >= 2:
break
except Exception:
passI saved it as `measure-cache.py` and ran it from inside a baseline project — no CLAUDE.md, no hooks, no skills — right after opening a fresh session, then ran the exact same baseline through three different launch paths: the VSCode extension's chat panel, a terminal opened inside VSCode running the Claude Code CLI, and a standalone terminal (iTerm2) running the same CLI outside VSCode entirely.
**Same project, three launch paths:**
| launch path | cache_creation | cache_read |
|---|---|---|
| VSCode
// artículos relacionados
Twitter/X: @elder_plinius @LYSIOS The timing makes the contrast hard to miss: Anthropic is IPO-ing at $70–78…
Twitter/X: @JakeDSBD24 @Kevin_Logan @bot People that had ultra like my self down graded to the $30 to keep t…
Twitter/X: Just tried the free version of Claude to create a SaaS launch video, and the results are CRAZY. …