The quantum reproducibility crisis
Quantum computing experiments are notoriously difficult to reproduce. When a paper claims "We achieved 73% fidelity on Grover's algorithm", reviewers and researchers have no way to verify or reproduce the result because critical information is missing.
What's actually needed: Exact versions of qiskit, qiskit-aer, numpy, scipy; which of the 127 qubits were used; what were the error rates; what optimization level; what routing algorithm.
You can't reproduce what you can't document. QBOM solves this by automatically capturing complete experiment provenance with zero code changes required.
| Capability | QBOM | Manual Logging | Notebooks |
|---|---|---|---|
| Zero code changes | Yes | No | No |
| Automatic capture | Yes | No | No |
| Calibration data (T1, T2, error rates) | Yes | Rarely | Rarely |
| Transpilation details | Yes | Often forgotten | Often forgotten |
| Content verification (hashing) | Yes | No | No |
| SBOM export (CycloneDX/SPDX) | Yes | No | No |
What is QBOM
QBOM (Quantum Bill of Materials) automatically captures complete provenance for quantum computing experiments. Just add one import line to your code, and QBOM invisibly records everything needed to reproduce your experiment.
Zero code changes
Add import qbom and your existing quantum code works unchanged. Provenance capture is invisible.
Multi-framework support
Full support for Qiskit, Cirq, and PennyLane. AWS Braket support planned.
Reproducibility scoring
Get a 0-100 score showing how reproducible your experiment is, with detailed component breakdown.
Standard exports
Export to CycloneDX and SPDX formats for software supply chain integration.
Getting started
Installation
Requires Python 3.10+. Clone and install from source:
git clone https://github.com/csnp/qbom.git
cd qbom
pip install -e ".[qiskit]"
qbom --version
Framework options:
pip install -e ".[qiskit]" # Qiskit support, including qiskit-aer
pip install -e ".[cirq]" # Cirq support
pip install -e ".[pennylane]" # PennyLane support
pip install -e ".[yaml]" # YAML export
pip install -e ".[all]" # Everything above
Basic usage
Add a single import line to your quantum code. It can go anywhere relative to your framework imports:
import qbom # Add this one line
# Your existing quantum code, unchanged
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
qc = QuantumCircuit(2, name="bell_state")
qc.h(0)
qc.cx(0, 1)
qc.measure_all()
backend = AerSimulator()
job = backend.run(qc, shots=4096)
result = job.result()
# View what was captured
qbom.show()
import qbom is captured
the same way as one imported before it. This was not true before
2026-08-05: the hook used an import API that Python 3.12 removed, so on
current Python the order above captured nothing and gave no warning. If
you cloned before then and see an empty trace, run
git pull and reinstall.
Sample output
╭──────────────────────────── QBOM: qbom_581b871b ─────────────────────────────╮
│ Summary: 2q circuit | on aer_simulator | 4,096 shots │
│ Created: 2026-08-05 17:47:23 UTC │
│ Hash: 48443acdc2c71632 │
│ │
│ ENVIRONMENT │
│ Python: 3.14.3 │
│ SDK: qiskit==2.5.1 │
│ qiskit: 2.5.1 │
│ qiskit-aer: 0.17.2 │
│ numpy: 2.5.1 │
│ scipy: 1.18.0 │
│ │
│ CIRCUIT │
│ Name: bell_state │
│ Qubits: 2 │
│ Depth: 3 │
│ Gates: 5 (1 1q, 1 2q) │
│ Hash: ad3deb49eae5f780 │
│ │
│ HARDWARE │
│ Provider: Aer (Local) │
│ Backend: aer_simulator │
│ Type: Simulator │
│ │
│ EXECUTION │
│ Job ID: dd51a610-431c-46d4-9b11-ab0a12997aba │
│ Shots: 4,096 │
│ │
│ RESULTS │
│ |00⟩ ███████████████░░░░░░░░░░░░░░░ 50.5% │
│ |11⟩ ██████████████░░░░░░░░░░░░░░░░ 49.5% │
│ │
╰──────────────────────────────────────────────────────────────────────────────╯
Captured on 2026-08-05 from the example above, running QBOM 0.1.0 against qiskit 2.5.1 and qiskit-aer 0.17.2. The trace identifier, job identifier and the split between the two measured states differ on every run.
What gets captured
| Category | What's Captured |
|---|---|
| Environment | Python version, all package versions |
| Circuit | Gates, depth, qubits, content hash |
| Transpilation | Optimization level, qubit mapping, routing |
| Hardware | Backend, calibration (T1, T2, error rates) |
| Execution | Shots, job ID, timestamps |
| Results | Counts, probabilities, result hash |
How it works
import qbom # 1. Import hook installed
from qiskit import ... # 2. Qiskit adapter activates
transpile(circuit, backend) # 3. Transpilation captured
job = backend.run(circuit) # 4. Execution captured
result = job.result() # 5. Results captured, trace saved
Traces are stored in ~/.qbom/traces/.
Reproducibility score
QBOM calculates a 0-100 score showing how reproducible your experiment is:
| Score | Rating | Meaning |
|---|---|---|
| 90-100 | Excellent | Fully reproducible |
| 70-89 | Good | Minor details missing |
| 50-69 | Fair | Some information missing |
| 25-49 | Poor | Major gaps |
| 0-24 | Critical | Cannot reproduce |
$ qbom score qbom_c4b17b13
╭─────────────────────────── Reproducibility Score ────────────────────────────╮
│ 71/100 (Good) │
╰──────────────────────────────────────────────────────────────────────────────╯
┏━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━┓
┃ Component ┃ Score ┃ Status ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━┩
│ Environment │ 20/20 │ ● │
│ Circuit │ 17/20 │ ◐ │
│ Transpilation │ 7/15 │ ◐ │
│ Hardware │ 9/25 │ ◐ │
│ Execution │ 10/10 │ ● │
│ Results │ 8/10 │ ● │
└───────────────┴───────┴────────┘
CLI reference
| Command | Description |
|---|---|
qbom list |
List recent traces |
qbom show <id> |
Display trace details |
qbom score <id> |
Calculate reproducibility score |
qbom validate <id> |
Check trace completeness |
qbom diff <id1> <id2> |
Compare two traces |
qbom drift <id> |
Analyze calibration drift |
qbom export <id> <file> |
Export to file |
qbom paper <id> |
Generate paper statement |
qbom verify <file> |
Verify trace integrity |
Example: list recent traces
$ qbom list
Recent QBOM Traces
╭───────────────┬──────────────────┬───────────────┬─────────┬───────╮
│ ID │ Created │ Backend │ Circuit │ Shots │
├───────────────┼──────────────────┼───────────────┼─────────┼───────┤
│ qbom_c4b17b13 │ 2025-01-15 14:40 │ aer_simulator │ 2q, d=3 │ 4,096 │
│ qbom_bf522429 │ 2025-01-15 14:45 │ aer_simulator │ 2q, d=3 │ 1,024 │
│ qbom_b8678a13 │ 2025-01-15 14:46 │ aer_simulator │ 2q, d=3 │ 1,024 │
╰───────────────┴──────────────────┴───────────────┴─────────┴───────╯
Example: generate paper statement
$ qbom paper qbom_c4b17b13
Reproducibility Statement
(For Methods section)
Experiments were performed using qiskit==2.2.3 on the aer_simulator simulator.
Circuits were transpiled with optimization level 2. Each experiment used 4,096
shots.
Complete QBOM trace: qbom_c4b17b13
Content hash: a9463e429a524897
Export formats
qbom export <id> trace.json # JSON (default)
qbom export <id> trace.cdx.json -f cyclonedx # CycloneDX SBOM
qbom export <id> trace.spdx.json -f spdx # SPDX SBOM
qbom export <id> trace.yaml -f yaml # YAML, needs the yaml extra
pip install -e ".[yaml]". Without it the command names the
missing package and exits non-zero; the other three formats need nothing
extra.
Python API
import qbom
# View current trace
qbom.show()
# Get trace object
trace = qbom.current()
print(trace.environment.packages)
print(trace.hardware.backend_name)
# Export
qbom.export("experiment.json")
# Scoped experiments
with qbom.experiment(name="VQE optimization"):
# quantum code here
pass
Ready to make your quantum experiments reproducible?
Get started with QBOM today - one import for complete provenance capture with zero code changes.
View on GitHub Take QRAMM AssessmentRelated resources
- CryptoScan Guide - Source code cryptographic discovery
- TLS Analyzer Guide - Network security assessment
- CryptoDeps Guide - Dependency crypto analysis
- PQC-Bench Guide - Post-quantum algorithm recommendations