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.
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).
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.
CodeCarbon already measures
E(energy consumed) and already appliesI(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).
Or declaratively, matching how
BoAmpsOutput.from_file()works today:and via config,
output_methods = csv,sci.The handler writes
sci_report_<run_id>.jsoncontaining the SCI value, the four terms, and a provenance block (grid intensity source, measurement boundary, hardware, PUE, duration).Iis derived asemissions * 1000 / energy_consumedrather than recomputed, so the report is consistent with the CSV by construction.task_out()writes per-task reports when tasks are in use.The
MtermCodeCarbon 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
Mis user-declared only: it comes from the context file or the constructor, and when it is not supplied the report still emits, withM_gCO2e: 0andM_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
Ris never declared the report is written withsci: nulland astatusexplaining why, rather than dividing by zero or silently assumingR = 1.Why it fits
OutputMethodis a plain str enum incodecarbon/output_methods/base_output.pyand_init_output_methodsincodecarbon/emissions_tracker.pyappends one handler per selected member;BoAmpsOutputalready demonstrates the "final standards report,live_out()is a no-op" pattern. No new dependencies —jsonanddataclassescover 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
emissionsmeans; automatic embodied-carbon estimation; anEmbodiedProfiletracker parameter; multiple simultaneous functional units; schema validation on write (no stable machine-readable SCI schema to validate against yet).