# AI Energy Impact Analyzer

**Understand the energy, carbon, and real-dollar footprint of your Claude API
usage — in plain language, from data you already have.**

If you run a small business (or just your own projects) on LLMs and feel
uneasy about their energy consumption and carbon footprint, this package turns
your Anthropic billing exports into an honest sustainability report:

- ⚡ **Energy** — estimated kWh consumed by your API usage
- 🌍 **Carbon** — estimated kg of CO₂ that energy produced
- 💰 **Energy cost & "energy tax"** — what that electricity costs, plus an
  internal carbon price you can use to budget for offsets
- 🎯 **Recommendations** — concrete ways to cut the footprint (cache usage,
  model right-sizing)

No API keys, no telemetry, no network calls. Everything runs locally against
CSV files.

**License:** MIT (see [`ai/LICENSE`](./LICENSE)) — free to use, modify, and
redistribute, including outside this repository. This differs deliberately
from `theunpartyrunway`'s repo-wide [Hippocratic-3.0](../LICENSE.md)
license: this package is meant to stand on its own and be useful to anyone,
independent of the rest of `theunpartyrunway`. Every
[`ae-v*` release](https://github.com/unparty-app/theunpartyrunway/releases)
bundles this README, the license, and the package's three Python files as
downloadable assets for exactly that reason.

## Honesty first: these are estimates

Anthropic (like every major provider) publishes **no per-model energy data**.
This tool builds research-calibrated estimates instead, and every report
discloses its own limitations:

1. **Per-token energy is estimated** from public research on comparable
   models ([Epoch AI](https://epoch.ai/gradient-updates/how-much-energy-does-chatgpt-use),
   [Google's Gemini efficiency paper](https://arxiv.org/abs/2508.15734),
   [ML.Energy leaderboard](https://ml.energy/leaderboard/)), scaled by model
   tier (Haiku < Sonnet < Opus/Fable).
2. **Token counts may themselves be estimates.** If you only have dollar-cost
   exports (no token counts), tokens are reverse-estimated from
   [Anthropic's published pricing](https://platform.claude.com/docs/en/about-claude/pricing) —
   an estimate built on an estimate. The report labels which mode it used.
3. **Grid carbon intensity varies by region.** The default (386 gCO₂/kWh) is
   the US grid average from [EPA eGRID](https://www.epa.gov/egrid); the
   default electricity rate ($0.134/kWh) is the
   [EIA US commercial average](https://www.eia.gov/electricity/monthly/).
   Both are configurable if you know your region or provider's numbers.

Treat totals as **order-of-magnitude indicators** for decision-making — good
enough to compare months, spot cache-efficiency problems, and budget for
offsets; not a substitute for a provider-published audit.

## Quickstart

Requires Python 3.9+ (standard library only — no third-party dependencies).

```bash
# From the repository root:
python3 ai/ai_energy_impact_analyzer.py            # full analysis + reports
python3 ai/ai_energy_impact_analyzer.py --check-freshness   # CI-friendly staleness gate
python3 ai/ai_energy_cli.py analyze                # friendlier CLI front-end
python3 ai/ai_energy_cli.py quick                  # one-glance summary of last run
python3 ai/ai_energy_cli.py models                 # compare model energy profiles
python3 ai/ai_energy_cli.py dashboard              # combine cost + energy views
```

Outputs land in `docs/`:

- `ai_energy_impact_analysis_<timestamp>.json` — full machine-readable report
- `ai_energy_impact_report_<timestamp>.md` — human-readable summary

## Feeding it your data

**Drop every Console export you have into `claude/`, under whatever name it
downloads with.** The analyzer reads every CSV in that folder and classifies
each one by its header row, not its filename — there's no naming convention
to memorize and no separate folder for a different export type:

| Schema (by header columns) | Treated as | Notes |
|------|------|-------|
| Has `usage_date_utc`, `model_version`, `usage_input_tokens_no_cache`, `usage_output_tokens` | **Measured token export** (best) | All matching files are merged. If any exist, they're used exclusively — see precedence below. |
| Has `usage_date_utc`, `model`, `cost_usd` | **Cost export** | Tokens are reverse-estimated from dollars. All matching files are merged. |
| Neither | Ignored | Reported by name under *CSVs in claude/ ignored* in the Data Sources & Quality section, so a misclassified file is visible, not silently dropped. |

If none of the above are found, `LLM/LLM.py`'s baseline module (if present)
is tried as a last-resort fallback.

**Precedence: measured token exports always win over cost exports**, even
when both exist for the same or an overlapping period — a dollar-based
estimate is strictly less accurate than a measured token count, so it's
never preferred just for being newer. Every report's *Data Sources &
Quality* section states in plain text which files were **found** vs. which
were **actually used** this run, so this is never ambiguous after the fact.

Cost-export rows that aren't token line items (e.g. `web_search` fees, rows
with model `--`) are skipped and counted in the report's *Data Sources &
Quality* section, not silently mixed into energy math.

(A legacy `data/claude_api_tokens_master.csv` file, if present from an
earlier setup, is still read in addition to `claude/`.)

## Model coverage

Profiles ship for the full Claude lineup (Haiku 3.5→4.5, Sonnet 3.5→5,
Opus 3→5, Fable/Mythos 5.x). Model names are matched by **family +
generation**, so `Claude Opus 4`, `claude-opus-4-1-20250805`, and
`claude 3 opus` all resolve correctly.

- **Unknown generation, known family** (e.g. a future "Claude Opus 9") → uses
  that family's newest known profile, and the report discloses the fallback.
- **Completely unrecognized model** → uses a mid-tier default profile
  (`claude-sonnet-5`), prints a warning, and the report lists the model under
  *Unrecognized models* so it can't silently skew results.

Historical note: earlier versions of this script had a matching bug where any
Opus usage silently fell through to Sonnet's (much lower) energy constants.
That path is now impossible — Opus resolves to Opus, and regression tests
(`tests/test_ai_energy_impact_analyzer.py`) keep it that way.

## Configuration

Constants live at the top of `ai/ai_energy_impact_analyzer.py` with citations
(`MODEL_ENERGY_PROFILES`, `MODEL_PRICING_USD_PER_1M_TOKENS`,
`CARBON_INTENSITY_G_PER_KWH`, `ENERGY_COST_RATES_USD_PER_KWH`,
`CARBON_PRICE_USD_PER_KG`). Per-run overrides:

```python
from ai.ai_energy_impact_analyzer import AIEnergyImpactAnalyzer

analyzer = AIEnergyImpactAnalyzer(
    carbon_intensity_g_per_kwh=125.0,   # e.g. a low-carbon cloud region
    energy_cost_usd_per_kwh=0.31,       # e.g. EU commercial rates
    staleness_max_age_days=60,
)
report = analyzer.generate_report()
```

## Data freshness

A report is only as good as the data behind it. The analyzer checks the age
of the newest usage record (default threshold: **45 days**, covering monthly
exports plus grace):

- Stale data ⇒ a ⚠️ banner at the top of every report, a console warning, and
  freshness metadata in the JSON output.
- `--check-freshness` exits non-zero when stale, so CI can annotate or gate.
- `--max-age-days N` adjusts the threshold.

There is no live API call anywhere in this pipeline — every source in the
priority list above is a file someone exported by hand. A stale warning
means exactly one thing: it's time to export a new file. This applies
identically inside or outside the unparty-app org; nothing here is
org-specific.

### How to refresh it

1. **Export usage data from the Anthropic Console.**
   Go to your organization's Console (`https://console.anthropic.com`), under
   Usage. Pick either report type — you can export both:
   - **Cost report** → dollar-based, tokens reverse-estimated.
   - **Usage/token report** (if your Console plan exposes per-model token
     counts) → measured tokens, no estimation. Preferred when available.
   Set the date range to cover the gap since the last export, and download
   as CSV.

2. **Drop the file straight into `claude/` — no renaming.**
   ```bash
   mv ~/Downloads/<whatever-the-console-named-it>.csv claude/
   ```
   That's the entire step. The analyzer identifies the file by its header
   row (see the schema table above), so the Console's default filename is
   fine as-is. Add it alongside whatever's already in `claude/` — nothing
   needs to be merged or overwritten by hand; every file of the same schema
   is combined automatically.

3. **Re-run the analyzer.**
   ```bash
   python3 ai/ai_energy_impact_analyzer.py --check-freshness   # confirm the warning clears
   python3 ai/ai_energy_impact_analyzer.py                     # regenerate the full report
   ```

4. **Check which file(s) it actually used.** Open the generated
   `docs/ai_energy_impact_report_*.md` and look at *Data Sources & Quality*
   — it lists every file found, which ones were the active source for this
   run, and any file in `claude/` it couldn't classify. If a fresh export
   doesn't show up as the active source, this table tells you why (e.g. an
   older token export is still present and — correctly — outranking a
   newer cost export).

This procedure is identical whether or not you're part of the unparty-app
org — it's just your own Console export, in your own Console account,
dropped in the same folder. (`claude/add_new_claude_data.sh` and
`claude/auto_claude_data_processor.py` still exist in this repo but default
to `data/`, not `claude/`, and aren't part of this flow — step 2 above is
the complete procedure without them.)

## Automation

`.github/workflows/ai-energy-impact.yml` keeps this a living metric instead
of a one-off script:

- **Monthly schedule** (3rd of each month) plus runs on pushes that touch the
  analyzer or its source CSVs, and manual `workflow_dispatch`.
- Runs the regression tests, emits a **stale-data warning annotation** when
  source CSVs are out of date, and publishes the report to the job's step
  summary.
- Uploads the JSON + Markdown reports as **workflow artifacts (90-day
  retention)**.

### Report history policy

Generated reports are intentionally **gitignored** (see `.gitignore`;
timestamped reports previously accumulated as untracked clutter and were
purged in commit `24411559f`). The archive of record is the CI artifact
trail: each monthly run keeps its reports for 90 days, and the step summary
preserves the headline numbers with the run itself. Run locally whenever you
want a fresh copy — reports are cheap to regenerate from the source CSVs.

## The "energy tax" idea

The report prices carbon at **$30/tonne** (configurable), in line with common
internal-carbon-pricing practice, then applies an efficiency multiplier:
heavy cache reuse earns a discount, poor cache efficiency pays a premium.
The result is a small dollar figure you can treat as a monthly
sustainability budget — offset purchases, green-tariff upgrades, or simply a
number that makes the footprint visible next to the API bill.

## Files in this package

| File | Purpose |
|------|---------|
| `ai_energy_impact_analyzer.py` | Core engine: data loading, energy/carbon/tax math, freshness check, report generation |
| `ai_energy_cli.py` | Friendly CLI: `analyze`, `quick`, `models`, `recommendations`, `dashboard` |
| `ai_energy_dashboard_integrator.py` | Merges energy results with API cost data into a combined dashboard summary |
| `ai_integration_analyzer.py` | Separate tool: repository AI-integration analysis (not part of the energy pipeline) |
| `LICENSE` | MIT license text for this package |

## Tests

```bash
python3 -m pytest tests/test_ai_energy_impact_analyzer.py \
                  tests/test_ai_energy_cli_smoke.py \
                  tests/test_ai_energy_impact.py -q
```

## UNPARTY

For historical use of AI sessions in the unparty-app development process: [Claude Session] (https://claude.ai/share/56af6c59-978a-4830-a7f5-b79099f8350c). 
