Skip to content

Hatchling build hook

Use this when you build wheels with Hatchling and want an SBOM embedded automatically -- no separate CLI step to remember.

Pitloom embeds the SBOM at .dist-info/sboms/<name>-<version>.spdx3.json (e.g. .dist-info/sboms/mypackage-1.0.0.spdx3.json), per PEP 770 (wheels only), as compact canonical JSON.

Quick guide

[build-system]
requires = ["hatchling>=1.29.0", "pitloom>=0.20.2"]
build-backend = "hatchling.build"

[tool.hatch.build.hooks.pitloom]
# This can be empty

That's all -- hatch build and python -m build now embed the SBOM.

Installation

Add pitloom as a build requirement (Hatchling 1.29.0+ required) and add the [tool.hatch.build.hooks.pitloom] table to pyproject.toml (as shown above) -- both parts are required. Listing pitloom under [build-system] requires alone does not activate the hook: Hatchling only runs hooks whose name appears under [tool.hatch.build.hooks], so the table itself is what turns it on, even left empty.

No separate pip install step is needed beyond that -- the build front-end (pip, build, hatch) installs pitloom as a build-time dependency automatically, the same way it installs Hatchling itself.

[!NOTE] Hatchling 1.32.3 changed the build-hook plugin interface, and 1.32.4 reverted the change. Pitloom works with both, but other build-hook plugins written for the usual interface may fail to import on 1.32.3. If you pin Hatchling, prefer any version other than 1.32.3.

Usage details

Every hatch build/python -m build invocation now:

  1. Generates a Build SBOM (software_SbomType.build) for the project being built.
  2. Merges in any fragments registered under [tool.pitloom.fragment] (see the Python API tracking decorator, or a hand-authored fragment).
  3. Embeds the result into the wheel's .dist-info/sboms/ directory.

[!NOTE] Lock-file resolution and lock-file SHA-256 hash preservation are source-stage only (loom project / loom generate). Wheels built via hatch build do not consult source-stage lock files; dependency integrity hashes in embedded build SBOMs are resolved via PyPI (when online) or omitted (when offline).

The table's enabled key defaults to true, so an empty [tool.hatch.build.hooks.pitloom] is enough. Set enabled = false inside it to skip generation for a particular build without removing the table.

Status/skip/deviation messages the hook logs during a build follow the same grep-able INFO:/WARNING:/ERROR: stderr convention as the loom CLI (see Command line) -- e.g. a merge failure (see Merge fragments) fails the build outright with an ERROR: line, and "generation skipped: hook disabled" is an INFO:.

Configuration

Basename and fragments are configured under [tool.pitloom]:

[tool.pitloom]
sbom-basename = "custom-bom"       # -> "custom-bom.spdx3.json" (default: "<name>-<version>")
                                   # (a trailing ".spdx3.json" is dropped, with a WARNING)

[tool.pitloom.fragment]
files = ["fragments/model.json"]   # merge externally tracked fragments

Creator/tool metadata uses the same [[tool.pitloom.creator]] / [[tool.pitloom.creation-tool]] / [tool.pitloom.creation] tables the CLI reads -- see Creation metadata. Provenance detail is controlled the same way too -- see Metadata provenance.

See also

  • Command line -- generate an SBOM manually or post-process built wheels with loom embed-wheel.
  • Dependency sources and precedence -- why wheel embedding scopes dependencies to the build stage.
  • GitHub Action -- embed PEP 770 SBOMs in CI for any build backend.
  • Python API -- the tracking decorator that produces the fragments this hook merges.