claude-carbon is an open source Claude Code plugin that tracks the carbon footprint of your sessions: a live CO2 estimate in the status line, computed locally from your token usage, next to the session cost.
> /plugin marketplace add gwittebolle/claude-carbon> /plugin install claude-carbon@claude-carbon
Repo: gwittebolle/claude-carbon
What's inside
claude-carbon is an open source Claude Code plugin that tracks the carbon footprint of your sessions: a live CO2 estimate in the status line, computed locally from your token usage, next to the session cost.

~/.claude transcripts/carbon-report (text), /carbon-card (PNG), /carbon-pr (footprint of a pull request)1. Install (or update):
macOS, Linux, WSL:
curl -fsSL https://raw.githubusercontent.com/gwittebolle/claude-carbon/main/install.sh | bash
Windows (PowerShell), which needs Git for Windows and two packages first - see Windows:
irm https://raw.githubusercontent.com/gwittebolle/claude-carbon/main/install.ps1 | iex
Or, on any platform with Node.js:
npx claude-carbon
Same command to install and to update to the latest version (all three run the same installer).
Installed from Anthropic's community marketplace and the plugin fails to load? The
co2-tracker@claude-communityentry is pinned to a release from August 2026 that current Claude Code rejects ("Duplicate hooks file detected"). Run/plugin uninstall co2-tracker@claude-community, then install with one of the commands above.
2. Restart Claude Code. Your CO2 appears in the status line:
claude-carbon ⌥ main | 🟢 Opus 5 ▓▓▓░░░░░░░ 35% | $0.50 · 65g CO₂ | Use 24% ↻13:00
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%).
Where the CO2 shows up. The status line is a feature of the Claude Code terminal UI. It is displayed only when you run
claudein a terminal, including the integrated terminal of VS Code or JetBrains. The IDE extensions' chat panel has no status line at all, so nothing is displayed there even though the hooks still run and your sessions are recorded:/carbon-reportcovers them. If you use the VS Code panel and want the live CO2, open a terminal in VS Code (Ctrl+`) and runclaudefrom there. The web app (claude.ai/code) and the desktop app run neither the status line nor the hooks, so nothing is displayed or recorded there.
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:
rate_limits.five_hour.used_percentage in the statusline JSON, that value is used straight away.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.Accurate on every plan, including Max 20x.
3. Use the slash commands:
/carbon-report - text report with totals, equivalences, top sessions/carbon-card - generate shareable PNG report cards (requires playwright-core, see Dependencies)/carbon-update - update to the latest version and re-price history (see Updating)Generate yours with /carbon-card in Claude Code. The summary and detailed PNGs land in
~/Downloads/claude-carbon/ (the Windows Downloads folder follows the system setting, so a
OneDrive-redirected one is honoured) and the folder opens in your file manager, with the
card selected on macOS. CLAUDE_CARBON_EXPORT_DIR picks another folder;
CLAUDE_CARBON_NO_OPEN=1 skips the opening.
From the 1st to the 10th of each month the status line ends with 📊 August wrapped · /carbon-card:
the month just closed has its bar on the card, under the running total. Generating a card
clears it for the month; it goes quiet on its own after the 10th. CLAUDE_CARBON_CARD_NUDGE_UNTIL_DAY
moves the cut-off, CLAUDE_CARBON_NO_CARD_NUDGE=1 removes the nudge. Nothing is posted anywhere:
sharing stays a human decision.
# Since a specific date
bash ~/code/claude-carbon/scripts/generate-report.sh --since 2026-03-01
# All time
bash ~/code/claude-carbon/scripts/generate-report.sh --all
# A closed period (--until is an exclusive upper bound: this one stops at June 30th)
bash ~/code/claude-carbon/scripts/generate-report.sh --since 2026-01-01 --until 2026-07-01
curl -fsSL https://raw.githubusercontent.com/gwittebolle/claude-carbon/main/install.sh | CLAUDE_CARBON_DIR=~/my-path/claude-carbon bash
The env var has to sit on the bash side of the pipe, not the curl side, or the installer never sees it.
If you run a second Claude Code environment out of its own config directory, e.g.
alias claude-work="CLAUDE_CONFIG_DIR=~/.claude-work claude"
install claude-carbon into that same directory by passing CLAUDE_CONFIG_DIR to the installer:
curl -fsSL https://raw.githubusercontent.com/gwittebolle/claude-carbon/main/install.sh | CLAUDE_CONFIG_DIR=~/.claude-work bash
The status line, the hooks, the database and the /carbon-* commands all live under that config dir, so each environment tracks its own sessions independently. When CLAUDE_CONFIG_DIR is unset everything falls back to ~/.claude as before.
git clone https://github.com/gwittebolle/claude-carbon.git ~/code/claude-carbon
bash ~/code/claude-carbon/scripts/setup.sh
bash ~/code/claude-carbon/scripts/configure-settings.sh
The second script merges the block below into ~/.claude/settings.json (additively: an existing status line or third-party hooks are left alone) and symlinks the /carbon-* commands. To wire it by hand instead, skip it and add:
{
"statusLine": {
"type": "command",
"command": "~/code/claude-carbon/scripts/statusline.sh"
},
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/code/claude-carbon/scripts/persist-session.sh"
}
]
}
],
"SessionEnd": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/code/claude-carbon/scripts/persist-on-exit.sh"
}
]
}
],
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/code/claude-carbon/scripts/safety-rescan.sh"
}
]
}
]
}
}
The Stop hook records the session after each turn, and SessionEnd records it once more as it closes, so a last turn interrupted before Stop fired is still counted. The SessionStart one re-scans for sessions both missed (crash, kill) and drives the daily update check the status line reads; without it you are never told a new version exists.
Restart Claude Code.
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:
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.
The number reviewers rarely see is what the PR cost to develop: your local Claude Code sessions while building the branch. /carbon-pr (or scripts/generate-pr-report.sh) sums the recorded sessions of the current branch and posts one sticky comment on its open PR, through your own gh auth. Run it after your push; running it again updates the same comment in place.
**Claude Code carbon report** · developing this PR
124 g CO2e · $3.00 · 180k tokens · 1.5M cache reads · 2 sessions
How the sessions are attributed: the Stop hook stores each session's git branch (read from the transcript), and the report selects project + branch. Sessions recorded before this column existed carry no branch; scripts/backfill.sh repairs them while their transcripts are still on disk (about 30 days). Sessions started from a subdirectory of the repo are stored under the subdirectory's name and stay out of the sum. A session that ends on another branch than it started is attributed to where it finished.
Turning it off is the default: nothing is posted unless you run it. --dry-run previews the comment, --pr <number> targets a specific PR, and deleting the comment on GitHub is the full cleanup.
Three data paths, two levels of accuracy:
| Script | Trigger | Data source | Subagents | Cache reads | Accuracy |
|---|---|---|---|---|---|
backfill.sh | Manual / setup | JSONL files | Included | Counted (8% energy) | Best estimate |
persist-session.sh | Stop + SessionEnd hooks | JSONL files | Included | Counted (8% energy) | Best estimate |
statusline.sh | Every turn (live) | carbon.db row | Included | Counted (8% energy) | One turn late |
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.
FAQ
claude-carbon is a Claude Code plugin with 5 hand-picked skills for monitoring work, indexed on Flowy. Install it with the command on its page. It includes carbon-badge, carbon-card, carbon-pr. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.
Is this plugin yours?
Claim it with GitHubSubmit a pluginPromote it