How to build, run, test, and lint BioNeMo Inference Runtime (BioIR). For coding style and conventions, refer to Coding Guidelines; for the public API, refer to Python API.
-
GPU: An NVIDIA GPU listed in the BioIR Support Matrix.
- BioIR's CuTeDSL kernels, CUDA graphs, and CUDA runtime paths use NVIDIA GPU capabilities; they do not run on CPU-only or non-NVIDIA systems. Which architectures the fused kernels cover, and what the rest fall back to, is in Support Matrix.
- H200, H100, A100, L40S, GB200, and GB300 are release-qualified with measured speed, peak memory, and accuracy in the benchmarks.
-
Driver: minimum version 580.
- The NVIDIA Container Toolkit (below) reads the CUDA version requirement off
the image label and enforces it at
docker run.
- The NVIDIA Container Toolkit (below) reads the CUDA version requirement off
the image label and enforces it at
-
Docker: Docker Engine (minimum version 23.0.1), and the NVIDIA Container Toolkit (minimum version 1.13.5).
- They are needed for
docker/dev.shandmake -C docker wheel. - Ignore them if the host already has Python and the toolchain below, and docker is not used.
- They are needed for
-
Python: 3.12 for source development.
.python-versionselects the latest 3.12 patch through uv, the extension is builtcp312, and the published package metadata remainsrequires-python >=3.12,<4.0. -
uv: 0.12.x on a configured host. Install uv if it is not already available. The development image includes the repository's minimum accepted version.
-
Toolchain: a C++17 compiler and CUDA toolkit headers, only to build the extension from source. CMake and nanobind are declared build dependencies, so the build frontend supplies them.
Verify these requirements with the commands in Collecting System Information. If the requirements are not met, follow the GPU Stack guide.
The kernels are precompiled. Neither building the wheel nor running it needs
nvcc — only the driver's libcuda.so.1.
Host and development-container commands use uv and the committed lock. The container reuses its preinstalled locked dependencies for native rebuilds.
For convenience, docker/dev.sh builds the dev image and opens a shell in it,
with the checkout and the caches — weights, ccache, uv/pip, compiled kernels —
mounted from the host; refer to Docker Images.
Configure SSH authentication with GitHub, then clone the repository and fetch its Git LFS objects and submodules:
git lfs install &&
GIT_LFS_SKIP_SMUDGE=0 \
git clone --recurse-submodules \
git@github.com:NVIDIA-BioNeMo/BioNeMo-Inference-Runtime.git &&
cd BioNeMo-Inference-RuntimeThat leaves you on the host checkout.
From the repository root, create the locked Python 3.12 environment and build the editable native extension:
uv sync --locked
uv run --locked python -c "import bionemo_ir.libs._cutedsl_kernels; print('ok')"
uv run --locked prek installuv downloads a compatible Python when the host has no Python 3.12 interpreter.
It installs the dev dependency group by default. If nvcc is not on
PATH, set the wheel's CUDA tag explicitly:
CUDA_TAG=cu132 uv sync --lockedBuild the image and open its shell from the host:
docker/dev.shThe image already contains the third-party dependencies. Verify the checked-out lock, register the editable project in its writable environment, and install the hooks inside the shell:
uv lock --check
uv pip install --no-deps -e .
prek installFrom the host, invoke the containerized wheel build. The source is copied into
the image rather than mounted, so your checkout is untouched and only dist/ is
written.
# Run from the host; this command builds the wheel in a container.
make -C docker wheel
ls distThe artifact is bionemo_ir-<version>+cu<xyz>-cp312-cp312-linux_<arch>.whl.
To build directly on a configured host or inside the development container, use the lock-constrained repository wrapper:
scripts/build_wheel.sh --out-dir distThe wrapper exports the exact build group from uv.lock, constrains the
isolated PEP 517 environment with its hashes, and invokes uv build. It shares
build/ with the editable install, and it deletes the
extension from the source tree on its way through — every real build does, so a
stale copy cannot shadow the fresh one — but only an editable install puts one
back. Until you reinstall, pytest refuses to collect: the session starts by
requiring the extension and stops with the reason it could not load it.
Restore the host editable build with:
uv sync --locked --reinstall-package bionemo-irOn a configured host, uv sync creates .venv, installs the locked dev
group and installs BioIR in editable mode. Activate that environment for plain
python, pip, and prek commands:
uv sync --locked
source .venv/bin/activateInside the development container, verify the lock and register the mounted checkout without resolving dependencies again:
uv lock --check
uv pip install --no-deps -e .Both paths compile bionemo_ir.libs._cutedsl_kernels, a nanobind extension
embedding the CUBIN packs under cpp/kernels/cutedsl_*/cubins/. Verify the
active environment:
python -c "import bionemo_ir.libs._cutedsl_kernels; print('ok')"uv's host project workflow builds in an isolated environment constrained by the
build group in uv.lock. The image installs the same build and development
groups on top of the NGC Python environment so it keeps the tested torch,
Triton, and CUDA stack; --no-deps adds only the mounted checkout to its
writable development venv. Do not use the container command in a general
interpreter because it suppresses dependencies the package requires.
One thing the isolated build environment does not have is torch. The wheel's
CUDA tag comes from nvcc first and only falls back to torch.version.cuda, so
this is invisible wherever nvcc is on PATH. Where it is not, set the tag
rather than reaching for the flag:
# Configured host.
CUDA_TAG=cu132 uv sync --locked
# Development container.
CUDA_TAG=cu132 uv pip install --no-deps -e .On a configured host, uv tracks setup.py, the CMake and C++ sources,
committed CUBIN indexes and packs, build.env, and build-affecting environment
variables in the editable project's cache key. A later uv run or uv sync
rebuilds the extension when one of those inputs changes. Python-only edits
remain immediately visible through the editable install.
Consumer dependency ranges live in [project.dependencies] in
pyproject.toml. Development-only requirements live in
[dependency-groups]. The focused build group pins PEP 517 requirements;
release adds artifact inspection tools and is not installed in the default
environment.
Regenerate and verify the exact development resolution after either dependency source changes:
uv lock
uv sync --lockedThe lock covers Python 3.12 on Linux x86_64 and aarch64. Resolution fails when a
wheel-only dependency does not support either architecture. Upgrade
deliberately with uv lock --upgrade, inspect the lock diff, then run the same
locked sync and test gates; routine uv lock preserves versions already
selected.
Two things are needed:
The commands below use the configured-host form. Inside the development
container, omit the uv run --locked prefix.
-
Inputs:
examples/data/samples/carries small, real inputs — monomers, heterooligomers,RNA/DNA/ligandcomplexes, MSAs, and templates — so both routes below have something to fold without assembling your own data. -
Weights: pull the Boltz-2 checkpoint into the shared cache.
uv run --locked scripts/fetch_weights.sh --model boltz-2
OpenFold3 uses a gated Hugging Face checkpoint. Create a Hugging Face account, request access and accept the terms on
OpenFold/OpenFold3, then authenticate and fetch the checkpoint:uv run --locked hf auth login uv run --locked scripts/fetch_weights.sh --model openfold3
For a non-interactive environment, export
HF_TOKENinstead of runninghf auth login:export HF_TOKEN=hf_... uv run --locked scripts/fetch_weights.sh --model openfold3Refer to Model Weights for the other families, cache layout, token alternatives, and manual checkpoint staging.
The wheel is self-contained: the CUBINs are compiled into the extension, so
running needs no source checkout, no CMake, and no CUDA toolkit — only a driver
providing libcuda.so.1.
In the dev image every dependency is already installed, so build the venv on top of them and install the wheel alone:
python -m venv --system-site-packages /tmp/venv
/tmp/venv/bin/pip install --no-deps dist/bionemo_ir-*.whl
/tmp/venv/bin/python examples/folding/run_demo.py --output-dir /tmp/bioir-demoAn empty environment instead makes pip resolve the whole dependency closure — torch, ray, and the rest — from PyPI, which takes a while on a cold pip cache:
python -m venv /tmp/venv
/tmp/venv/bin/pip install dist/bionemo_ir-*.whlThat is the slower path and the stricter one: --no-deps above says nothing
about whether the wheel's dependencies are declared correctly.
Python puts the script's own directory on sys.path, not the repo root, so this
imports the installed package even when run from the checkout. That makes it the
check that a change survives packaging: a module that only imports because the
source tree happened to be on sys.path fails here. The
minimal runtime image applies both
checks at once, on a CUDA base carrying nothing else.
With the editable install from Build:
uv run --locked python examples/folding/run_demo.py # Boltz-2 on the bundled T1031 sample
uv run --locked python examples/folding/run_demo.py \
--model-source openfold3 \
--input examples/data/samples/monomers/T1031.json \
--output-dir output
uv run --locked python examples/folding/run_demo.py --helpThe default run writes T1031.cif and T1031_scores.json to the output
directory, and takes a few minutes on an A100. Which model sources the demo can
drive is in the folding demo README —
it is narrower than the support matrix.
uv run --locked scripts/run_tests.shThis stages missing model weights, then runs pytest in two phases: an xdist-parallel bulk phase, then the trees that must run serially.
Expect a green run with a large number of skips, from missing checkpoints or inputs — what actually runs depends on what you staged.
uv run --locked scripts/run_tests.sh --no-weights
uv run --locked scripts/run_tests.sh --helpFor one tree, file, or case, call pytest directly:
uv run --locked pytest -q tests/ops
uv run --locked pytest -q tests/_torch
uv run --locked pytest -q tests/ops/test_gated_sigmoid.py::test_gated_sigmoid_config_selection_is_source_freeStyle is enforced by prek, which runs the hooks
pinned in prek.toml. The default dev group installs it; wire up the git
hooks once:
uv run --locked prek installThey then run on git commit. To run them by hand:
uv run --locked prek run
uv run --locked prek run --all-filesA clean uv run --locked prek run --all-files is required for every PR, and
CI runs the same hooks. prek.toml lists them: a formatter and a linter per
language in the tree, plus the SPDX license header every source file carries.
Inside the development container, use the equivalent bare prek commands.
Both CI systems run their CPU gates through scripts/ci/: style.sh wraps the
hooks above, and contract.sh runs the build-contract and CUBIN suites with no
GPU and no built extension.
Fork, then sign commits with git commit -s; refer to
Contributing. Ensure all three pass:
- Style —
uv run --locked prek run --all-files - Build —
uv sync --locked, then import the extension - Tests —
uv run --locked scripts/run_tests.sh
Write the MR/PR title as the commit you want in history; squash is the default. Refer to Commits.