How much CO2 does a Claude Code session actually emit?

작성자

카테고리:

← 피드로
DEV Community · gwittebolle · 2026-07-20 개발(SW)

I spend most of my working day inside Claude Code. At some point I started
wondering what that adds up to, physically. I just wanted a number next to
the session cost, something to glance at rather than feel bad about.

There is no official answer. Anthropic, like every frontier lab, does not
publish per-inference energy data. So I built the estimate myself, put it in
my status line, and open-sourced the whole thing as
claude-carbon. This post is
the methodology: where the numbers come from, what I had to estimate, and
where the estimate is weakest.

My own six months, measured by the tool: 893 sessions, roughly 970 kg CO2e.
About one economy seat on a one-way transatlantic flight. The median session
is ~200 g, the distribution has a long tail, and my worst single session was
68 kg. I would not have guessed any of those numbers within a factor of five.

The only measured data point

Everything starts from one paper: Jegham et al. 2025, “How Hungry is AI?”
(arxiv.org/abs/2505.09598). It measures
per-query inference energy for a range of models on AWS. For Claude 3.7
Sonnet it reports three configurations (PUE included):

Input tokens Output tokens Energy 100 300 0.950 Wh 1,000 1,000 2.989 Wh 10,000 1,500 5.671 Wh

Three points, two unknowns. Fit an ordinary least-squares regression through
the origin, with one coefficient for input tokens and one for output tokens,
and you get ~1.35e-4 Wh per input token and ~2.88e-3 Wh per output token.
The fit matches the two high-token configurations within 1%, which is the
regime real coding sessions live in.

Convert with the grid: Jegham et al. use the AWS region carbon intensity,
0.287 kgCO2e/kWh, location-based. That yields the two numbers everything
else hangs on:

  • 39 gCO2e per million input tokens
  • 826 gCO2e per million output tokens

The 21:1 ratio falls out of the fit rather than being assumed, though three
measured points give it real uncertainty. The direction, however, is solid.
FLOPs per token are similar in prefill and decode; what differs is hardware
utilization. Prefill processes
the whole prompt in parallel and saturates compute; each decode step
re-reads the weights and KV cache to produce a single token, so it is
memory-bandwidth-bound and burns more energy per token. The exact multiple
depends on batch size and serving stack.

Could this be wrong? I cross-checked against
EcoLogits, which estimates impact by a completely
independent route (parameter counts plus a lifecycle model, no AWS
telemetry). Their Sonnet band is ~565-1385 gCO2e per million output tokens.
826 sits inside it. Two unrelated methods landing in the same range is the
strongest corroboration available today.

Three model families are extrapolated, and here is how fragile that is

Only Sonnet has measured energy data. Everything else is inference from
weak signals, so let me rank the numbers by how much I trust them:

  • Sonnet: measured. Three points and a fit. The solid ground.
  • Opus: extrapolated, band 1.7x-5x Sonnet. The two available signals, EcoLogits’ parameter assumptions and Anthropic’s price ratio, both land around 1.7-2x, and that is where the tool sits (2x). The band stretches to 5x because neither signal is a measurement, so the likely error is upward.
  • Haiku: the most uncomfortable one. Jegham actually measured Haiku 3.5 higher than Sonnet, which is usually read as a serving artifact (latency-optimized serving, small batches). EcoLogits’ modern Haiku reads far lower. The tool uses 0.5x Sonnet. If you instead take the measurement at face value, Haiku lands near Sonnet and most of the “route small tasks to small models” gain evaporates. I chose the reading the physics supports, but you should know the other one exists.
  • Fable: the least reliable number in the tool. No measurement, no parameter estimate, only the list-price ratio (2x Opus), and price is a poor proxy for energy: providers price on what the market bears, and electricity is a small slice of it.

Why publish point values at all when the bands are this wide? Because a
status line needs one number. The mitigation is structural: the tool stores
raw token counts and derives the grams from them, so the day better data
lands, one script re-prices the entire history.

These are order-of-magnitude estimates and the repo labels them as such. If
you want a tool that pretends to three significant digits, this is not it.

The cache is the hard part

Nobody tells you this before you parse your own transcripts:
87% of my tokens are cache reads. Claude Code re-sends the conversation
prefix on every turn, and prompt caching means those tokens skip prefill
compute. So the factor you assign to a cached token dominates the headline
number more than any per-model factor does.

The tempting shortcut is Anthropic’s billing ratio: cache reads cost 0.1x
input. But a price is not an energy measurement (OpenAI prices the identical
mechanism at 0.5x). The honest answer is that no study measures this ratio
directly, so I derived an engineering estimate from adjacent measurements:
prefill accounts for under ~3.4% of total inference energy in generation
workloads, and decode energy per token grows with KV-cache size because
every generated token re-reads the entire cache from HBM. Cached tokens
skip prefill but still pay that decode-phase residual forever.

I use 0.08x with a documented defensible range of 0.05-0.15. It is a
single configurable constant, and it is the biggest lever in the whole
model. Setting it to 0 is a legitimate lower bound, but it declares a reused
100K-token system prompt carbon-free, which a memory bus somewhere would
dispute.

Counting tokens is its own bug hunt

Token counts come from Claude Code’s local JSONL transcripts. If you naively
sum message.usage over the lines, you over-count by roughly 3x. Resumed
and compacted sessions replay earlier messages into the same file, and
streaming rewrites the same message id with a growing output count. On my
data, 55% of assistant lines are replays. Deduplicate by
(message.id, requestId), keep the last occurrence, then sum.

One more trap: Claude Code purges transcripts after about 30 days. The tool
captures each session into SQLite when it ends, raw token breakdown
included, so when a factor is revised the entire
history can be re-priced with one script. Emission factors will keep
changing as measurements improve; raw tokens are forever.

Numbers you can’t silently break

Every factor and price in the repo is covered by golden vectors: 12
canonical sessions with hand-derived expected outputs, replayed against
data/factors.json in CI on every push. If someone (usually me) tweaks a
factor without updating the vectors and the written derivation in
METHODOLOGY.md, the build fails.

I added this after catching myself unable to reproduce my own earlier
numbers. Fact-checking the arithmetic ten times had not caught it, because
the arithmetic was fine; the derivation had drifted. If your project ships
numbers, put the derivation itself under test.

What it looks like day to day

The status line shows grams next to dollars, live:

claude-carbon ⌥ main | 🟢 Opus 4.7 ▓▓▓░░░░░░░ 35% | $1.72 · 101g CO₂ | Use 21% ↻13:00

Enter fullscreen mode Exit fullscreen mode

The change in my behavior is model routing (my usage certainly did not go
down): the family factors put small models several times below the big ones. I
won’t quote a precise ratio, because the inter-family ratios are the
weakest numbers in the model (they are the extrapolations described above).
The direction is robust though, and a visible number at
decision time makes “does this task need the big model?” a real question,
the same way the cost display already does.

Honest limitations

Inference only: no training amortization, no hardware manufacturing, no
water. The carbon intensity is a static grid average for a single region.
The cache-read factor is an engineering derivation with a documented
range. The right way to read any
session figure is “hundreds of grams, not tens of milligrams and not tens of
kilograms.”

If you use Claude Code, the install is one line and everything stays local
(SQLite, no telemetry, no account):

npx claude-carbon

Enter fullscreen mode Exit fullscreen mode

Repo and full methodology, sources included:
github.com/gwittebolle/claude-carbon.
If you find a flaw in the derivation, open an issue. The golden vectors make
corrections cheap, and being corrected with sources is the point of
publishing the method.

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다