Skip to content
Agentic Control Plane

Claude Code Cost Tracking — What Exists, What's Missing, and How to Meter Every Session

David Crowe David Crowe · · Updated · 12 min read
claude-code cost tokens reference
Share X HN LinkedIn
Session cost X-ray of a real working day: $472.03 at API rates, 1,052 loop turns, 100% loop tax at a 100% cache hit rate, the cumulative bill curve, and 3,744 free tool calls beneath it — with 4,790 allowed, 6 denied, 115 PII findings

Just want the answer? Claude Code estimates a session total; it doesn't price calls. The ACP hook does, from the transcript Claude Code already writes:

curl -sf https://agenticcontrolplane.com/install.sh | bash
claude   # every model turn priced from the transcript; session X-ray in the console

Optional: launch with claude-acp to also route model calls through the proxy — on exit it prints the session total with a link to the breakdown:

ACP · session: 276 model calls · 1,697 tool calls · $148.16 @ API rates
→ https://cloud.agenticcontrolplane.com/sessions/…

Full Claude Code setup (both planes) →  ·  get a workspace key →  ·  free up to 5 agents

Claude Code is better at this than most harnesses. It will tell you a session’s estimated cost, put a dollar figure in your status line, and emit a cost metric over OpenTelemetry. What it won’t do is price a single call, tell you which part of the session the money went to, or produce a number that means anything on a Max subscription.

This is the reference for what you can see natively, what each surface can’t tell you, and the config that closes the gap.

What Claude Code shows natively

  • /usage — the Session block at the top shows total estimated cost, API duration, and usage by model for the current session. On Pro, Max, Team and Enterprise plans it also shows plan-usage bars and an attribution breakdown (skills, subagents, plugins, MCP servers). The docs are plain that the session cost figure is meant for API users; on a subscription it “isn’t relevant for billing.” Older builds called this /cost.
  • The status line — a statusLine script receives JSON on every refresh with cost.total_cost_usd, cost.total_duration_ms, cost.total_api_duration_ms, context_window.used_percentage, rate-limit percentages on subscription plans, and a prompt_cache block after the first response. One cumulative number per session, updated as it grows.
  • OpenTelemetry — set CLAUDE_CODE_ENABLE_TELEMETRY=1 plus the OTEL_* exporter variables and Claude Code emits claude_code.cost.usage (USD) and claude_code.token.usage (split by input, output, cache read, cache creation), tagged with model. With the logs exporter on, it also emits claude_code.tool_result and claude_code.tool_decision events per tool call. This is the most complete native surface, and it needs a collector on the other end.
  • The session transcripts — every session writes a JSONL file under ~/.claude/projects/. Community tools such as ccusage read those files and total the token counts against a price list. The schema isn’t documented, so those tools track the format rather than an API.

So the native answer to “what did that session cost?” is a session total, estimated, with a caveat on subscriptions. Better than nothing; not attribution.

What a session total can’t tell you

  1. Which calls the money went to. A session is a few hundred model calls. The total says $148.16; it doesn’t say that the last 28 turns bought 10% of the output, or that one re-read of a large file cost more than the edit it preceded. That needs a price on each call at the moment it’s made.
  2. Loop vs. leaf. In agent sessions the bill is mostly the orchestration loop re-reading its own context to pick the next step, not the leaf work that produces answers. In the July research corpus (285,814 metered calls across our own workspaces) the loop was 97% of spend. A token total can’t separate the two; per-call tagging can, and it changes which model you put on the loop.
  3. Cache economics per call. Cached input bills at a fraction of the full rate, so two sessions with the same token count can differ several-fold in dollars. The status line’s prompt_cache block gives you the session’s shape; only per-call metering shows the turn where the prefix stopped being cache-stable.
  4. The fleet. Native surfaces are per-machine and per-session. Cost by agent, cost by person, and run-to-run variance across a team live nowhere in Claude Code.
  5. A cap that holds. There is no native budget. A runaway loop surfaces on next month’s statement, or in the rate-limit bar after the money is gone.

The config

There are two ways to get per-call cost, and the first needs nothing but the hook.

From the transcript (default). Every PostToolUse hook call carries transcript_path, and the session JSONL records each assistant turn’s input_tokens, cache_read_input_tokens, cache_creation_input_tokens, output_tokens and model. The installed ACP hook reads the turns it hasn’t reported yet, sends them with the tool-output report it already makes, and the gateway prices each one at list rates with the cache rates applied. Plain claude, no launcher, no env var; on a subscription the figures are API-rate equivalents. Turns land beside the tool calls as loop turns, so the Session X-ray, loop-vs-leaf split and the daily ledger see them the same way they see proxied calls.

Through the proxy (optional). The proxy adds what a transcript can’t give you: policy on the model call itself (denied tool_use blocks stripped before the harness sees them) and the declared tool surface, captured from request bodies. Claude Code honors ANTHROPIC_BASE_URL. Point it at the ACP proxy and pass your workspace key as the auth token:

# ~/.zshrc, or the environment of whatever launches claude
export ANTHROPIC_BASE_URL="https://api.agenticcontrolplane.com/anthropic"
export ANTHROPIC_AUTH_TOKEN="$ACP_KEY"   # workspace key (gsk_…)

The one-command installer writes this for you as a launcher, ~/.acp/bin/claude-acp; plain claude keeps its normal model path and is still priced from the transcript. Either way each /v1/messages request passes through the proxy carrying the login you already have: a Max or Pro OAuth session stays subscription traffic, an API key stays API traffic. The usage fields on the way back are priced at list rates, and the call lands as a row in the console — model, tokens, cached share, dollars, and whether it was a loop turn or leaf work.

When a claude-acp session exits it prints the session’s bill and a link to its cost X-ray:

ACP · session: 276 model calls · 1,697 tool calls · $148.16 @ API rates
→ https://cloud.agenticcontrolplane.com/sessions/…

That line is from a real working day on a Max subscription; the page it links to shows the curve.

Subscription and API-key billing

The proxy never changes who pays. A subscription login is forwarded untouched and Anthropic bills the subscription as before; ACP labels every dollar figure for that traffic as an API-rate equivalent, which is what the same tokens would have cost through the API, not a charge. API-key traffic is billed by Anthropic at standard rates. ACP does not touch or mark up your tokens.

Budget limits

Claude Code has none. Through the proxy, workspace-billed traffic is subject to your workspace’s daily LLM cost cap, enforced at the gateway before the call goes upstream; the session halts rather than warns. Subscription and bring-your-own-key traffic is billed or quota-limited by Anthropic; ACP meters it but cannot enforce a cap on an account it doesn’t hold.

Troubleshooting

Calls work but nothing appears in the console. Check ANTHROPIC_AUTH_TOKEN is your ACP key, not an Anthropic key. The proxy needs the workspace key to attribute the call; without it the request is rejected rather than metered to nowhere.

/usage and the console disagree. They measure different things. /usage is Claude Code’s own estimate for the session; the console prices each call from the usage fields the API returned. On a subscription, only the console figure is labelled as an API-rate equivalent.

The status line shows cost but the console shows nothing. The status line reads Claude Code’s internal estimate and works without a proxy. Console rows need the base URL set in the environment of the process that launched claude; a value exported in one shell doesn’t reach an IDE-launched session.

OTel metrics stopped when I set the base URL. Unrelated: the docs note ANTHROPIC_BASE_URL is not passed to spawned subprocesses, but telemetry export is configured by the OTEL_* variables, which are. Check the collector endpoint first.

What this pairs with

Cost is one of the two planes. The other — controlling what Claude Code does — is the PreToolUse hook covered in the Claude Code hooks reference. They’re independent: the hook sees tool calls and never token usage; the proxy sees model calls and never what your shell actually ran. Ways to set up ACP wires both and tells you which planes you have.

Frequently asked questions

Does Claude Code track cost?

It estimates it. /usage shows a session total at list rates, the status line can display cost.total_cost_usd, and OpenTelemetry emits a claude_code.cost.usage metric. On a Pro or Max subscription the docs say the session figure isn’t relevant for billing. None of these price an individual call, attribute spend to the orchestration loop versus the leaf work, or roll up across a team’s agents.

How do I see what a Claude Code session actually costs at API rates?

Install the ACP hook. Claude Code hands it the session transcript, which records every model turn’s tokens and model; the hook reports each new turn and ACP prices it at list rates with cache rates applied, so plain claude sessions are priced with no launcher and no env var. The proxy path (ANTHROPIC_BASE_URL or the claude-acp launcher) remains for policy on the model call and the declared tool surface.

Does this work on a Max or Pro subscription?

Yes. The subscription login is forwarded untouched, so Anthropic bills you exactly as before. ACP prices each call at API list rates and labels the figures as API-rate equivalents, not charges.

Can I set a budget that stops a Claude Code session?

Not natively. Through the proxy, workspace-billed traffic is subject to a daily LLM cost cap enforced at the gateway before the call goes upstream. Subscription or bring-your-own-key traffic is billed by Anthropic; ACP meters it but cannot cap the upstream account.

What does the loop tax mean for a Claude Code session?

Most spend in an agent session is the orchestration loop re-reading its own context to choose the next step, not the answers. In one metered working day of Claude Code, 276 model calls cost $148.16 at API rates and the loop was all of it. A token total can’t show that; per-call attribution can.

If the hook can't see tokens, how does it price anything?

It reads them from the transcript Claude Code writes and hands to the hook. The PreToolUse hook itself sees only tool calls; the PostToolUse hook receives transcript_path, and the session JSONL carries every model turn’s usage. The proxy sees model requests directly and is the path for model-call policy and the declared tool surface.

Where to read more

Share X HN LinkedIn
Get the next data drop
What agents actually cost, new tool-surface captures, and the occasional incident post-mortem — sent when we publish something worth your inbox, not on a schedule. Unsubscribe anytime.
Share: Twitter LinkedIn
Related posts

← back to blog