greenpick 0.1.0__tar.gz

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.
Files changed (48) hide show
  1. greenpick-0.1.0/LICENSE +21 -0
  2. greenpick-0.1.0/PKG-INFO +271 -0
  3. greenpick-0.1.0/README.md +241 -0
  4. greenpick-0.1.0/pyproject.toml +59 -0
  5. greenpick-0.1.0/setup.cfg +4 -0
  6. greenpick-0.1.0/src/greenpick/__init__.py +7 -0
  7. greenpick-0.1.0/src/greenpick/__main__.py +18 -0
  8. greenpick-0.1.0/src/greenpick/config.py +58 -0
  9. greenpick-0.1.0/src/greenpick/data/__init__.py +28 -0
  10. greenpick-0.1.0/src/greenpick/data/auto_repository.py +47 -0
  11. greenpick-0.1.0/src/greenpick/data/eia_repository.py +156 -0
  12. greenpick-0.1.0/src/greenpick/data/electricitymaps_repository.py +104 -0
  13. greenpick-0.1.0/src/greenpick/data/emission_factors.json +35 -0
  14. greenpick-0.1.0/src/greenpick/data/entsoe_repository.py +401 -0
  15. greenpick-0.1.0/src/greenpick/data/gpu_power.json +26 -0
  16. greenpick-0.1.0/src/greenpick/data/inference_energy.json +50 -0
  17. greenpick-0.1.0/src/greenpick/data/instance_families.json +32 -0
  18. greenpick-0.1.0/src/greenpick/data/mock_repository.py +53 -0
  19. greenpick-0.1.0/src/greenpick/data/network.json +7 -0
  20. greenpick-0.1.0/src/greenpick/data/power.json +7 -0
  21. greenpick-0.1.0/src/greenpick/data/pricing.json +31 -0
  22. greenpick-0.1.0/src/greenpick/data/regions.json +22 -0
  23. greenpick-0.1.0/src/greenpick/data/repository.py +27 -0
  24. greenpick-0.1.0/src/greenpick/data/static_data.py +105 -0
  25. greenpick-0.1.0/src/greenpick/models.py +342 -0
  26. greenpick-0.1.0/src/greenpick/server.py +349 -0
  27. greenpick-0.1.0/src/greenpick/services/__init__.py +5 -0
  28. greenpick-0.1.0/src/greenpick/services/carbon_service.py +28 -0
  29. greenpick-0.1.0/src/greenpick/services/cost_service.py +21 -0
  30. greenpick-0.1.0/src/greenpick/services/forecast_service.py +72 -0
  31. greenpick-0.1.0/src/greenpick/services/inference_service.py +100 -0
  32. greenpick-0.1.0/src/greenpick/services/instance_service.py +132 -0
  33. greenpick-0.1.0/src/greenpick/services/latency_service.py +33 -0
  34. greenpick-0.1.0/src/greenpick/services/locality_service.py +160 -0
  35. greenpick-0.1.0/src/greenpick/services/metric_scaffold_service.py +149 -0
  36. greenpick-0.1.0/src/greenpick/services/recommender.py +203 -0
  37. greenpick-0.1.0/src/greenpick/services/residency_service.py +53 -0
  38. greenpick-0.1.0/src/greenpick/services/rightsizing_service.py +93 -0
  39. greenpick-0.1.0/src/greenpick/services/scheduling_service.py +211 -0
  40. greenpick-0.1.0/src/greenpick/services/serving_service.py +202 -0
  41. greenpick-0.1.0/src/greenpick/services/training_service.py +209 -0
  42. greenpick-0.1.0/src/greenpick.egg-info/PKG-INFO +271 -0
  43. greenpick-0.1.0/src/greenpick.egg-info/SOURCES.txt +46 -0
  44. greenpick-0.1.0/src/greenpick.egg-info/dependency_links.txt +1 -0
  45. greenpick-0.1.0/src/greenpick.egg-info/entry_points.txt +2 -0
  46. greenpick-0.1.0/src/greenpick.egg-info/requires.txt +8 -0
  47. greenpick-0.1.0/src/greenpick.egg-info/top_level.txt +1 -0
  48. greenpick-0.1.0/tests/test_services.py +1078 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Data Science Advisers, LLC
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.
@@ -0,0 +1,271 @@
1
+ Metadata-Version: 2.4
2
+ Name: greenpick
3
+ Version: 0.1.0
4
+ Summary: Design-time sustainability co-pilot (MCP server): greener, cheaper cloud infrastructure decisions with carbon + cost + latency tradeoffs.
5
+ Author-email: "Data Science Advisers, LLC" <info@datascienceadvisers.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/bithug01/greenpick
8
+ Project-URL: Repository, https://github.com/bithug01/greenpick
9
+ Project-URL: Issues, https://github.com/bithug01/greenpick/issues
10
+ Keywords: mcp,sustainability,carbon,cloud,finops,developer-tools,green-software
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Software Development :: Libraries
18
+ Classifier: Topic :: Scientific/Engineering
19
+ Requires-Python: >=3.11
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: mcp<2,>=1.2
23
+ Requires-Dist: pydantic>=2.0
24
+ Requires-Dist: httpx>=0.27
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=8.0; extra == "dev"
27
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
28
+ Requires-Dist: ijson>=3.0; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ <p align="center">
32
+ <img src="docs/img/logo.svg" alt="GreenPick logo — a leaf whose veins are circuit traces" width="120" />
33
+ </p>
34
+
35
+ <h1 align="center">GreenPick</h1>
36
+
37
+ <p align="center"><strong>Write greener, cheaper cloud infrastructure — before you deploy.</strong></p>
38
+
39
+ <!-- mcp-name: io.github.bithug01/greenpick -->
40
+
41
+
42
+ <p align="center">
43
+ <img src="https://img.shields.io/pypi/v/greenpick" alt="PyPI version" />
44
+ <img src="https://img.shields.io/badge/license-MIT-green" alt="License: MIT" />
45
+ <img src="https://img.shields.io/badge/tests-passing-brightgreen" alt="Tests: passing" />
46
+ <img src="https://img.shields.io/badge/python-3.11%2B-blue" alt="Python 3.11+" />
47
+ <img src="https://img.shields.io/badge/MCP%20tools-15-0ea5e9" alt="MCP tools: 15" />
48
+ </p>
49
+
50
+ A **design-time sustainability co-pilot** that runs as an MCP server inside your vibe-coding
51
+ environment (Cursor / Claude Code / Kiro). Ask it where to deploy, when to run a job, or how to
52
+ right-size — and it answers with an honest **carbon + cost + latency** tradeoff, in-editor, in
53
+ seconds. (It responds when you ask; auto-nudging on infra-code changes is on the roadmap.)
54
+
55
+ > **Status: working — 15 tools.** Live carbon for US (EIA-930) and EU (ENTSO-E), cross-cloud cost
56
+ > parity (Vantage-refreshed), per-axis R/Y/G ratings, carbon-aware scheduling + day-ahead forecast,
57
+ > GPU-training **and LLM-inference** carbon, right-sizing, serving-pattern and data-locality/residency
58
+ > checks — all shipped. Falls back to clearly-labelled mock data offline or without API keys.
59
+
60
+ <p align="center">
61
+ <img src="docs/img/region-carbon-30x.svg" alt="Same H100 training run, ~30× the carbon depending only on region (Stockholm vs Sydney)" width="560" />
62
+ </p>
63
+
64
+ *The same 40-GPU-hour training run emits ~0.7 kg CO₂ in Stockholm vs ~19 kg in Sydney — a ~30×
65
+ difference from region choice alone. Ask GreenPick and it surfaces that (with the cost and latency
66
+ tradeoff) while you're still in the editor, before you commit.*
67
+
68
+ **▶ [See the 5-minute demo](docs/demo.md)** — three scenarios with real tool output (training placement, the egress backfire, the forecast).
69
+
70
+ ## Features
71
+
72
+ - 🧮 **Right-sizing that cuts cost *and* carbon together** — the FinOps win with a carbon twin. The money saved is the reason to run it; the carbon comes free.
73
+ - ⏱ **Carbon-aware scheduling** — run deferrable jobs (ETL, batch, training) when the grid is cleanest, now or day-ahead. A decision you make for *every* recurring job.
74
+ - ⚡ **GPU training & LLM inference carbon** — estimate a run's footprint and the greener *where* + *when*; the size/placement choices that actually move the number.
75
+ - 🌍 **Greener region picks** — ranked by carbon, with the cost + latency tradeoff shown, not hidden.
76
+ - 🛡 **Backfire guards** — flags when a greener move loses to egress, or crosses a data-residency line.
77
+ - 🔌 **Live US + EU grid data**, honest mock fallback — **no API keys required to start**.
78
+
79
+ ## Contents
80
+
81
+ - [Why this exists](#why-this-exists)
82
+ - [What it is / is NOT](#what-it-is--is-not) · [How it differs](#how-it-differs-from-whats-out-there)
83
+ - [Scope](#scope)
84
+ - [MCP tools](#mcp-tools)
85
+ - [Data sources](#data-sources-free-swappable-behind-one-interface)
86
+ - [Honest limitations](#honest-limitations-shipped-in-the-tool-itself)
87
+ - [Quick start](#quick-start)
88
+ - [FAQ](#faq)
89
+ - [Contributing](#contributing)
90
+ - [License](#license)
91
+
92
+ ## Why this exists
93
+
94
+ The same web service emits very different CO₂ depending on **which region** it runs in, because
95
+ electricity grids differ in carbon intensity. Existing tools either rank regions in the abstract,
96
+ or measure carbon *after* you deploy. GreenPick does it **at the moment you choose**, and tells you
97
+ what the greener choice *costs you* in latency and dollars — so you can accept or reject it with
98
+ eyes open.
99
+
100
+ ## What it is / is NOT
101
+
102
+ - **IS:** directional "greener choice" guidance for a developer picking a cloud region while
103
+ building. Guidance, with tradeoffs stated.
104
+ - **IS NOT:** audited carbon accounting, ESG/Scope-2 reporting, or a real-time scheduler.
105
+ GreenPick does **not** claim GHG-Protocol or ISO compliance — that's what the paid data vendors
106
+ (Electricity Maps, WattTime) provide. GreenPick is for *decisions*, not *disclosures*.
107
+
108
+ ### How it differs from what's out there
109
+
110
+ - **Measurement tools** (Cloud Carbon Footprint, CodeCarbon, Kepler) report what you *already*
111
+ emitted, *after* you deploy. GreenPick advises *before* — at the choice.
112
+ - **Cloud providers' own tools** (AWS CCFT, Azure, Google's "Low CO₂" region labels) cover *one*
113
+ cloud and show carbon alone. GreenPick is **cross-cloud** and weighs carbon **against cost and
114
+ latency** so you see the tradeoff, not just a green badge.
115
+ - **CI/CD carbon tools** act at merge time on a pipeline job. GreenPick works earlier, in the
116
+ editor, across more decisions (scheduling, right-sizing, training/inference, egress & residency).
117
+ - **Grid-data SDKs** (Electricity Maps, WattTime, GSF Carbon Aware SDK) are building blocks;
118
+ GreenPick is the decision layer on top of that kind of data.
119
+
120
+ The combination — **cross-cloud, carbon + cost + latency, at design time, in the editor, with
121
+ backfire guards** — is the part nothing else puts together.
122
+
123
+ ## Scope
124
+
125
+ - Providers: **AWS, GCP, Azure** regions.
126
+ - Workloads: long-running **web/API services**, **GPU training** runs, and **deferrable jobs**
127
+ (ETL / batch / backups) — placement and timing for each.
128
+ - Carbon = **grid carbon intensity by region** (directional, point-in-time; live US + EU), plus a
129
+ **day-ahead forecast** (EU) for forward-looking scheduling.
130
+ - Cost = **compute + egress ballpark** (deterministic static table, apples-to-apples across
131
+ clouds; never LLM-invented).
132
+ - Latency = **geographic estimate** to a stated user location.
133
+ - Efficiency levers: **greener instance family** (perf-per-watt), **right-sizing** (cost + carbon
134
+ together), and a **carbon-metric scaffold** to track your app over time.
135
+ - Guardrails: **data-locality / egress** backfire checks and **cross-jurisdiction residency** flags.
136
+ - **Free data only.** No flow-traced consumption accounting; carbon forecast is relative, not absolute.
137
+
138
+ Roadmap: data-format/engine efficiency advice, sub-national grid zones, CI/CD integration.
139
+ See `docs/user-questions-backlog.md`.
140
+
141
+ ## MCP tools
142
+
143
+ 15 tools, grouped by what you're trying to do.
144
+
145
+ ### Pick a region
146
+
147
+ | Tool | What it does |
148
+ |------|--------------|
149
+ | `compare_regions_tri_axis` | Rank candidate regions by carbon with cost + latency tradeoffs; recommend a pick, each axis rated R/Y/G. Pass `regions` to rank only the ones you'd actually consider. |
150
+ | `greener_alternative_to` | "You picked X — the greenest region within +N ms latency is Y (−Z% carbon, Δcost)." The core nudge. |
151
+ | `region_carbon_now` | Current gCO₂/kWh for a region, with source + timestamp + freshness. |
152
+
153
+ ### Time a job (scheduling)
154
+
155
+ | Tool | What it does |
156
+ |------|--------------|
157
+ | `cleanest_hours_to_run` | Cleanest recent hours to time a deferrable job (ETL, backups, training), + % reduction. Pass `window_hours` for a job of known duration → cleanest contiguous window to start at. |
158
+ | `cleanest_time_of_day` | For a **recurring** job (nightly batch): the region's cleanest time of day, averaged across recent days. A daily pattern, not a 7-day weekly one. |
159
+ | `carbon_forecast` | Forward-looking: which **upcoming** hours will be cleanest, from the EU day-ahead wind+solar forecast (ENTSO-E). Relative ranking; US/uncovered zones degrade to the recent historical pattern. |
160
+
161
+ ### Estimate a workload's carbon
162
+
163
+ | Tool | What it does |
164
+ |------|--------------|
165
+ | `estimate_workload_carbon` | Rough kgCO₂/month for a workload in a region (an *estimate*, not a measurement). |
166
+ | `estimate_training_carbon` | Carbon of a GPU training run (TDP-based energy × live grid), with greener **where** (region ranking) + **when** (cleanest hours) — the two levers that compound for portable, deferrable training. |
167
+ | `estimate_inference_carbon` | Energy + CO₂ of an LLM **inference** workload, by model size class × output tokens × requests (× live grid). A low–high band; smaller size class is the big lever. Self-hosted-friendly; not a named-model leaderboard. |
168
+
169
+ ### Efficiency & guardrails
170
+
171
+ | Tool | What it does |
172
+ |------|--------------|
173
+ | `greener_instance_family` | A greener same-size family in the same region via perf-per-watt (newer generation / ARM Graviton-class does the same work on less energy). |
174
+ | `rightsizing_check` | Right-sizing (the #1 FinOps win) with a carbon twin: if you're over-provisioned, a smaller size cuts **both** cost and carbon → the right-sized target with monthly $ and kg CO₂ saving. |
175
+ | `data_locality_egress_check` | Warn when running compute away from where your data lives backfires: directional egress $ + coarse transfer carbon, and whether a greener-region move is still a net win. |
176
+ | `serving_pattern_advice` | For a user-facing platform: serve from one region or several? Traffic-weighted latency + carbon, with the multi-region data-sync egress and cross-jurisdiction residency catches. |
177
+
178
+ ### Instrument & understand
179
+
180
+ | Tool | What it does |
181
+ |------|--------------|
182
+ | `carbon_metric_scaffold` | Emits paste-in instrumentation (Python) so your app reports its own **estimated** carbon over time — observable proxies × GreenPick's power model × live grid. Self-tracking, directional; not a runtime meter. |
183
+ | `explain_methodology_and_limits` | The assumptions and what GreenPick explicitly does **not** claim. |
184
+
185
+ ## Data sources (free; swappable behind one interface)
186
+
187
+ - **EIA-930** (US balancing authorities) and **ENTSO-E** (EU zones) — live grid carbon,
188
+ auto-routed by region. Both also drive `cleanest_hours_to_run` from recent hourly history.
189
+ - **Mock** — deterministic, offline default; clearly labelled `quality: "mock"` so nothing is
190
+ mistaken for a real reading. Used wherever a key is missing or a region isn't covered.
191
+ - Cost: a **dated static pricing table** (`data/pricing.json`), refreshed from live Vantage
192
+ pricing via `scripts/refresh_pricing.py` using one matched method across all three clouds.
193
+ - Instance-family efficiency: directional perf-per-watt multipliers (`data/instance_families.json`).
194
+ - Latency: great-circle distance from region coordinates to the user's location.
195
+
196
+ Set `EIA_API_KEY` and `ENTSOE_TOKEN` in `.env` (both free) for live carbon; `GREENPICK_CARBON_SOURCE`
197
+ selects the source (`auto` routes US→EIA, EU→ENTSO-E, else mock).
198
+
199
+ The data layer is a swappable repository (`MOCK` by default, works offline). Nothing here invents
200
+ numbers: the LLM writes the *rationale*, the code supplies the *figures*.
201
+
202
+ ## Honest limitations (shipped in the tool itself)
203
+
204
+ Directional, not audited. Region→grid-zone mapping is approximate. Carbon is point-in-time, not
205
+ flow-traced consumption. Cost is a ballpark, not a quote. Latency is a geographic estimate.
206
+ "Greener" assumes grid intensity dominates and ignores embodied/hardware carbon and provider RECs.
207
+
208
+ ## Quick start
209
+
210
+ ```bash
211
+ # Python 3.11+
212
+ pip install greenpick # from PyPI
213
+ python -m greenpick # run the MCP server (stdio)
214
+ ```
215
+
216
+ Or from source, for development (editable install + tests):
217
+
218
+ ```bash
219
+ git clone https://github.com/bithug01/greenpick.git
220
+ cd greenpick
221
+ pip install -e ".[dev]"
222
+ cp .env.example .env # defaults to mock data — works offline
223
+ python -m greenpick # run the MCP server (stdio)
224
+ pytest # run tests
225
+ ```
226
+
227
+ Connect it to an MCP client (e.g. Kiro / Claude Code / Cursor) by pointing the client at
228
+ `python -m greenpick` in this directory. See `.env.example` for switching the data source.
229
+
230
+ ## FAQ
231
+
232
+ **Do I need API keys?** No — GreenPick runs on clearly-labelled mock data out of the box. For *live*
233
+ carbon, set two free keys in `.env` (`EIA_API_KEY` for US, `ENTSOE_TOKEN` for EU) and
234
+ `GREENPICK_CARBON_SOURCE=auto`. Without them it still works; it just says `quality: "mock"`.
235
+
236
+ **Why "directional" and not audited numbers?** Because it's for a *design-time decision*, not a
237
+ compliance report. "Stockholm is ~30× cleaner than Sydney" is what you need to pick a region in
238
+ seconds — a certified figure is a different job for a different tool (Electricity Maps, WattTime).
239
+ GreenPick is for *decisions*, not *disclosures*, and says so in every tool's limitations.
240
+
241
+ **My cloud says this region is already 100% renewable — so does region even matter?** That's
242
+ *market-based* accounting (the provider matches usage with renewable certificates/PPAs over a year).
243
+ GreenPick uses *location-based* accounting — the actual carbon intensity of the grid you physically
244
+ draw from, hour to hour. Both are legitimate (the GHG Protocol asks for both), and they answer
245
+ different questions: market-based is about procurement claims; location-based is about the real grid
246
+ your workload leans on right now. GreenPick is deliberately location-based because that's what a
247
+ *placement/timing* decision actually affects — you can't change the provider's annual REC portfolio,
248
+ but you *can* choose a cleaner grid or a cleaner hour. We ignore RECs by design, not oversight.
249
+
250
+ **What happens for a region with no live data?** It falls back to the recent historical pattern or
251
+ to mock, and labels which — it never presents a fallback as a live reading. Forecast likewise degrades
252
+ to historical (labelled) where no day-ahead feed exists (e.g. US).
253
+
254
+ **Can it rank Claude vs GPT vs Llama for carbon?** No, by design. `estimate_inference_carbon` works by
255
+ model *size class* (self-hosted-friendly), not a named-model leaderboard — vendors don't disclose the
256
+ serving details that would make such a ranking honest.
257
+
258
+ **How do I ask it something?** You don't call tools directly — you talk to your MCP client in plain
259
+ language ("where's the greenest region to run this?") and it invokes the right tool. See the
260
+ [demo](docs/demo.md) for the kinds of questions that trigger each one.
261
+
262
+ ## Contributing
263
+
264
+ Contributions of any kind are welcome — a bug report, a data-source correction, a sharper caveat, or
265
+ code. See [CONTRIBUTING.md](CONTRIBUTING.md) for the short version. The one thing GreenPick asks:
266
+ keep it **honest and directional** — no invented numbers, no precision the data can't back (that
267
+ discipline is the whole point).
268
+
269
+ ## License
270
+
271
+ MIT — see [LICENSE](LICENSE). © 2026 Data Science Advisers, LLC.
@@ -0,0 +1,241 @@
1
+ <p align="center">
2
+ <img src="docs/img/logo.svg" alt="GreenPick logo — a leaf whose veins are circuit traces" width="120" />
3
+ </p>
4
+
5
+ <h1 align="center">GreenPick</h1>
6
+
7
+ <p align="center"><strong>Write greener, cheaper cloud infrastructure — before you deploy.</strong></p>
8
+
9
+ <!-- mcp-name: io.github.bithug01/greenpick -->
10
+
11
+
12
+ <p align="center">
13
+ <img src="https://img.shields.io/pypi/v/greenpick" alt="PyPI version" />
14
+ <img src="https://img.shields.io/badge/license-MIT-green" alt="License: MIT" />
15
+ <img src="https://img.shields.io/badge/tests-passing-brightgreen" alt="Tests: passing" />
16
+ <img src="https://img.shields.io/badge/python-3.11%2B-blue" alt="Python 3.11+" />
17
+ <img src="https://img.shields.io/badge/MCP%20tools-15-0ea5e9" alt="MCP tools: 15" />
18
+ </p>
19
+
20
+ A **design-time sustainability co-pilot** that runs as an MCP server inside your vibe-coding
21
+ environment (Cursor / Claude Code / Kiro). Ask it where to deploy, when to run a job, or how to
22
+ right-size — and it answers with an honest **carbon + cost + latency** tradeoff, in-editor, in
23
+ seconds. (It responds when you ask; auto-nudging on infra-code changes is on the roadmap.)
24
+
25
+ > **Status: working — 15 tools.** Live carbon for US (EIA-930) and EU (ENTSO-E), cross-cloud cost
26
+ > parity (Vantage-refreshed), per-axis R/Y/G ratings, carbon-aware scheduling + day-ahead forecast,
27
+ > GPU-training **and LLM-inference** carbon, right-sizing, serving-pattern and data-locality/residency
28
+ > checks — all shipped. Falls back to clearly-labelled mock data offline or without API keys.
29
+
30
+ <p align="center">
31
+ <img src="docs/img/region-carbon-30x.svg" alt="Same H100 training run, ~30× the carbon depending only on region (Stockholm vs Sydney)" width="560" />
32
+ </p>
33
+
34
+ *The same 40-GPU-hour training run emits ~0.7 kg CO₂ in Stockholm vs ~19 kg in Sydney — a ~30×
35
+ difference from region choice alone. Ask GreenPick and it surfaces that (with the cost and latency
36
+ tradeoff) while you're still in the editor, before you commit.*
37
+
38
+ **▶ [See the 5-minute demo](docs/demo.md)** — three scenarios with real tool output (training placement, the egress backfire, the forecast).
39
+
40
+ ## Features
41
+
42
+ - 🧮 **Right-sizing that cuts cost *and* carbon together** — the FinOps win with a carbon twin. The money saved is the reason to run it; the carbon comes free.
43
+ - ⏱ **Carbon-aware scheduling** — run deferrable jobs (ETL, batch, training) when the grid is cleanest, now or day-ahead. A decision you make for *every* recurring job.
44
+ - ⚡ **GPU training & LLM inference carbon** — estimate a run's footprint and the greener *where* + *when*; the size/placement choices that actually move the number.
45
+ - 🌍 **Greener region picks** — ranked by carbon, with the cost + latency tradeoff shown, not hidden.
46
+ - 🛡 **Backfire guards** — flags when a greener move loses to egress, or crosses a data-residency line.
47
+ - 🔌 **Live US + EU grid data**, honest mock fallback — **no API keys required to start**.
48
+
49
+ ## Contents
50
+
51
+ - [Why this exists](#why-this-exists)
52
+ - [What it is / is NOT](#what-it-is--is-not) · [How it differs](#how-it-differs-from-whats-out-there)
53
+ - [Scope](#scope)
54
+ - [MCP tools](#mcp-tools)
55
+ - [Data sources](#data-sources-free-swappable-behind-one-interface)
56
+ - [Honest limitations](#honest-limitations-shipped-in-the-tool-itself)
57
+ - [Quick start](#quick-start)
58
+ - [FAQ](#faq)
59
+ - [Contributing](#contributing)
60
+ - [License](#license)
61
+
62
+ ## Why this exists
63
+
64
+ The same web service emits very different CO₂ depending on **which region** it runs in, because
65
+ electricity grids differ in carbon intensity. Existing tools either rank regions in the abstract,
66
+ or measure carbon *after* you deploy. GreenPick does it **at the moment you choose**, and tells you
67
+ what the greener choice *costs you* in latency and dollars — so you can accept or reject it with
68
+ eyes open.
69
+
70
+ ## What it is / is NOT
71
+
72
+ - **IS:** directional "greener choice" guidance for a developer picking a cloud region while
73
+ building. Guidance, with tradeoffs stated.
74
+ - **IS NOT:** audited carbon accounting, ESG/Scope-2 reporting, or a real-time scheduler.
75
+ GreenPick does **not** claim GHG-Protocol or ISO compliance — that's what the paid data vendors
76
+ (Electricity Maps, WattTime) provide. GreenPick is for *decisions*, not *disclosures*.
77
+
78
+ ### How it differs from what's out there
79
+
80
+ - **Measurement tools** (Cloud Carbon Footprint, CodeCarbon, Kepler) report what you *already*
81
+ emitted, *after* you deploy. GreenPick advises *before* — at the choice.
82
+ - **Cloud providers' own tools** (AWS CCFT, Azure, Google's "Low CO₂" region labels) cover *one*
83
+ cloud and show carbon alone. GreenPick is **cross-cloud** and weighs carbon **against cost and
84
+ latency** so you see the tradeoff, not just a green badge.
85
+ - **CI/CD carbon tools** act at merge time on a pipeline job. GreenPick works earlier, in the
86
+ editor, across more decisions (scheduling, right-sizing, training/inference, egress & residency).
87
+ - **Grid-data SDKs** (Electricity Maps, WattTime, GSF Carbon Aware SDK) are building blocks;
88
+ GreenPick is the decision layer on top of that kind of data.
89
+
90
+ The combination — **cross-cloud, carbon + cost + latency, at design time, in the editor, with
91
+ backfire guards** — is the part nothing else puts together.
92
+
93
+ ## Scope
94
+
95
+ - Providers: **AWS, GCP, Azure** regions.
96
+ - Workloads: long-running **web/API services**, **GPU training** runs, and **deferrable jobs**
97
+ (ETL / batch / backups) — placement and timing for each.
98
+ - Carbon = **grid carbon intensity by region** (directional, point-in-time; live US + EU), plus a
99
+ **day-ahead forecast** (EU) for forward-looking scheduling.
100
+ - Cost = **compute + egress ballpark** (deterministic static table, apples-to-apples across
101
+ clouds; never LLM-invented).
102
+ - Latency = **geographic estimate** to a stated user location.
103
+ - Efficiency levers: **greener instance family** (perf-per-watt), **right-sizing** (cost + carbon
104
+ together), and a **carbon-metric scaffold** to track your app over time.
105
+ - Guardrails: **data-locality / egress** backfire checks and **cross-jurisdiction residency** flags.
106
+ - **Free data only.** No flow-traced consumption accounting; carbon forecast is relative, not absolute.
107
+
108
+ Roadmap: data-format/engine efficiency advice, sub-national grid zones, CI/CD integration.
109
+ See `docs/user-questions-backlog.md`.
110
+
111
+ ## MCP tools
112
+
113
+ 15 tools, grouped by what you're trying to do.
114
+
115
+ ### Pick a region
116
+
117
+ | Tool | What it does |
118
+ |------|--------------|
119
+ | `compare_regions_tri_axis` | Rank candidate regions by carbon with cost + latency tradeoffs; recommend a pick, each axis rated R/Y/G. Pass `regions` to rank only the ones you'd actually consider. |
120
+ | `greener_alternative_to` | "You picked X — the greenest region within +N ms latency is Y (−Z% carbon, Δcost)." The core nudge. |
121
+ | `region_carbon_now` | Current gCO₂/kWh for a region, with source + timestamp + freshness. |
122
+
123
+ ### Time a job (scheduling)
124
+
125
+ | Tool | What it does |
126
+ |------|--------------|
127
+ | `cleanest_hours_to_run` | Cleanest recent hours to time a deferrable job (ETL, backups, training), + % reduction. Pass `window_hours` for a job of known duration → cleanest contiguous window to start at. |
128
+ | `cleanest_time_of_day` | For a **recurring** job (nightly batch): the region's cleanest time of day, averaged across recent days. A daily pattern, not a 7-day weekly one. |
129
+ | `carbon_forecast` | Forward-looking: which **upcoming** hours will be cleanest, from the EU day-ahead wind+solar forecast (ENTSO-E). Relative ranking; US/uncovered zones degrade to the recent historical pattern. |
130
+
131
+ ### Estimate a workload's carbon
132
+
133
+ | Tool | What it does |
134
+ |------|--------------|
135
+ | `estimate_workload_carbon` | Rough kgCO₂/month for a workload in a region (an *estimate*, not a measurement). |
136
+ | `estimate_training_carbon` | Carbon of a GPU training run (TDP-based energy × live grid), with greener **where** (region ranking) + **when** (cleanest hours) — the two levers that compound for portable, deferrable training. |
137
+ | `estimate_inference_carbon` | Energy + CO₂ of an LLM **inference** workload, by model size class × output tokens × requests (× live grid). A low–high band; smaller size class is the big lever. Self-hosted-friendly; not a named-model leaderboard. |
138
+
139
+ ### Efficiency & guardrails
140
+
141
+ | Tool | What it does |
142
+ |------|--------------|
143
+ | `greener_instance_family` | A greener same-size family in the same region via perf-per-watt (newer generation / ARM Graviton-class does the same work on less energy). |
144
+ | `rightsizing_check` | Right-sizing (the #1 FinOps win) with a carbon twin: if you're over-provisioned, a smaller size cuts **both** cost and carbon → the right-sized target with monthly $ and kg CO₂ saving. |
145
+ | `data_locality_egress_check` | Warn when running compute away from where your data lives backfires: directional egress $ + coarse transfer carbon, and whether a greener-region move is still a net win. |
146
+ | `serving_pattern_advice` | For a user-facing platform: serve from one region or several? Traffic-weighted latency + carbon, with the multi-region data-sync egress and cross-jurisdiction residency catches. |
147
+
148
+ ### Instrument & understand
149
+
150
+ | Tool | What it does |
151
+ |------|--------------|
152
+ | `carbon_metric_scaffold` | Emits paste-in instrumentation (Python) so your app reports its own **estimated** carbon over time — observable proxies × GreenPick's power model × live grid. Self-tracking, directional; not a runtime meter. |
153
+ | `explain_methodology_and_limits` | The assumptions and what GreenPick explicitly does **not** claim. |
154
+
155
+ ## Data sources (free; swappable behind one interface)
156
+
157
+ - **EIA-930** (US balancing authorities) and **ENTSO-E** (EU zones) — live grid carbon,
158
+ auto-routed by region. Both also drive `cleanest_hours_to_run` from recent hourly history.
159
+ - **Mock** — deterministic, offline default; clearly labelled `quality: "mock"` so nothing is
160
+ mistaken for a real reading. Used wherever a key is missing or a region isn't covered.
161
+ - Cost: a **dated static pricing table** (`data/pricing.json`), refreshed from live Vantage
162
+ pricing via `scripts/refresh_pricing.py` using one matched method across all three clouds.
163
+ - Instance-family efficiency: directional perf-per-watt multipliers (`data/instance_families.json`).
164
+ - Latency: great-circle distance from region coordinates to the user's location.
165
+
166
+ Set `EIA_API_KEY` and `ENTSOE_TOKEN` in `.env` (both free) for live carbon; `GREENPICK_CARBON_SOURCE`
167
+ selects the source (`auto` routes US→EIA, EU→ENTSO-E, else mock).
168
+
169
+ The data layer is a swappable repository (`MOCK` by default, works offline). Nothing here invents
170
+ numbers: the LLM writes the *rationale*, the code supplies the *figures*.
171
+
172
+ ## Honest limitations (shipped in the tool itself)
173
+
174
+ Directional, not audited. Region→grid-zone mapping is approximate. Carbon is point-in-time, not
175
+ flow-traced consumption. Cost is a ballpark, not a quote. Latency is a geographic estimate.
176
+ "Greener" assumes grid intensity dominates and ignores embodied/hardware carbon and provider RECs.
177
+
178
+ ## Quick start
179
+
180
+ ```bash
181
+ # Python 3.11+
182
+ pip install greenpick # from PyPI
183
+ python -m greenpick # run the MCP server (stdio)
184
+ ```
185
+
186
+ Or from source, for development (editable install + tests):
187
+
188
+ ```bash
189
+ git clone https://github.com/bithug01/greenpick.git
190
+ cd greenpick
191
+ pip install -e ".[dev]"
192
+ cp .env.example .env # defaults to mock data — works offline
193
+ python -m greenpick # run the MCP server (stdio)
194
+ pytest # run tests
195
+ ```
196
+
197
+ Connect it to an MCP client (e.g. Kiro / Claude Code / Cursor) by pointing the client at
198
+ `python -m greenpick` in this directory. See `.env.example` for switching the data source.
199
+
200
+ ## FAQ
201
+
202
+ **Do I need API keys?** No — GreenPick runs on clearly-labelled mock data out of the box. For *live*
203
+ carbon, set two free keys in `.env` (`EIA_API_KEY` for US, `ENTSOE_TOKEN` for EU) and
204
+ `GREENPICK_CARBON_SOURCE=auto`. Without them it still works; it just says `quality: "mock"`.
205
+
206
+ **Why "directional" and not audited numbers?** Because it's for a *design-time decision*, not a
207
+ compliance report. "Stockholm is ~30× cleaner than Sydney" is what you need to pick a region in
208
+ seconds — a certified figure is a different job for a different tool (Electricity Maps, WattTime).
209
+ GreenPick is for *decisions*, not *disclosures*, and says so in every tool's limitations.
210
+
211
+ **My cloud says this region is already 100% renewable — so does region even matter?** That's
212
+ *market-based* accounting (the provider matches usage with renewable certificates/PPAs over a year).
213
+ GreenPick uses *location-based* accounting — the actual carbon intensity of the grid you physically
214
+ draw from, hour to hour. Both are legitimate (the GHG Protocol asks for both), and they answer
215
+ different questions: market-based is about procurement claims; location-based is about the real grid
216
+ your workload leans on right now. GreenPick is deliberately location-based because that's what a
217
+ *placement/timing* decision actually affects — you can't change the provider's annual REC portfolio,
218
+ but you *can* choose a cleaner grid or a cleaner hour. We ignore RECs by design, not oversight.
219
+
220
+ **What happens for a region with no live data?** It falls back to the recent historical pattern or
221
+ to mock, and labels which — it never presents a fallback as a live reading. Forecast likewise degrades
222
+ to historical (labelled) where no day-ahead feed exists (e.g. US).
223
+
224
+ **Can it rank Claude vs GPT vs Llama for carbon?** No, by design. `estimate_inference_carbon` works by
225
+ model *size class* (self-hosted-friendly), not a named-model leaderboard — vendors don't disclose the
226
+ serving details that would make such a ranking honest.
227
+
228
+ **How do I ask it something?** You don't call tools directly — you talk to your MCP client in plain
229
+ language ("where's the greenest region to run this?") and it invokes the right tool. See the
230
+ [demo](docs/demo.md) for the kinds of questions that trigger each one.
231
+
232
+ ## Contributing
233
+
234
+ Contributions of any kind are welcome — a bug report, a data-source correction, a sharper caveat, or
235
+ code. See [CONTRIBUTING.md](CONTRIBUTING.md) for the short version. The one thing GreenPick asks:
236
+ keep it **honest and directional** — no invented numbers, no precision the data can't back (that
237
+ discipline is the whole point).
238
+
239
+ ## License
240
+
241
+ MIT — see [LICENSE](LICENSE). © 2026 Data Science Advisers, LLC.
@@ -0,0 +1,59 @@
1
+ [project]
2
+ name = "greenpick"
3
+ version = "0.1.0"
4
+ description = "Design-time sustainability co-pilot (MCP server): greener, cheaper cloud infrastructure decisions with carbon + cost + latency tradeoffs."
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ authors = [{ name = "Data Science Advisers, LLC", email = "info@datascienceadvisers.com" }]
10
+ keywords = ["mcp", "sustainability", "carbon", "cloud", "finops", "developer-tools", "green-software"]
11
+ classifiers = [
12
+ "Development Status :: 4 - Beta",
13
+ "Intended Audience :: Developers",
14
+ "Operating System :: OS Independent",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Topic :: Software Development :: Libraries",
19
+ "Topic :: Scientific/Engineering",
20
+ ]
21
+ dependencies = [
22
+ "mcp>=1.2,<2", # Model Context Protocol SDK (FastMCP lives here). Pinned <2: mcp 2.x
23
+ # renamed FastMCP -> MCPServer and changed APIs; this code targets the 1.x API.
24
+ "pydantic>=2.0",
25
+ "httpx>=0.27", # async HTTP for live data sources
26
+ # .env is parsed by config.py with no third-party dep (avoids the python-dotenv/dotenv
27
+ # name-collision that silently skipped loading under some interpreters).
28
+ ]
29
+
30
+ [project.optional-dependencies]
31
+ dev = [
32
+ "pytest>=8.0",
33
+ "pytest-asyncio>=0.23",
34
+ "ijson>=3.0", # used only by scripts/refresh_pricing.py (not a runtime dep)
35
+ ]
36
+
37
+ [project.urls]
38
+ Homepage = "https://github.com/bithug01/greenpick"
39
+ Repository = "https://github.com/bithug01/greenpick"
40
+ Issues = "https://github.com/bithug01/greenpick/issues"
41
+
42
+ [project.scripts]
43
+ greenpick = "greenpick.__main__:main"
44
+
45
+ [build-system]
46
+ requires = ["setuptools>=77"]
47
+ build-backend = "setuptools.build_meta"
48
+
49
+ [tool.setuptools.packages.find]
50
+ where = ["src"]
51
+
52
+ [tool.setuptools.package-data]
53
+ # Bundle the static JSON models into the wheel. Without this, a pip install from
54
+ # PyPI ships no data files and every tool fails at Path(__file__).parent / "*.json".
55
+ "greenpick.data" = ["*.json"]
56
+
57
+ [tool.pytest.ini_options]
58
+ asyncio_mode = "auto"
59
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,7 @@
1
+ """GreenPick — design-time sustainability co-pilot (MCP server).
2
+
3
+ Greener cloud-region choices with honest carbon + cost + latency tradeoffs,
4
+ delivered inside the vibe-coding loop. Directional guidance, not audited accounting.
5
+ """
6
+
7
+ __version__ = "0.1.0"
@@ -0,0 +1,18 @@
1
+ """Entry point: run the GreenPick MCP server over stdio.
2
+
3
+ python -m greenpick
4
+ """
5
+ from __future__ import annotations
6
+
7
+ import logging
8
+ from .config import SETTINGS
9
+ from .server import mcp
10
+
11
+
12
+ def main() -> None:
13
+ logging.basicConfig(level=getattr(logging, SETTINGS.log_level, logging.INFO))
14
+ mcp.run() # stdio transport by default — what MCP clients expect
15
+
16
+
17
+ if __name__ == "__main__":
18
+ main()