Feature proposal.
The problem
CI is the one workload nearly every project runs continuously, on someone else's hardware, without anybody ever looking at its energy cost. Running codecarbon monitor -- pytest in a pipeline already works today, but it leaves an emissions.csv behind that nobody reads: there is no supported way to turn that file into something a pipeline can print, gate on, or compare against the target branch.
What developers actually want in a pipeline is one line of output attached to a diff — "this branch burns 12.4 g CO2eq per test run, +18% vs master" — and, optionally, a hard failure when a change blows past a budget. Today that means every user writes their own pandas snippet.
Proposed design
A single new CLI command, deliberately CI-agnostic so GitLab, Jenkins, Buildkite and GitHub all get it:
$ codecarbon ci-report --csv emissions.csv --baseline base/emissions.csv --format markdown
Surface:
--csv PATH (default emissions.csv) — the run to summarise.
--baseline PATH (optional) — a second CSV to diff against; absent or unreadable means the report is rendered without a comparison rather than failing.
--format markdown|json — markdown for job summaries and PR comments, JSON for anything that wants to post-process.
--label TEXT — free-text label for the measured workload, shown in the header.
--threshold-kg FLOAT (optional) — exit non-zero when total emissions exceed it; unset means never fail.
Aggregation follows the file format rather than guessing: rows written during a run are per-flush deltas sharing a run_id, so the report sums the rows of the most recent run_id and reports total emissions, energy and duration.
Why it fits existing extension points
Nothing here is new measurement code. codecarbon monitor (codecarbon/cli/main.py) already wraps an arbitrary command under a process-scoped tracker and preserves the child exit code, and FileOutput already writes the EmissionsData schema to emissions.csv. ci-report is a reader over that existing output, registered next to monitor and detect on the existing Typer app. No new dependency, no new extra, no configuration surface: the tracker side is still driven by .codecarbon.config and CODECARBON_* env vars as it is today.
Putting the logic in the CLI rather than in pipeline shell means it is unit-testable and portable across CI systems.
Scope boundary
In scope: the ci-report command, its rendering, the baseline diff, the threshold exit code, tests and docs.
Explicitly out of scope for now: a published composite GitHub Action, PR-comment posting, artifact download of the base-branch baseline, and any marketplace packaging. Those are thin wrappers over this command and can follow once the command itself has settled; they carry CI-specific maintenance that shouldn't gate the portable half.
Also worth documenting rather than hiding: on virtualised hosted runners RAPL is unavailable and CPU energy falls back to the TDP model, so numbers are comparable between runs on identical runner types, not absolute.
Feature proposal.
The problem
CI is the one workload nearly every project runs continuously, on someone else's hardware, without anybody ever looking at its energy cost. Running
codecarbon monitor -- pytestin a pipeline already works today, but it leaves anemissions.csvbehind that nobody reads: there is no supported way to turn that file into something a pipeline can print, gate on, or compare against the target branch.What developers actually want in a pipeline is one line of output attached to a diff — "this branch burns 12.4 g CO2eq per test run, +18% vs
master" — and, optionally, a hard failure when a change blows past a budget. Today that means every user writes their own pandas snippet.Proposed design
A single new CLI command, deliberately CI-agnostic so GitLab, Jenkins, Buildkite and GitHub all get it:
$ codecarbon ci-report --csv emissions.csv --baseline base/emissions.csv --format markdownSurface:
--csv PATH(defaultemissions.csv) — the run to summarise.--baseline PATH(optional) — a second CSV to diff against; absent or unreadable means the report is rendered without a comparison rather than failing.--format markdown|json— markdown for job summaries and PR comments, JSON for anything that wants to post-process.--label TEXT— free-text label for the measured workload, shown in the header.--threshold-kg FLOAT(optional) — exit non-zero when total emissions exceed it; unset means never fail.Aggregation follows the file format rather than guessing: rows written during a run are per-flush deltas sharing a
run_id, so the report sums the rows of the most recentrun_idand reports total emissions, energy and duration.Why it fits existing extension points
Nothing here is new measurement code.
codecarbon monitor(codecarbon/cli/main.py) already wraps an arbitrary command under a process-scoped tracker and preserves the child exit code, andFileOutputalready writes theEmissionsDataschema toemissions.csv.ci-reportis a reader over that existing output, registered next tomonitoranddetecton the existing Typer app. No new dependency, no new extra, no configuration surface: the tracker side is still driven by.codecarbon.configandCODECARBON_*env vars as it is today.Putting the logic in the CLI rather than in pipeline shell means it is unit-testable and portable across CI systems.
Scope boundary
In scope: the
ci-reportcommand, its rendering, the baseline diff, the threshold exit code, tests and docs.Explicitly out of scope for now: a published composite GitHub Action, PR-comment posting, artifact download of the base-branch baseline, and any marketplace packaging. Those are thin wrappers over this command and can follow once the command itself has settled; they carry CI-specific maintenance that shouldn't gate the portable half.
Also worth documenting rather than hiding: on virtualised hosted runners RAPL is unavailable and CPU energy falls back to the TDP model, so numbers are comparable between runs on identical runner types, not absolute.