claude-carbon 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gaetan Wittebolle
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,322 @@
1
+ # claude-carbon
2
+
3
+ [![GitHub stars](https://img.shields.io/github/stars/gwittebolle/claude-carbon)](https://github.com/gwittebolle/claude-carbon/stargazers)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
5
+ [![GitHub release](https://img.shields.io/github/v/release/gwittebolle/claude-carbon)](https://github.com/gwittebolle/claude-carbon/releases)
6
+
7
+ Track the carbon footprint of your Claude Code sessions.
8
+
9
+ **1. Install (or update):**
10
+
11
+ ```bash
12
+ curl -fsSL https://raw.githubusercontent.com/gwittebolle/claude-carbon/main/install.sh | bash
13
+ ```
14
+
15
+ Or, if you have Node.js:
16
+
17
+ ```bash
18
+ npx claude-carbon
19
+ ```
20
+
21
+ Same command to install and to update to the latest version (both run the same installer).
22
+
23
+ **2. Restart Claude Code.** Your CO2 appears in the status line:
24
+
25
+ ```
26
+ claude-carbon โŒฅ main | ๐ŸŸข Opus 4.7 โ–“โ–“โ–“โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ 35% | $0.50 ยท 65g COโ‚‚ | Use 24% โ†ป13:00
27
+ ```
28
+
29
+ Segments, left to right: project + git branch, model + context window %, session cost + CO2, 5h block usage % + reset time. A ๐Ÿ”ฅ prefix appears when the sustained burn rate would overshoot 100% of the limit by the end of the 5h block (after a 15 min grace window, only once usage reaches 15%).
30
+
31
+ > **Terminal and IDE only.** claude-carbon runs through the Claude Code status line and shell hooks, which execute in the terminal CLI and IDE extensions. They do not run in the web app (claude.ai/code) or the desktop app, so no CO2 is displayed or recorded there.
32
+
33
+ **5h quota source.** The percentage comes directly from Anthropic's `/api/oauth/usage` endpoint (the same data Claude Code displays in `/usage`). No heuristic, no token-limit file to seed. Two sources in order:
34
+
35
+ 1. **stdin** (preferred): if Claude Code injects `rate_limits.five_hour.used_percentage` in the statusline JSON, that value is used straight away.
36
+ 2. **OAuth API fallback**: `GET https://api.anthropic.com/api/oauth/usage` with the bearer token from macOS Keychain, `CLAUDE_CODE_OAUTH_TOKEN`, or `~/.claude/.credentials.json`. Cached 60s in `~/.claude/claude-carbon/oauth-usage.json`.
37
+
38
+ Accurate on every plan, including Max 20x.
39
+
40
+ **3. Use the slash commands:**
41
+
42
+ - `/carbon-report` - text report with totals, equivalences, top sessions
43
+ - `/carbon-card` - generate shareable PNG report cards (requires `playwright-core`, see [Dependencies](#dependencies))
44
+ - `/carbon-update` - update to the latest version and re-price history (see [Updating](#updating))
45
+
46
+ ## What it does
47
+
48
+ - Adds a live CO2 estimate to the Claude Code status line, next to the session cost
49
+ - Persists each session to a local SQLite database
50
+ - Backfills historical data from existing `~/.claude` transcripts
51
+ - Two slash commands: `/carbon-report` (text) and `/carbon-card` (PNG)
52
+
53
+ ## Example report
54
+
55
+ <p align="center">
56
+ <img src="docs/example-report-v2.png" alt="Claude Carbon Report" width="540">
57
+ </p>
58
+
59
+ Generate yours with `/carbon-card` in Claude Code. Exports summary and detailed PNGs to `exports/`.
60
+
61
+ <details>
62
+ <summary>Advanced options (CLI)</summary>
63
+
64
+ ```bash
65
+ # Since a specific date
66
+ bash ~/code/claude-carbon/scripts/generate-report.sh --since 2026-03-01
67
+
68
+ # All time
69
+ bash ~/code/claude-carbon/scripts/generate-report.sh --all
70
+ ```
71
+
72
+ </details>
73
+
74
+ <details>
75
+ <summary>Custom install directory</summary>
76
+
77
+ ```bash
78
+ CLAUDE_CARBON_DIR=~/my-path/claude-carbon curl -fsSL https://raw.githubusercontent.com/gwittebolle/claude-carbon/main/install.sh | bash
79
+ ```
80
+
81
+ </details>
82
+
83
+ <details>
84
+ <summary>Manual install</summary>
85
+
86
+ ```bash
87
+ git clone https://github.com/gwittebolle/claude-carbon.git ~/code/claude-carbon
88
+ bash ~/code/claude-carbon/scripts/setup.sh
89
+ ```
90
+
91
+ Then add to `~/.claude/settings.json`:
92
+
93
+ ```json
94
+ {
95
+ "statusLine": {
96
+ "type": "command",
97
+ "command": "~/code/claude-carbon/scripts/statusline.sh"
98
+ },
99
+ "hooks": {
100
+ "Stop": [
101
+ {
102
+ "matcher": "",
103
+ "hooks": [
104
+ {
105
+ "type": "command",
106
+ "command": "~/code/claude-carbon/scripts/persist-session.sh"
107
+ }
108
+ ]
109
+ }
110
+ ]
111
+ }
112
+ }
113
+ ```
114
+
115
+ Restart Claude Code.
116
+
117
+ </details>
118
+
119
+ ## For teams
120
+
121
+ claude-carbon measures one developer's sessions, locally. If the question comes from your CTO, a client RFP or a CSR committee, the same methodology exists as a hosted layer:
122
+
123
+ - [Free calculator and per-model factor sheets](https://tokenclimate.com/calculator) - the exact versioned factors of this repo, browsable.
124
+ - [Bilan IA](https://tokenclimate.com/bilan) - a self-serve, shareable report of your organisation's real Claude usage (cost, CO2e, water, energy), generated in minutes from an Anthropic admin key. The key is never stored; the methodology annex is citation-ready.
125
+ - [TokenClimate](https://tokenclimate.com) - hosted team dashboards. Both sides share this repo's golden vectors, verified weekly in CI.
126
+
127
+ The only places the OSS points there are a one-line footer in `/carbon-report` and a small credit on the `/carbon-card` PNGs. No status-line promo, no email capture: nothing leaves your machine.
128
+
129
+ ## How it works
130
+
131
+ ![Data flow](docs/data-flow.png)
132
+
133
+ **Three data paths, two levels of accuracy:**
134
+
135
+ | Script | Trigger | Data source | Subagents | Cache reads | Accuracy |
136
+ | -------------------- | ----------------------- | --------------------- | ------------ | ------------------- | ------------- |
137
+ | `backfill.sh` | Manual / setup | JSONL files | Included | Counted (8% energy) | Best estimate |
138
+ | `persist-session.sh` | Stop hook (session end) | JSONL files | Included | Counted (8% energy) | Best estimate |
139
+ | `statusline.sh` | Every turn (live) | `context_window` JSON | Not included | Included (approx) | Approximate |
140
+
141
+ **backfill** and **persist-session** parse the raw JSONL transcripts (main session + subagent files), applying per-model emission factors. They deduplicate assistant messages by `(message.id, requestId)`, so resumed and compacted sessions are not double-counted (this matches `ccusage`; without it the token sum inflates roughly 3x). Each session stores its raw token breakdown (input, cache write, cache read, output), which feeds the SQLite database used by reports.
142
+
143
+ **Cost** is the theoretical API list value (pay-as-you-go), not your subscription price: input, output, cache write (1.25x input), and cache read (0.1x input) at current Anthropic rates, set in `data/prices.json`. On deduplicated data it matches `ccusage`.
144
+
145
+ **statusline** reads `context_window.total_input_tokens` from Claude Code at each turn. This value represents the current context size (not a cumulative total), includes cache reads, and does not account for subagent tokens. It's an indicative live display, not a data source for reports.
146
+
147
+ ### Surviving the 30-day transcript purge
148
+
149
+ Claude Code deletes JSONL transcripts after about 30 days, so the SQLite database is the durable record. The `Stop` hook captures each session before its transcript ages out, and a once-a-day background re-scan (`SessionStart` hook, `safety-rescan.sh`) catches any session the `Stop` hook missed while its transcript still exists. Because each row stores raw token counts, `recompute.sh` regenerates cost and CO2 from `data/factors.json` + `data/prices.json` at any time, with no transcript needed. When Anthropic changes a price or a factor is revised, edit the config and run:
150
+
151
+ ```bash
152
+ bash scripts/recompute.sh
153
+ ```
154
+
155
+ ## Commands
156
+
157
+ | Command | What it does |
158
+ | ---------------- | --------------------------------------------------- |
159
+ | `/carbon-report` | Text report with totals, equivalences, top sessions |
160
+ | `/carbon-card` | Generate shareable PNG report cards |
161
+ | `/carbon-update` | Update to the latest version and re-price history |
162
+
163
+ <details>
164
+ <summary>Scripts (run automatically, rarely needed manually)</summary>
165
+
166
+ | Script | What it does |
167
+ | -------------------- | ----------------------------------------------------------------------------------------- |
168
+ | `setup.sh` | Init database, backfill historical sessions, show total |
169
+ | `statusline.sh` | Status line script (called automatically by Claude Code) |
170
+ | `persist-session.sh` | Stop hook (saves session data on exit) |
171
+ | `safety-rescan.sh` | SessionStart hook (throttled background re-scan, catches missed sessions) |
172
+ | `backfill.sh` | Re-parse all historical JSONL transcripts (incl. subagents) |
173
+ | `recompute.sh` | Re-derive cost/CO2 from stored tokens after a price/factor change (no transcripts needed) |
174
+ | `generate-report.sh` | Export PNG report cards (CLI, with `--since` / `--all`) |
175
+
176
+ Note: backfill now derives project names from the transcript's `cwd` (matching the live hook). Sessions backfilled before this change keep their old, possibly truncated names; delete those rows and re-run `backfill.sh` to normalize them.
177
+
178
+ </details>
179
+
180
+ ## Emission factors
181
+
182
+ Factors from [Jegham et al. 2025](https://arxiv.org/abs/2505.09598), a peer-reviewed study measuring energy consumption of LLM inference on AWS infrastructure.
183
+
184
+ | Model | Input (gCO2e/Mtok) | Output (gCO2e/Mtok) | Basis |
185
+ | ------ | ------------------ | ------------------- | -------------------------- |
186
+ | Fable | 156 | 3304 | Extrapolated (2x Opus) |
187
+ | Opus | 78 | 1652 | Extrapolated (2x Sonnet) |
188
+ | Sonnet | 39 | 826 | 3-point fit (Jegham v6) |
189
+ | Haiku | 20 | 413 | Extrapolated (0.5x Sonnet) |
190
+
191
+ **Important: these are order-of-magnitude estimates, not precise measurements.**
192
+
193
+ - Sonnet factors are a 3-point least-squares fit to the three measured Claude 3.7 Sonnet per-query energies in Jegham et al. v6 (0.950 / 2.989 / 5.671 Wh), giving a ~21:1 output:input ratio. The value is cross-validated against [EcoLogits](https://ecologits.ai): its independent estimate for Sonnet brackets the same range. Fable, Opus and Haiku are extrapolated (no public data from Anthropic on per-model energy consumption); Opus = 2x Sonnet matches both the current EcoLogits Opus 4.5+ parameter ratio and the Anthropic price ratio (honest band 2x-5x).
194
+ - Sessions run on non-Anthropic models (e.g. local models behind `ANTHROPIC_BASE_URL`) are stored with their raw tokens but zero cost/CO2 and excluded from reports - a datacenter factor doesn't apply to them. Add patterns to `exclude_models` in `data/factors.json` to exclude more models by name.
195
+ - Cache read tokens are counted at a reduced factor (default 0.08 of an input token, set in `data/factors.json`). A cached token skips prefill compute but still incurs decode-phase memory reads, so it is cheap but not free. This is an engineering estimate derived from the literature, not Anthropic's 0.1x billing ratio. See [METHODOLOGY.md](METHODOLOGY.md).
196
+ - Carbon intensity uses the AWS region grid (location-based, 0.287 kgCO2e/kWh), not real-time grid data. This sits at the low end of the location-based range; the US national average is ~380 g/kWh.
197
+ - Anthropic does not publish Scope 1, 2, or 3 emissions. These estimates are independent and based on academic research, not provider data.
198
+
199
+ Factors are editable in `data/factors.json`. See [METHODOLOGY.md](METHODOLOGY.md) for the full scientific basis, formula, and equivalences.
200
+
201
+ ### Golden vectors
202
+
203
+ The methodology is pinned by golden test vectors in [`tests/methodology-vectors.json`](tests/methodology-vectors.json): hand-computed expected CO2/cost values for known token breakdowns, replayed by `bash tests/run-vectors.sh` in CI on every push. Downstream consumers (such as TokenClimate) keep a copy of this file and verify weekly that their implementation produces the same numbers. If you edit `data/factors.json` or `data/prices.json`, update the vectors in the same commit, otherwise CI fails.
204
+
205
+ ## Updating
206
+
207
+ When a newer version is available, the status line shows a discreet `โฌ† /carbon-update` hint. The check runs in the background (at most once a day, never on the status line's hot path); opt out with `CLAUDE_CARBON_NO_UPDATE_NOTIFIER=1`.
208
+
209
+ To update, run `/carbon-update` in Claude Code, or re-run the installer:
210
+
211
+ ```bash
212
+ curl -fsSL https://raw.githubusercontent.com/gwittebolle/claude-carbon/main/install.sh | bash
213
+ ```
214
+
215
+ - Updating re-prices your stored history with the new factors automatically (CO2 only; cost figures are left intact). Run `scripts/recompute.sh --with-cost` yourself only after a price change.
216
+ - If you edited `data/factors.json` or `data/prices.json` locally, the update keeps your edits; on a conflict with upstream it saves yours to `*.local.bak` and tells you.
217
+ - Installed via the plugin marketplace? Update with Claude Code's built-in `/plugin update` instead.
218
+
219
+ ## Dependencies
220
+
221
+ - `jq` - JSON parsing
222
+ - `sqlite3` - local database
223
+ - `git` - branch detection in status line (optional)
224
+ - `curl` - 5h quota usage via Anthropic's `/api/oauth/usage` endpoint (optional, 60s cache)
225
+ - `playwright-core` + Chromium - PNG export for `/carbon-card` (optional)
226
+
227
+ `jq` and `sqlite3` are pre-installed on macOS. On Linux: `apt install jq sqlite3`.
228
+
229
+ To use `/carbon-card`, install Playwright and its Chromium browser:
230
+
231
+ ```bash
232
+ npm install -g playwright-core
233
+ npx playwright install chromium
234
+ ```
235
+
236
+ ## Reduce your footprint
237
+
238
+ Measuring is step one. Here are concrete levers to reduce your AI carbon footprint, ranked by impact.
239
+
240
+ ### Use the right model for the task
241
+
242
+ Output tokens cost ~21x more energy than input tokens (the marginal output:input ratio from Jegham v6). Opus consumes ~2x more than Sonnet per token.
243
+
244
+ ```json
245
+ {
246
+ "env": {
247
+ "CLAUDE_CODE_SUBAGENT_MODEL": "claude-haiku-4-5"
248
+ }
249
+ }
250
+ ```
251
+
252
+ Use Opus for architecture and planning. Sonnet for daily work. Haiku for subagents (exploration, file reading, reviews). This alone can cut your emissions by 60%.
253
+
254
+ ### Install RTK (Rust Token Killer)
255
+
256
+ [RTK](https://github.com/rtk-ai/rtk) is a CLI proxy that filters noise from shell outputs (progress bars, verbose logs, passing tests) before they hit the context window. 60-90% token reduction on CLI commands, zero quality loss.
257
+
258
+ ```bash
259
+ brew install rtk-ai/tap/rtk
260
+ rtk init -g
261
+ ```
262
+
263
+ ### Reduce thinking tokens
264
+
265
+ Claude's extended thinking can use up to 32k hidden tokens per message. Capping it reduces consumption without degrading quality on routine tasks.
266
+
267
+ ```json
268
+ {
269
+ "env": {
270
+ "MAX_THINKING_TOKENS": "10000"
271
+ }
272
+ }
273
+ ```
274
+
275
+ ### Compact earlier
276
+
277
+ By default, Claude Code compacts context at 95% usage. Compacting earlier keeps context cleaner and avoids bloated sessions.
278
+
279
+ ```json
280
+ {
281
+ "env": {
282
+ "CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "50"
283
+ }
284
+ }
285
+ ```
286
+
287
+ ### Write concise instructions
288
+
289
+ Add to your project's CLAUDE.md:
290
+
291
+ ```
292
+ Be concise. No preamble, no summaries unless asked.
293
+ ```
294
+
295
+ Output tokens are the most expensive in both cost and energy.
296
+
297
+ ### Combined impact
298
+
299
+ | Lever | Estimated reduction |
300
+ | -------------------- | ----------------------- |
301
+ | Right model per task | -60% vs all-Opus |
302
+ | RTK | -70% on CLI tokens |
303
+ | Thinking cap at 10k | -70% on thinking tokens |
304
+ | Haiku subagents | -80% on exploration |
305
+ | **All combined** | **-50 to 70% total** |
306
+
307
+ ### Further reading
308
+
309
+ - [IEA - Energy and AI (2025)](https://www.iea.org/reports/energy-and-ai/) - data center projections
310
+ - [Jegham et al. - How Hungry is AI?](https://arxiv.org/abs/2505.09598) - per-model energy measurements
311
+ - [UCL/UNESCO - 90% AI energy reduction](https://www.ucl.ac.uk/news/2025/jul/practical-changes-could-reduce-ai-energy-demand-90) - frugal AI approaches
312
+ - [GreenIT.fr - AI impacts 2025-2030](https://www.greenit.fr/impacts-ia-monde-2025-2030-rapport/) - French data
313
+
314
+ ## Why
315
+
316
+ Every Claude Code session uses real compute, real energy, real emissions. The number is small per query, but it adds up. Making it visible is the first step to owning it.
317
+
318
+ ## Open source
319
+
320
+ claude-carbon is free and open source under the [MIT license](LICENSE). Contributions welcome.
321
+
322
+ Built by [Gaetan Wittebolle](https://github.com/gwittebolle).
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env node
2
+ // npx claude-carbon โ€” thin wrapper around the git-based installer.
3
+ // Downloads install.sh from the repo and runs it; the plugin itself
4
+ // lives in a git clone, not in this npm package.
5
+
6
+ "use strict";
7
+
8
+ const { spawnSync } = require("node:child_process");
9
+ const { mkdtempSync, writeFileSync } = require("node:fs");
10
+ const { tmpdir } = require("node:os");
11
+ const { join } = require("node:path");
12
+ const pkg = require("../package.json");
13
+
14
+ const INSTALL_URL =
15
+ process.env.CLAUDE_CARBON_INSTALL_URL ||
16
+ "https://raw.githubusercontent.com/gwittebolle/claude-carbon/main/install.sh";
17
+
18
+ const arg = process.argv[2];
19
+
20
+ if (arg === "--version" || arg === "-v") {
21
+ console.log(pkg.version);
22
+ process.exit(0);
23
+ }
24
+
25
+ if (arg === "--help" || arg === "-h") {
26
+ console.log(`claude-carbon ${pkg.version}
27
+ Track the carbon footprint of your Claude Code sessions.
28
+
29
+ Usage: npx claude-carbon [--dry-run]
30
+
31
+ Downloads and runs the installer from:
32
+ ${INSTALL_URL}
33
+
34
+ Options:
35
+ --dry-run Download the installer and print its path without running it
36
+ --version Print the wrapper version
37
+ --help Show this help
38
+
39
+ Docs: ${pkg.homepage}`);
40
+ process.exit(0);
41
+ }
42
+
43
+ if (arg !== undefined && arg !== "--dry-run") {
44
+ console.error(`Unknown option: ${arg}\nTry: npx claude-carbon --help`);
45
+ process.exit(2);
46
+ }
47
+
48
+ async function main() {
49
+ if (process.platform === "win32") {
50
+ console.error(
51
+ "claude-carbon needs bash (macOS or Linux); Windows is not supported yet.",
52
+ );
53
+ process.exit(1);
54
+ }
55
+
56
+ const res = await fetch(INSTALL_URL);
57
+ if (!res.ok) {
58
+ console.error(
59
+ `Could not download the installer (HTTP ${res.status}): ${INSTALL_URL}`,
60
+ );
61
+ process.exit(1);
62
+ }
63
+ const script = await res.text();
64
+
65
+ const file = join(
66
+ mkdtempSync(join(tmpdir(), "claude-carbon-")),
67
+ "install.sh",
68
+ );
69
+ writeFileSync(file, script, { mode: 0o700 });
70
+
71
+ if (arg === "--dry-run") {
72
+ console.log(`Downloaded installer to ${file} (not run: --dry-run)`);
73
+ process.exit(0);
74
+ }
75
+
76
+ const { status, error } = spawnSync("bash", [file], { stdio: "inherit" });
77
+ if (error) {
78
+ console.error(`Could not run bash: ${error.message}`);
79
+ process.exit(1);
80
+ }
81
+ process.exit(status ?? 1);
82
+ }
83
+
84
+ main().catch((err) => {
85
+ console.error(err && err.message ? err.message : String(err));
86
+ process.exit(1);
87
+ });
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "claude-carbon",
3
+ "version": "1.1.1",
4
+ "description": "Track the carbon footprint of your Claude Code sessions",
5
+ "bin": {
6
+ "claude-carbon": "bin/claude-carbon.js"
7
+ },
8
+ "files": [
9
+ "bin"
10
+ ],
11
+ "homepage": "https://github.com/gwittebolle/claude-carbon#readme",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/gwittebolle/claude-carbon.git"
15
+ },
16
+ "bugs": "https://github.com/gwittebolle/claude-carbon/issues",
17
+ "author": "Gaetan Wittebolle (https://github.com/gwittebolle)",
18
+ "license": "MIT",
19
+ "keywords": [
20
+ "carbon-footprint",
21
+ "sustainability",
22
+ "claude-code",
23
+ "claude",
24
+ "green-it",
25
+ "co2"
26
+ ],
27
+ "engines": {
28
+ "node": ">=18"
29
+ }
30
+ }