| Created | 2026-02-06 |
|---|---|
| Last-Modified | 2026-11-05 |
| SPDX-FileCopyrightText | 2026-present Arthit Suriyawongkul |
| SPDX-FileType | DOCUMENTATION |
| SPDX-License-Identifier | CC0-1.0 |
See also: file-map.md for the full project directory tree.
An SBOM (Software Bill of Materials) generator for Python projects and AI
models. Supports the Hatchling, Poetry, setuptools, Flit and PDM build
backends (src/pitloom/extract/project/). The generator produces
SPDX 3.0 compliant SBOMs in JSON-LD format.
-
SPDX 3.0 data models (
spdx-python-model)- Fully migrated to the official
spdx-python-modellibrary - Proper JSON-LD serialisation and validation
- Deterministic UUIDv5 SPDX document IDs (
compute_doc_uuid) keyed on project name, version, normalised dependencies, and SHA-256 Merkle root of wheel files - Per-element sequential IDs (
generate_spdx_id) reproducible across builds
- Fully migrated to the official
-
Metadata extraction (
src/pitloom/extract/)project/pyproject.py-- readspyproject.toml; supports PEP 621[project], Poetry[tool.poetry](fallback when[project]is absent), and merging of both when both sections are present ([project]wins field-by-field)project/poetry.py-- extracts metadata from[tool.poetry]and[tool.poetry.dependencies]; converts Poetry version specifiers (^,~, bare versions) to PEP 440;[tool.poetry.group.*]dev/deploy dependency groups are intentionally excluded from the SBOMproject/setuptools.py,project/setuptools_cfg.py,project/setuptools_py.py-- extract metadata fromsetup.cfgandsetup.pyfor setuptools projects;detect_build_backend()auto-selects the right extractor; asetup()keyword overrides the samesetup.cfgoption, as setuptools doesproject/flit.py,project/pdm.py-- Flit and PDM dynamic-field resolution within the[project]path- Domain-specific extractors are grouped into subpackages:
project/(build backends),lock/(lock files),ai_model/(model formats),dataset/(datasets),remote/(remote registries/hubs), alongside top-level moduleswheel.py,env.py,binary.py,scanner.py wheel.py-- reads metadata from built.whlfiles (Analyzed SBOM) and computes file-level SHA-256 and SHA-512 hashesenv.py-- delegates topipdeptree --jsonto extract a complete dependency graph of the active installed environment (Deployed SBOM); see deployed-env-pipdeptree.mdbinary.py-- heuristic scanner that detects bundled third-party binary libraries (e.g..so,.dylib) within wheel files (phantom dependencies)- Extracts project metadata (name, version, description, authors, URLs)
- Handles dynamic versions from
__about__.py - Parses dependency specifications with version constraints
- Returns
(ProjectMetadata, PitloomConfig)tuple
-
SPDX 3 exporter (
src/pitloom/export/spdx3_json.py)- JSON-LD output using official bindings and SHACLObjectSet
- Clean API for building SPDX documents and adding elements
- Graceful component ingestion via
spdx3.JSONLDDeserializer
-
SBOM generator (
src/pitloom/assemble/)generate_project_sbom()/generate()orchestrates the full pipeline for source code (Source SBOM)generate_wheel_sbom()andgenerate_model_sbom()orchestrate the pipeline for built wheels and AI models (Analyzed SBOM), usingextract/wheel.py,extract/ai_model/andextract/binary.pyto identify phantom dependenciesgenerate_env_sbom()orchestrates the pipeline for active environments (Deployed SBOM), mapping the tree usingenv.py- Builds
DocumentModelfrom extracted metadata - Passes
DocumentModelto assembly functions (build(),build_deployed()) inassemble/spdx3/ - Merges pre-generated SBOM fragments
- Generates copyright information from metadata
-
Hatchling build hook (
src/pitloom/plugins/hatch.py)PitloomBuildHookregistered via pluggy entry point ([project.entry-points."hatch"])- Generates SBOM in
initialize(), stages to aTemporaryDirectory - Appends staged path to
build_data["sbom_files"]-- Hatchling 1.29.0+ places it at.dist-info/sboms/<filename>(PEP 770) natively finalize()cleans up the staging directory- Config:
[tool.hatch.build.hooks.pitloom] enabledonly; basename, fragments, and creator/tool metadata come from[tool.pitloom]/[[tool.pitloom.creator]]/[[tool.pitloom.creation-tool]]/[tool.pitloom.creation]-- the same settings the CLI uses
-
Command-line interface & API redesign (
src/pitloom/cli/,src/pitloom/__main__.py,src/pitloom/assemble/)__main__.pyis a thin entry point only: logging setup andargs.func(args)dispatch. Argparse construction (cli/parser.py), CLI-vs-pyproject.toml-vs-default option resolution (cli/options.py),--verbosereporting (cli/verbose.py), theidsubcommand (cli/id.py), and each subcommand's own_run_<verb>_command()+add_parser()(cli/commands/*.py, one module per subcommand) all live undercli/-- see cli-test-coverage-roadmap.md for the per-module breakdown- User-friendly argparse-based CLI with input-centric subcommands
(
project,wheel,model,env,merge,enrich,fragment,embed-wheel,verify-wheel,validate-wheel,id) and a smart entrypointloom generate [TARGET](requires-o, unlike the input-centric subcommands, which each have an obvious target-derived default filename) - Emitted SBOM data model strictly complies with CISA 6 SBOM Types (Source, Build, Analyzed, Deployed, Runtime per CISA April 2023 guide) and SPDX 3.0.1
loom projectscans unbuilt source directories,.tar.gz/.zipsdist archives or Git repository URLs (Source SBOM; see remote-git-ingestion.md)loom wheelscans built.whlarchives (Analyzed SBOM)loom modelscans local model files or Hugging Face repositories with explicit--offlinesupport (Analyzed AIBOM)loom envscans the active installed environment (Deployed SBOM)loom mergestitches dynamic execution fragments (Runtime SBOM)- Python API harmonised 1:1 (
pitloom.generate(),generate_project_sbom(),generate_wheel_sbom(),generate_model_sbom(),generate_env_sbom(),generate_merged_sbom(),enrich_model()) - See working-docs/implementation/cli-ux.md
- Default output filename derived from project metadata
(
{name}-{version}.spdx3.json) or[tool.pitloom] sbom-basenamewhen set - Creator information options
- Clear error messages
-
Metadata provenance tracking (
src/pitloom/assemble/spdx3/provenance.py,src/pitloom/extract/project/pyproject.py,src/pitloom/loom.py)- Tracks source of each metadata field
- Records extraction method (static, dynamic, or inferred)
- Supports dynamic introspection via
loom.pyinspection - Recorded as SPDX 3 Core
Annotationelements (structured, machine-readable JSON), with the original SPDX 3commentattribute kept for back-compat, controlled by[tool.pitloom.provenance] - See working-docs/implementation/provenance/metadata-provenance.md and annotation-provenance.md
-
ML tracking SDK (
src/pitloom/loom.py)- Dual-syntax ContextDecorator (
@loom.runandwith loom.run) - Emits SPDX 3 SBOM fragments automatically during ML executions
- Seamlessly ingested into project SBOMs using
[tool.pitloom.fragment]config
- Dual-syntax ContextDecorator (
-
Model & provenance tests
- SPDX ID generation
- CreationMetadata serialisation and provenance tracking
spdx-python-modelvalidation
-
Metadata extraction tests
- Basic metadata extraction and generic fragment paths
- Error handling for missing files
- Dynamic and build-time version extraction via
importlib.metadata
-
Generator integration tests
- End-to-end SBOM generation
- Generic fragment merging via Deserialisation
-
SDK tracker tests
test_loom.pyverifies both Decorator and Context Manager tracking- Asserts caller-inspection relative path generation
- Linting: pylint 10.00/10, flake8 clean, ruff clean
- Type checking: mypy -- no issues across all source files
- Type hints: Comprehensive type annotations throughout
- Documentation: Inline docstrings for all public APIs
- README.md: Complete usage guide with examples
- working-docs/implementation/demo.md: Prototype capabilities and validation
- working-docs/implementation/provenance/demo-provenance.md: Provenance tracking demo
- working-docs/design/format-neutral-representation.md: Multi-format support plan
- working-docs/implementation/provenance/metadata-provenance.md: Provenance tracking specification
- working-docs/design/metadata-sources.md: Metadata sources research and integration plan
- working-docs/implementation/setuptools-support.md: Setuptools extractor design and limitations
- Inline documentation: Comprehensive docstrings
Historical snapshot, early prototype. The invocation and element counts below predate the input-centric CLI subcommands (
project/wheel/model/env/generate/id, among others) and provenance-as-Annotation (see annotation-provenance.md) -- a current run usesloom project <path>(orloom generate <path>), not the bare un-namespaced form shown here, and emits additionalAnnotationelements for provenance. Kept as a record of the initial validation, not a spec for current output shape; see examples/sentimentdemo-aibom/ for a current, fuller worked example (AI pipeline, fragments, dataset).
Successfully generated SPDX 3 SBOM for the reference repository:
$ loom project /tmp/sentimentdemo -o sbom.spdx3.json
Generating SBOM for project in: /tmp/sentimentdemo
SBOM written to: sbom.spdx3.json
- Total Elements: 14
- CreationInfo: 1 (with timestamp and creator)
- SoftwareAgent: 1 (default createdBy agent when no creator is named;
one
Person/Organizationper[[tool.pitloom.creator]]table instead when set) - Tool: 1 (Pitloom, in createdUsing)
- SpdxDocument: 1 (root document)
- software_Sbom: 1 (SBOM declaration)
- software_Package: 5 (main package + 4 dependencies)
- Relationship: 4 (dependsOn relationships)
Main package:
- Name: sentimentdemo
- Version: 0.0.2 (dynamically extracted)
- Download: https://github.com/bact/sentimentdemo
- Description: Full description preserved
Dependencies (all captured correctly):
- fasttext: 0.9.3
- newmm-tokenizer: 0.2.2
- numpy: 1.26.4
- th-simple-preprocessor: 0.10.1
Src-layout, one directory per pipeline layer
(extract/ -> core/ -> assemble/ -> export/), plus a cli/
package for the CLI surface and a tests/ tree that mirrors
src/pitloom/<package>/ once an area grows past a few files. See
file-map.md for the full tree.
- Easy to add new extractors (as Poetry, setuptools, PDM and Flit were)
- Easy to add new assemblers/exporters (CycloneDX, AIDOC, etc.) consuming
the same
DocumentModel-- no changes to extractors needed - Clean separation of concerns: extractors ->
DocumentModel-> serialisers
- src-layout for proper package structure
- Type hints with Python 3.10+ compatibility
- Comprehensive error handling
- Runtime dependencies kept minimal and declared in
pyproject.toml
| Feature | Reference SBOM | Pitloom Generated | Status |
|---|---|---|---|
| SPDX 3.0 Structure | ✅ | ✅ | ✅ Complete |
| Package Metadata | ✅ | ✅ | ✅ Complete |
| Dependencies | ✅ | ✅ | ✅ Complete |
| Relationships | ✅ | ✅ | ✅ Complete |
| File-level Details | ✅ | ✅ | ✅ Complete |
| AI/Dataset Profiles | ✅ | ✅ | ✅ Complete |
| License Expressions | ✅ | ✅ | ✅ Complete |
Legend:
- ✅ Complete: Fully implemented
⚠️ Basic: Core functionality present, enhancements planned- 🔄 Roadmap: Planned for future releases
See working-docs/design/roadmap.md for the canonical, up-to-date roadmap.