Skip to content

Feature proposal: SCI (ISO/IEC 21031) report output method #1353

Description

@davidberenstein1957

Feature proposal.

Problem

Sustainability and procurement teams ask for one number by name: the Software Carbon Intensity, as defined by the Green Software Foundation and standardised as ISO/IEC 21031:2024.

SCI = (E * I + M) / R

CodeCarbon already measures E (energy consumed) and already applies I (regional carbon intensity, including cloud region and PUE handling). What it does not do is express the result in the shape a reviewer recognises, so teams export the CSV and rebuild the arithmetic in a spreadsheet. R, the functional unit, is the one term that genuinely cannot be inferred — only the user knows what one unit of their software is — and it should be recorded as an explicit declaration rather than guessed.

Proposed design

A new output method, alongside the existing ones, mirroring the BoAmps exporter that already covers exactly this shape of problem (a standards-format JSON report written once at the end of a run).

from codecarbon import EmissionsTracker
from codecarbon.output_methods.sci import SCIOutput, FunctionalUnit

sci = SCIOutput(
    functional_unit=FunctionalUnit(name="inference request", count=10_000),
    output_dir="reports",
)
tracker = EmissionsTracker(output_handlers=[sci])

Or declaratively, matching how BoAmpsOutput.from_file() works today:

sci = SCIOutput.from_file("sci_context.json")

and via config, output_methods = csv,sci.

The handler writes sci_report_<run_id>.json containing the SCI value, the four terms, and a provenance block (grid intensity source, measurement boundary, hardware, PUE, duration). I is derived as emissions * 1000 / energy_consumed rather than recomputed, so the report is consistent with the CSV by construction. task_out() writes per-task reports when tasks are in use.

The M term

CodeCarbon has no manufacturing/embodied data and should not invent any. An uncited embodied figure in a compliance report is worse than a blank one. So M is user-declared only: it comes from the context file or the constructor, and when it is not supplied the report still emits, with M_gCO2e: 0 and M_source: "not declared" so the reader can see the report is a partial one. Sourcing embodied figures automatically (a bundled hardware table, cloud-provider per-instance figures) is deliberately out of scope until someone owns the citations.

Similarly, when R is never declared the report is written with sci: null and a status explaining why, rather than dividing by zero or silently assuming R = 1.

Why it fits

OutputMethod is a plain str enum in codecarbon/output_methods/base_output.py and _init_output_methods in codecarbon/emissions_tracker.py appends one handler per selected member; BoAmpsOutput already demonstrates the "final standards report, live_out() is a no-op" pattern. No new dependencies — json and dataclasses cover it, as they do for BoAmps.

Scope boundary

In scope: the report, the enum value, config keys, docs, tests.

Explicitly out of scope: any change to what emissions means; automatic embodied-carbon estimation; an EmbodiedProfile tracker parameter; multiple simultaneous functional units; schema validation on write (no stable machine-readable SCI schema to validate against yet).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions