Metadata-Version: 2.4
Name: greentrain
Version: 0.1.0
Summary: Low-carbon AI training service built on iroh-tinker
License: Apache-2.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: iroh-tinker>=0.3.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Dynamic: license-file

# greentrain

Low-carbon AI training service built on [iroh-tinker](https://github.com/scairesearch/iroh_tinker).

greentrain takes a training workload plus its targets (accuracy, latency, cost),
picks the lowest-carbon device tier and elastic subnet that still meets those
targets, runs the job through iroh-tinker's multi-cloud launch, and emits an
auditable carbon report.

> **These are estimates unless the report says `measured`.**
> Every energy and carbon number greentrain prints carries a provenance label.
> A number is labelled `measured` only when it came from a physical
> instrument (`nvidia-smi`, Linux RAPL, or an operator-supplied meter). Anything
> derived from a power model or a grid-intensity dataset is labelled
> `estimated`. An unlabelled carbon claim is a liability, not a product.

## Install

```bash
pip install greentrain            # released package
pip install -e ".[dev]"            # from a checkout
```

greentrain depends on the public `iroh-tinker` surface and nothing else.
While `iroh-tinker` 0.3.0 is unreleased, install it from the working tree:

```bash
pip install -e /path/to/iroh-tinker
```

## Built on the iroh-tinker public surface

greentrain uses only published `iroh-tinker` API (verified against
`iroh-tinker` 0.3.0):

| API | Used for |
|---|---|
| `iroh_tinker.ofo.SubnetSampler` | elastic width/depth sampling per device tier |
| `iroh_tinker.ofo.OFAProfile` | per-tier latency/memory profile fed to the sampler |
| `iroh_tinker.ofo.ElasticConfig` | enabling the elastic width/depth knobs |
| `iroh_tinker.device.detect_devices` | local tier detection for the fallback power model |
| `iroh_tinker.hw.HardwareContext` / `infer_topology` | interconnect hints in the tier profile |
| `iroh_tinker.cloud.spec.LaunchSpec` / `ResourcesSpec` / `RendezvousSpec` / `RecoverySpec` / `CheckpointSpec` | the launch spec greentrain hands to iroh-tinker |
| `iroh_tinker.cloud.job.JobManager` | launch, status and log collection |
| `iroh_tinker.comm.CompressedTransport` | gradient transport used by the launched job |

`iroh_tinker.AllreduceAlgorithm` is **not** part of the top-level export
surface; it lives in `iroh_tinker.comm`. greentrain does not depend on it.

## CLI

```bash
greentrain tiers                      # tier power models (all estimated)
greentrain intensity --region eu-north-1
greentrain plan --spec workload.json  # cheapest feasible tier + subnet
greentrain run --spec workload.json   # run it and report the carbon
greentrain report --job-id my-job     # re-render a finished job's report
```

Every command accepts `--json` for machine consumption.

## Measurement methodology

**Energy.** `energy_kwh = average_watts * duration_s / 3_600_000`.

The average watts come from the first reader that can produce a reading:

1. `NvidiaSmiPowerReader` — `nvidia-smi --query-gpu=power.draw`. Measured.
2. `RaplPowerReader` — Linux RAPL package energy counters under
   `/sys/class/powercap`, differenced over a short interval. Measured.
3. `ExternalMeterPowerReader` — an operator-supplied callable returning watts
   from a smart plug, PDU or watt meter. Measured, and the operator's name is
   recorded in the report.
4. `EstimatedTierPowerReader` — the documented per-tier power model in
   `greentrain.power.TIER_POWER_MODELS`. **Estimated.**

**Carbon.** `carbon_kg = energy_kwh * intensity_gco2_per_kwh / 1000`, using the
bundled table in `greentrain/data/carbon_intensity.csv`. Each row carries a
provider, a retrieval date and a source URL. The loader rejects any row
without a valid date: an undated intensity cannot be audited.

The bundled values are annual-average grid figures and are therefore labelled
`estimated`. They are placeholders until a licensed feed (Ember / WattTime /
Electricity Maps) is wired in — see "Open questions" in the product-suite plan.

## Provenance contract

* `energy_provenance` is the provenance of the power reading.
* `carbon_provenance` is `measured` **only** when the energy *and* the grid
  intensity were both measured. A modelled energy figure or a dataset
  intensity always downgrades the carbon figure to `estimated`.
* `greentrain.carbon.check_provenance` raises `ProvenanceViolation` if a
  report ever claims more certainty than its inputs support.
* Every rendering (JSON, Markdown, Prometheus) carries the label. The JSON
  report has a top-level `measured` boolean that is `true` only when both
  sides of the comparison are measured.

## Subnet selection

For each candidate tier greentrain searches the tier's elastic width/depth
range for the cheapest subnet that still reaches the accuracy target and
respects the latency and cost targets:

```
achievable_accuracy = tier_accuracy_floor * width^0.5 * depth^0.5   (capped at 1.0)
power_factor        = clamp(width * depth, 0.35, 1.25)
estimated_watts     = watts_per_device * device_count * power_factor
```

The accuracy model is a documented heuristic, not a trained predictor. It is
deliberately conservative: it never lets a tier claim an accuracy it has not
demonstrated.

## Tests

```bash
pip install -e ".[dev]"
pytest
```

The suite is credential-free. The end-to-end test drives iroh-tinker's **local**
engine, so it needs no cloud account, no GPU and no network.

## Layout

```
src/greentrain/
  power.py                  power readers + provenance labels
  carbon.py                 accounting, intensity table loader, provenance checks
  data/carbon_intensity.csv dated, sourced grid intensity table
  subnet.py                 lowest-carbon tier/subnet selection
  report.py                 JSON / Markdown / Prometheus rendering
  runner.py                 LaunchSpec + JobManager driver
  cli.py                    greentrain plan | run | report | tiers | intensity
```

## Licence

Apache-2.0. greentrain is a separate project from iroh-tinker, which stays
MIT OR Apache-2.0.
