████████╗████████╗ ██████╗ ██╗ ██████╗
╚══██╔══╝╚══██╔══╝ ██╔══██╗ ██║ ██╔═══██╗
██║ ██║ █████╗ ██████╔╝ ██║ ██║ ██║
██║ ██║ ╚════╝ ██╔══██╗ ██║ ██║ ██║
██║ ██║ ██████╔╝ ██║ ╚██████╔╝
╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝
TT-Bio runs Boltz-2, ESMFold2, Protenix-v1 and Protenix-v2, OpenFold3, OpenBind-0, OpenDDE, and RoseTTAFold3 structure prediction, BoltzGen, RFdiffusion3 and PXDesign binder/protein design, and ESMC protein embeddings, SaProt structure-aware protein embeddings, and Nesso-1 structure-free binding affinity on Tenstorrent Blackhole and Wormhole, supporting single-card and multi-card configurations (e.g. QuietBox with 4 cards or Galaxy server with 32 cards). Multiple machines can also be combined into a single prediction run.
Benchmarks: tt-bio.com has throughput and cost for every model against NVIDIA DGX H200, B200 and A100. The full benchmark page has the measured seconds behind every figure, the fixtures they were run on, the run conditions and the cost model.
Accuracy
Every model TT-Bio serves is validated against its official reference implementation on the same input and reproduces it within that reference's own run-to-run noise. See docs/implementation-parity.md for the methodology, per-target results, and reproduction commands.
Performance and cost
Predictions and designs per hour per server, and throughput per dollar of purchase price and of total cost of ownership, measured against NVIDIA DGX systems. See the benchmark page for the numbers, the fixtures they were measured on, and the cost model behind them.
Installation
Create a Python virtual environment with Python 3.10 or 3.12, install with the Tenstorrent extra, then install the matching Tenstorrent system dependencies.
python3.10 -m venv env
source env/bin/activate
pip install 'tt-bio[tenstorrent]'
tt-bio install-deps
tt-bio install-deps installs the Tenstorrent system dependencies that match this release. It may ask for your sudo password.
On a host without a Tenstorrent card, plain pip install tt-bio is enough: the Boltz-2 CPU/GPU path (--accelerator cpu / --accelerator gpu) and the CLI work without the Tenstorrent SDK. The other models run on Tenstorrent only.
From GitHub / source
Pin to a tagged release, track nightly main (may be untested), or work from an editable clone:
pip install "tt-bio[tenstorrent] @ git+https://github.com/moritztng/tt-bio.git@v0.9.0" # pinned release, see Releases for the latest
pip install "tt-bio[tenstorrent] @ git+https://github.com/moritztng/tt-bio.git@main" # nightly
# or
git clone https://github.com/moritztng/tt-bio.git
cd tt-bio
pip install -e '.[tenstorrent]'
tt-bio install-deps
Drop the [tenstorrent] extra on a host without a Tenstorrent card.
Optional: Build TT-Metal / TT-NN from Source
If you need to build from source, follow the Tenstorrent Installation Guide.
Verify Installation
tt-bio --version # or -V; prints the installed version
tt-bio --help
tt-bio predict --help
tt-bio msa --help
Troubleshooting
Single-host prediction needs no MPI setup of yours. tt-metal ships the OpenMPI it wants, and a
system OpenMPI on the environment breaks that build instead of replacing it: with OMPI_MCA_* or
OPAL_PREFIX set, or a foreign libmpi on LD_LIBRARY_PATH, MPI_Init aborts before the fold
starts. tt-bio warns when it sees one and changes nothing for you. To clear it for the current
shell:
unset OMPI_MCA_pml OMPI_MCA_plm OPAL_PREFIX LD_LIBRARY_PATH
Basic Usage
Structure Prediction
tt-bio predict examples/prot.yaml --model boltz2 --override
Every command names its model with --model:
boltz2: folds complexes of proteins, DNA, RNA, and ligands and predicts binding affinity. MSA-dependent (uses an MSA by default).esmfold2/esmfold2-fast: fold complexes of proteins, DNA, RNA, and ligands (CCD code or SMILES) on-device, no MSA required (esmfold2-fastis the lighter, faster checkpoint). Modified residues are folded as the modified chemistry. Cyclic chains, templates and constraints are not supported and are refused.protenix-v1/protenix-v2: fold complexes of proteins, RNA, DNA, and ligands (an AlphaFold3-family model, the Protenix reproduction); MSA-dependent for proteins (uses an MSA by default), and also emit a PAE/PDE matrix with--write_pae.protenix-v1is upstream's own v0.5.0 base checkpoint: half the pair width and 4 trunk recycles againstprotenix-v2's 10, so it is the cheaper of the two. Covalentbondconstraints and modified residues are supported, andprotenix-v2takes per-chain templates as a precomputed alignment.npz.protenix-v1's checkpoint ships no template blocks, so it refuses templates; cyclic chains are refused on both.openfold3: folds proteins, RNA and DNA (an AlphaFold3-family model, the OpenFold3 reproduction); MSA-dependent (uses an MSA by default), with optional per-chain templates. Polymer chains only: ligands, covalent bonds, cyclic chains and modified residues are refused. Weights come from the OpenFold consortium; pointOF3_CKPTat them.openbind: OpenBind-0, the same OpenFold3 stack on upstream's v0.5.0 checkpoint, tuned for protein-ligand co-folding. Takes ligands by SMILES or CCD code alongside protein, RNA and DNA chains; MSA-dependent (uses an MSA by default), with optional per-chain templates. Covalent bonds, cyclic chains and modified residues are refused. Weights are a separate file fromopenfold3and are not downloaded; pointTT_BIO_OPENBINDat them (seedocs/weights.md).saprot: structure-aware protein embeddings, an ESM-2 encoder over a fused amino-acid + Foldseek-3Di vocabulary (446 tokens). Needs a structure for the 3Di structural tokens (--structure); runs sequence-only without it. Use for variant-effect / mutation-fitness scoring and function prediction.nesso1(tt-bio affinity): protein-ligand binding affinity without a structure. Predicts a soft distogram and reads the affinity off that, so it is much cheaper than folding and it returns no coordinates. Proteins and ligands only.opendde/opendde-abag: antibody-antigen co-folding built on the Protenix-v2 stack plus a structural-token expander;opendde-abagselects the antibody-antigen checkpoint. Protein and ligand chains, with covalentbondconstraints, modified residues and per-chain templates; nucleic acids and cyclic chains are refused. Proteins are MSA-dependent (uses an MSA by default, like Protenix-v2).rf3: folds complexes of proteins, RNA, DNA, and ligands (an AlphaFold3-family model, RoseTTAFold3 from the Institute for Protein Design); MSA-dependent for proteins (uses an MSA by default). Writes AlphaFold3-style<name>_summary_confidences.json(pTM, ipTM, chain-pair PAE/PDE, ranking score) next to each structure. Non-canonical residues, covalent modifications and cyclic chains reach the model only through RF3's own JSON/CIF spec, whichfeaturizereads directly; the YAML/FASTA input builds its spec from chains alone, so aconstraints:,modifications:,templates:orcyclic:block is refused there rather than dropped. Weights download from the IPD on first use.
tt-bio predict examples/prot.fasta --model esmfold2-fast --fast
tt-bio predict examples/fkg_ligand.yaml --model esmfold2 # protein + ligand co-fold, no MSA
tt-bio predict examples/prot.yaml --model protenix-v2 # MSA on by default; NA/ligand chains are single-sequence
tt-bio predict examples/prot.yaml --model protenix-v1 # upstream's v0.5.0 base checkpoint, 4 recycles
tt-bio predict examples/prot.fasta --model openfold3 # MSA on by default; set OF3_CKPT to the weights file
tt-bio predict examples/affinity.yaml --model openbind # protein + ligand co-fold; set TT_BIO_OPENBIND
tt-bio predict examples/9dsg_abag.yaml --model opendde-abag # antibody-antigen co-fold, MSA on by default
tt-bio predict examples/prot.yaml --model rf3 # MSA on by default; weights fetch from the IPD
tt-bio predict examples/prot.yaml --model rf3 \
--partial_t 150 --partial_structure start.cif # refine start.cif instead of folding from scratch
tt-bio predict targets.yaml --model rf3 --early_stop_plddt 0.5 # skip the rollout on hopeless targets
| Feature | Boltz-2 | ESMFold2 | Protenix-v1 | Protenix-v2 | OpenFold3 | OpenBind-0 | OpenDDE | RF3 |
|---|---|---|---|---|---|---|---|---|
| Input | protein/DNA/RNA/ligand complex | protein/DNA/RNA/ligand complex | protein/DNA/RNA/ligand complex | protein/DNA/RNA/ligand complex | protein/RNA/DNA (polymer-only) | protein/DNA/RNA/ligand complex | protein complex (antibody-antigen) | protein/DNA/RNA/ligand complex |
| MSA | MSA-dependent (on by default) | single-sequence | proteins MSA-dependent (on by default), NA/ligand single-sequence | proteins MSA-dependent (on by default), NA/ligand single-sequence | proteins MSA-dependent (on by default) | proteins MSA-dependent (on by default) | proteins MSA-dependent (on by default) | proteins MSA-dependent (on by default) |
PAE/PDE output (--write_pae) |
no | no | yes | yes | no | no | no | in _summary_confidences.json |
Ligands, nucleic acids, modified residues, cyclic chains, covalent and pocket constraints,
templates and affinity are one generated matrix:
docs/model-capabilities.md. Anything a model cannot honour is
refused by name before the fold starts, never accepted and dropped.
Targets of 850-1095 residues have folded on a single 12 GiB Wormhole card on every structure model, but that is not the same as a ceiling: a few models fail at sizes below one they handle, because the failure is an L1 layout clash that follows the padded tile shape rather than the residue count -- a model can fold 608 residues and throw at 576. So the size a model is safe up to is the largest one below its first measured failure, which for several models on Wormhole is under 1024:
| model | Wormhole limit | first measured failure |
|---|---|---|
opendde, opendde-abag |
1024 | 1088 |
openfold3 |
1024 | none found; top of the ladder |
openbind |
960 (residues; a ligand adds tokens) | 1024 |
pxdesign |
768 (target residues) | none found; top of the ladder |
protenix-v2 |
1024 (residues; a ligand adds tokens) | 1095 |
esmfold2 |
1024 (residues; a ligand adds tokens) | 1056 |
esmfold2-fast |
1152 (residues; a ligand adds tokens) | 1248 |
rfd3 |
1024 (motif + designed) | none found; top of the ladder |
boltzgen |
14786 (atoms in the target) | none found; top of the ladder |
esmc-6b (embed) |
1968 | 1984 |
Ask for more than a model's limit and tt-bio refuses before it opens a device, naming the
model, the limit and any model that does take the input. rf3 is not in the table because
it folds every rung to 1095 residues, the top of its ladder. boltz2 and nesso1 have no
measured limit and are never refused.
boltzgen is the one model sized on atoms rather than residues, because its wall follows the
target's atom count and atoms per residue vary with what the target is made of: the 14786-atom
rung is 1831 residues of a deposited protein, and a lighter target reaches more residues in the
same number of atoms. The designed binder is outside the number, which was 80 residues at every
rung. tt-bio counts the atoms out of the structure file your file: entity points at, so the
refusal still lands before a device opens.
Blackhole has more memory per chip, so it is a separate table and the Wormhole numbers do not carry over. Six models have been walked to a failure on a p150a:
| model | Blackhole limit | first measured failure |
|---|---|---|
saprot-35m (embed) |
126976 (longest sequence) | 131072 |
esmc-300m, esmc-600m, saprot-650m, saprot-1.3b (embed) |
114688 (longest sequence) | 126976 |
pxdesign |
2500 (target residues) | 3000 |
The embedding wall is one allocation: the model asks for the whole sequence-by-sequence attention
matrix as a single buffer that grows with the square of the sequence length, 34.4 GB at 131072
residues against a 31.9 GiB card. saprot-35m gets one rung further than the rest because its
weights are the smallest and leave more room for it. Everything else is unmeasured on Blackhole
and refused nothing, including boltzgen, which designs against a 16948-atom target there.
Blackhole structure-model ladders have also been walked, and nothing enforces them (an oversized
request is accepted rather than refused there). rf3 folds 768 residues on a p300c in 102 s and
does not return at 896, though on a p150a it reaches 1088 -- root-caused (not an external kill)
but not yet fixed. protenix-v2 folds to 1024 on both Blackhole boards. esmfold2 also folded
to 1024 until a row-block fix landed and raised its p150a ceiling to at least 1536 tokens (the
row-block retry path no longer assumes a module it doesn't have, and the diffusion pair
transition now uses the same refuse/halve/retry mechanism); its failure point past 1536, and its
p300c ceiling, have not been re-walked since. So on a p300c, treat rf3 over 768 residues as a
known gap rather than something tt-bio will refuse for you.
The limits were measured with an MSA, which is the default for the models that take one, and at the
deepest alignment the MSA pipeline actually produces. Folding single-sequence is roomier, so if you
know your run is lighter than the ladder that set the limit, TT_BIO_SIZE_LIMIT=0 turns the refusal
into a warning and runs it anyway.
A ligand counts against these limits. Its heavy atoms are tokens the model pays for exactly like
residues, and on esmfold2, esmfold2-fast, openbind and protenix-v2 the wall is on tokens,
so a cocrystal is checked on residues plus ligand atoms rather than on the residue count alone.
esmfold2 folds 1024 residues, which leaves no room at all: 1024 residues plus any ligand is
refused, and 991 residues with a 33-atom ligand folds. openbind was walked with a 35-atom
ligand already bound, so its 960 has room for a ligand of 64 atoms and refuses 65. Either way the
refusal names the token count and the wall, and it arrives before a device is opened instead of
as an out-of-memory error part way through the fold.
esmfold2-fast is the same architecture at half the trunk depth and is roomier, which is why it
has its own row rather than sharing one: it folds 1152 residues and fails at 1280, where the full
trunk already fails at 1057.
The pair track switches to row-blocked execution at a size threshold smaller targets never reach, so their speed and numerics are untouched. See docs/large-targets.md. Perf levers are gated at several sequence lengths, not just one; the release gate re-checks the ladder against a recorded baseline. See docs/size-generality.md.
All structure models support the sampling, output-format, and scheduling options.
MSA, affinity, constraint, and auxiliary-output options apply only where listed
below. Each model downloads its weights automatically on first use, except
OpenFold3: fetch the consortium checkpoint yourself and point OF3_CKPT at it,
or put it at ~/.boltz/of3-p2-155k.pt. tt-bio weights lists every artifact with
its status, size and path; --download prefetches, --prune reclaims disk. Set
TT_BIO_CACHE to move all of it (both ~/.boltz and the Hugging Face cache, about
65 GiB) somewhere with room. See docs/weights.md.
Boltz-2, Protenix-v1, Protenix-v2, OpenFold3, OpenDDE, and RF3 are MSA-dependent and use an MSA by default, a local
ColabFold DB (~/.boltz/msa_db) if one is set up (see Offline MSA),
otherwise the online ColabFold server. Sending sequences to the online server (api.colabfold.com)
leaves your machine; a one-line notice is printed when that fallback is used. Pass
--msa_db_path for a private offline database, or --single_sequence to deliberately fold
without an MSA (lower accuracy; for batch-screening orphan sequences). OpenDDE multi-chain
predictions still request paired MSAs from --msa_server_url; use --single_sequence to
prevent all network MSA requests. ESMFold2 is single-sequence.
--fast makes some operations use a lower-precision numeric format that runs faster. Accuracy is typically very close.
OpenDDE-abag matches the upstream checkpoint on the standard 1AHW antibody-antigen target. Both implementations perform poorly on 9DSG.
predict accepts either a single YAML/FASTA file or a directory containing many input files.
A live display shows the progress of each target. Prediction uses up to one card
per pending target, labelled in the display (quietbox:tt0, quietbox:tt1, ...).
Models load once per active card and stay resident:
tt-bio predict proteins/ --model boltz2 --out_dir results --fast
Pass --devices 0,1,2,3 to pick or limit the available cards. A single target
remains a single-card fold; additional cards increase throughput only when
multiple targets are queued.
Once enough folds run at once that each worker is down to a couple of CPU threads,
tt-bio also has their idle thread pools sleep between device syncs instead of
spinning on them. The output is identical either way, and a single fold is
unaffected. See Tuning flags for the measurement, or set
OMP_WAIT_POLICY yourself to take the decision back.
If you have additional machines with Tenstorrent cards, you can add them to a single run; see Optional: Multi-Machine Prediction.
Protein Embeddings (ESMC)
Turn protein sequences into ESMC language-model embeddings on-device (no
folding, no MSA). DATA is a FASTA file, a directory of them, a YAML
{id: sequence} mapping, or a bare sequence string:
tt-bio embed proteins.fasta --model esmc-600m --out_dir embeddings
tt-bio embed "MQIFVKTLTGKTITLEV..." --model esmc-600m # one-off sequence
--model selects the ESMC variant (esmc-300m, esmc-600m, esmc-6b). For
each sequence you get its per-residue embeddings ([length, d_model]
float32, one row per amino acid, row order == input order) and a pooled
whole-sequence vector ([d_model] float32, --pool mean/max/cls).
--out_dir (default ./embeddings) gets:
<id>.npzper sequence:per_residue,pooled(+logitswith--logits);--format npz, defaultembeddings.parquet: pooled vectors, one row per sequence;--format parquetmanifest.json: model/pool/shapes/dtype and which file holds each sequence
Add --logits for the per-residue amino-acid predictions (300M/600M only),
and --fast for the lower-precision weight path. Weights download automatically on
first use.
Sequences batch automatically on 300M/600M (--batch_size, default 8): a
padded, length-bucketed device forward per batch, masked so results are
identical to running each sequence alone. Single-sequence calls
(--batch_size 1, e.g. serving one sequence at a time) replay through a
captured device trace once a length bucket repeats, up to ~1.5x faster per
call on QuietBox-class hosts, bit-identical, no flags needed.
To embed a large batch faster, shard it across several cards with
--devices 0,1,2,3: one worker per card, results reassembled in input order
and identical to a single-card run:
tt-bio embed proteins.fasta --model esmc-600m --devices 0,1,2,3
Measured, not assumed: fanout only pays off when there's enough work per shard to amortize each worker's model-load and device-init cost. On small batches it can be flat or worse than a single card. esmc-6b scales to 4 cards on suitably large batches. Reach for --devices on large batches, not small ad-hoc jobs; use --controller (below) for repeated/production embedding.
For repeated/production embedding, submit to a persistent pool instead: a worker loads its model once and keeps it resident across every call, so the reload cost above is paid once per worker, not once per invocation:
tt-bio controller --listen 8765 # starts + keeps a worker per local card
tt-bio embed proteins.fasta --model esmc-6b --controller http://localhost:8765
The same capability is available from Python:
from tt_bio import esmc
emb = esmc.embed("MQIFVKTLTGKTITLEV...", model="esmc-600m")[0]
emb.per_residue # [L, d_model] float32
emb.pooled # [d_model] float32
# Shard a large set across cards (data-parallel, order preserved):
embs = esmc.embed(sequences, model="esmc-600m", devices=[0, 1, 2, 3])
Structure-Aware Protein Embeddings (SaProt)
SaProt is a structure-aware protein language model, an ESM-2 encoder over a fused
amino-acid + Foldseek 3Di vocabulary (446 tokens). Where ESMC is sequence-only, SaProt
also encodes local structure, so its embeddings and MLM logits reflect both sequence
and shape. Use it for variant-effect / mutation-fitness scoring and function prediction
when you have a structure (predicted or experimental: fold it with tt-bio predict
first, then score it with SaProt).
tt-bio saprot proteins.fasta --model saprot-650m --structure structs/ --out_dir embeddings
tt-bio saprot proteins.fasta --model saprot-650m # sequence-only (3Di = '#')
tt-bio saprot proteins.fasta --model saprot-650m --devices 0,1 # data-parallel across 2 cards
--structure is a PDB/cif file (single sequence) or a directory of <id>.pdb/<id>.cif
files, one per FASTA id. The 3Di structural tokens are computed on host with
Foldseek (conda install -c bioconda foldseek;
--foldseek PATH or FOLDSEEK_BIN if it is not on PATH); it runs off-device. Residues
the structure does not resolve get the # unknown-structure token, and a structure that
is not of the sequence you passed is refused rather than lined up by length. Omit
--structure for sequence-only mode (lower accuracy for 35M/650M; the 1.3B works
sequence-only).
For each sequence you get per-residue structure-aware embeddings ([length, d_model]
float32) and a pooled vector, plus per-residue MLM logits ([length, 446] with
--logits) over the fused vocabulary, the log-likelihoods used for zero-shot mutation
scoring. Output layout matches tt-bio embed (<id>.npz / embeddings.parquet /
manifest.json).
--model selects the variant (saprot-35m, saprot-650m, saprot-1.3b). --devices 0,1,2,3
shards the input across cards data-parallel (one pinned subprocess each, results reassembled in
input order), bit-exact vs single-card with --batch_size 1. Parity vs the reference HuggingFace
checkpoint, the multi-card bit-exactness check, and warm throughput are in
docs/saprot-parity.md.
Python:
from tt_bio import saprot
emb = saprot.embed(("MQIFVKTLTGKTITLEV...", "dweweaepvrdidi..."), model="saprot-650m")[0]
emb.per_residue # [L, d_model] float32, structure-aware
emb.logits # [L, 446] float32 (with return_logits=True)
Weights
Weights download on first use, so nothing here is required. tt-bio weights is for when
you want to see or move them:
tt-bio preflight protenix-v1 # can this machine run it right now?
tt-bio weights # every artifact: status, size, resolved path
tt-bio weights --download # prefetch everything (e.g. before going offline)
tt-bio weights --download boltz2 # or just one model's set
tt-bio weights --prune # reclaim superseded revisions and leftovers
tt-bio preflight answers before you submit a job, and exits non-zero when something is
missing, so it works in a script. When weights are missing it also measures whether the
hosts they come from can be reached from this machine.
A full set is about 65 GiB. It lands in ~/.boltz and the Hugging Face cache; set
TT_BIO_CACHE to put both somewhere with more room. Each artifact also takes its own
override, so TT_BIO_BOLTZ2_CONF=/mnt/weights/boltz2_conf.ckpt loads that file instead of
downloading. Rows show as corrupt if a download was interrupted, and are re-fetched rather
than loaded. No download waits forever: a source that sends nothing is dropped for the next
one, and the error names every host tried. See docs/weights.md.
Offline MSA (Optional)
Use this if you have enough disk and RAM and want local MSA. This avoids external MSA server calls and is faster for repeated runs.
tt-bio msa
tt-bio predict examples/prot.yaml --model boltz2 --override
tt-bio msa downloads UniRef30 to ~/.boltz/msa_db (~100GB download, ~500GB on disk after indexing). predict auto-detects this path.
To add EnvDB and use it in prediction: EnvDB can improve MSA coverage when UniRef30 hits are weak, at higher disk/RAM cost.
tt-bio msa --db all
tt-bio predict examples/prot.yaml --model boltz2 --use_envdb --override
Key Options:
--override: Re-run from scratch, ignoring cached files--use_msa_server: Generate MSA via ColabFold API--msa_db_path: Use a local database at a custom path (e.g.--msa_db_path /data/colabfold_db)--use_envdb: Include EnvDB in offline MSA (tt-bio msa --db all)--accelerator=tenstorrent: Use Tenstorrent hardware (default, or usecpu/gpu)--fast: Makes some operations use a lower-precision numeric format that runs faster; accuracy is typically very close--debug: Show all raw output from the hardware and libraries instead of the progress display--debug --log: Same as--debug, but also print what each device is currently working on
Shared MSA Server (Optional)
Host the database on one machine and let others fetch MSAs from it over HTTP, so each prediction machine need not keep its own ~500GB copy.
# On the machine with the database:
tt-bio msa-server --listen 0.0.0.0:8765
# On any other machine (no local database needed):
tt-bio predict examples/prot.yaml --model protenix-v2 --msa_endpoint http://HOST:8765
The server runs the same offline colabfold_search and serves unpaired {hash}.a3m, with a shared cache and a search-concurrency cap (--max_concurrent). Add --token to require Authorization: Bearer <token>. --msa_endpoint applies to --model esmfold2, protenix-v1, protenix-v2, openfold3, opendde, and rf3.
Binding Affinity Prediction (Boltz-2)
Predict binding affinity for protein-ligand complexes:
tt-bio predict examples/affinity.yaml --model boltz2 --use_msa_server --override --affinity_mw_correction
The --affinity_mw_correction flag applies molecular weight correction for more accurate predictions.
An affinity run folds the complex and then runs a second model that has its own
64-block trunk, so it costs more than a structure-only fold. All of it runs on the
card. FKBP12+SB3 at the default affinity protocol (200 sampling steps, 5 affinity
samples, single sequence) takes about 206 s per ligand on one Blackhole p150a,
measured as a whole tt-bio predict invocation with model load included.
--sampling_steps_affinity and --diffusion_samples_affinity are the two flags that
move that wall most.
The affinity trunk runs in fp32 because the predicted log10(IC50) is sensitive to activation precision, and that is not configurable. Earlier releases ran it in fp32 on the host CPU instead, which is why affinity used to take minutes per ligand and looked CPU-bound.
Binding Affinity Without a Structure (Nesso-1)
tt-bio affinity predicts protein-ligand affinity without folding anything. Nesso-1 has no
structure module, so it returns a number, not coordinates:
tt-bio affinity examples/affinity.yaml # one complex
tt-bio affinity ligands/ --out_dir screen # a directory is a screen
A directory keeps the model resident across inputs, so a ligand series against one target pays the
weight load and the kernel compile once. Output is one <id>_affinity.json per input plus an
affinity.csv for the whole run: the affinity value (mean of a two-member ensemble, and each
member), a binary binder probability, and six distogram entropies.
On DAVIS it reaches 0.662 mean within-target Pearson against measured Kd (0.175 for a molecular-weight-only control), matching the 0.636 the upstream implementation gets on an H200.
It is far cheaper than folding for the same question. One 512 aa prediction takes 8.3 s of model time on one Blackhole card, 33 s for the whole command including featurisation; Boltz-2 affinity takes 386 s for the same command on the same input, which is what tt-bio shipped for this before. Against a GPU it is 7.9x off an H200 at that size, so choose it for what the answer costs on this hardware rather than expecting it to beat a GPU.
Use it to rank a series; use predict --model boltz2 when you need the pose. Proteins and ligands
only, one ligand scored per input. The trunk runs bf16 by default: it is about 6x faster than fp32
and no less accurate from 276 tokens up, and fp32 runs out of DRAM around 1000 tokens. On inputs
under ~150 tokens fp32 is the more faithful arm, and --trunk fp32 switches back. See
docs/nesso1.md for the input schema, the four upstream limits, and what to watch
when comparing numbers against another implementation.
Input Format
ESMFold2 accepts proteins, DNA, RNA and ligands, and no constraints.
Protenix-v1 and Protenix-v2 accept proteins, DNA, RNA,
ligands, and covalent bond constraints. OpenFold3 accepts proteins, DNA and RNA
plus per-chain templates, and rejects ligands and constraints with a named error.
OpenDDE accepts proteins and ligands
and honors covalent bond constraints between them. Boltz-2 additionally supports affinity, pocket/contact constraints,
potentials, and user-supplied templates.
Create a YAML file describing your complex:
version: 1
sequences:
- protein:
id: A
sequence: MVTPEGNVSLVDESLLVGVTDEDRAVRSAHQFYERLIGLWAPAVMEAAHELGVFAALAEAPADSGELARRLDCDARAMRVLLDALYAYDVIDRIHDTNGFRYLLSAEARECLLPGTLFSLVGKFMHDINVAWPAWRNLAEVVRHGARDTSGAESPNGIAQEDYESLVGGINFWAPPIVTTLSRKLRASGRSGDATASVLDVGCGTGLYSQLLLREFPRWTATGLDVERIATLANAQALRLGVEERFATRAGDFWRGGWGTGYDLVLFANIFHLQTPASAVRLMRHAAACLAPDGLVAVVDQIVDADREPKTPQDRFALLFAASMTNTGGGDAYTFQEYEEWFTAAGLQRIETLDTPMHRILLARRATEPSAVPEGQASENLYFQ
- ligand:
id: B
smiles: 'N[C@@H](Cc1ccc(O)cc1)C(=O)O'
properties:
- affinity:
binder: B
Entity Types:
- Polymers (
protein,dna,rna): providesequence - Ligands (
ligand): providesmilesorccdcode
Multiple Identical Chains:
- protein:
id: [A, B] # Two identical chains
sequence: ...
Understanding Results
Output Structure
<model>_results_prot/ # e.g. protenix_results_prot, boltz2_results_prot
├── structures/
│ ├── prot.cif # Best-ranked predicted structure
│ └── prot_model_1.cif # Additional samples (if diffusion_samples > 1)
├── results.json # One entry per target with confidence/affinity metrics
├── power_profile.csv # (optional, --report-energy)
├── power_profile.png # (optional, --report-energy)
├── prot_pae.npz # (optional, --write_pae)
├── prot_pde.npz # (optional, --write_pde)
└── prot_embeddings.npz # (optional, --write_embeddings)
MSA results are cached in <out_dir>/msa/ (default ./msa/), keyed by sequence hash. The same protein sequence is never searched twice, even across different input files or runs. The MSA search uses all available CPU threads and keeps the database index memory-mapped for maximum speed.
Confidence Scores
Each target entry in results.json contains confidence metrics. The fields below are Boltz-2's; Protenix-v2 and OpenFold3 report the same confidence_score / ptm / iptm / plddt (and all_runs when --diffusion_samples > 1, ranked best-first), while an ESMFold2 entry instead carries plddt (mean, 0-1), ptm when available, and n_residues / n_chains. Every model reports its complex mean pLDDT under plddt.
{
"id": "prot",
"status": "ok",
"confidence_score": 0.84,
"ptm": 0.84,
"iptm": 0.82,
"complex_plddt": 0.84,
"plddt": 0.84,
"chains_ptm": {
"0": 0.85,
"1": 0.83
},
"pair_chains_iptm": {
"0": {"0": 0.85, "1": 0.72},
"1": {"0": 0.82, "1": 0.83}
}
}
confidence_score: Overall confidence (0-1, higher is better), calculated as 0.8 ×complex_plddt+ 0.2 ×iptm, or 0.8 ×complex_plddt+ 0.2 ×ptmfor a single-chain target, where there is no interface andiptmis 0. Models are ranked by this score. It is not a pLDDT and can sit either side of one: on CDK2 it is 0.008 abovecomplex_plddtat 298 aa and 0.050 below it at 512 aa. OpenFold3 uses its own upstream ranking score instead (0.8 ×iptm+ 0.2 ×ptm+ 0.5 × disorder − 100 × clash), so its values are not comparable to the other models'ptm: Predicted TM-score for complex (0-1)iptm: Interface TM-score (0-1)complex_plddt,plddt: Mean confidence (0-1), the same value under both names. It is the mean of the B-factor column of the structure file the same fold wrote, so averaging that column reproduces it. Boltz-2 writes one pLDDT per residue, so average over one atom per residue (CA); Protenix-v2, OpenFold3, OpenBind-0 and OpenDDE write one per atom, so average over all of themchains_ptm: Per-chain TM-scores (0-1)pair_chains_iptm: Per-chain-pair interface TM-scores (0-1)
Affinity Predictions
For affinity targets, the same results.json entry also contains:
{
"affinity_pred_value": 2.47,
"affinity_probability_binary": 0.41,
"affinity_pred_value1": 2.55,
"affinity_pred_value2": 2.19,
"affinity_probability_binary1": 0.50,
"affinity_probability_binary2": 0.42
}
affinity_probability_binary: Probability of binding (0-1). Use for hit discovery (higher = more likely to bind)affinity_pred_value: Predicted binding affinity as log10(IC50) in μM. Use for ligand optimization (lower = stronger binding). Only compare between known active moleculesaffinity_pred_value1,affinity_pred_value2: Individual model predictions for binding affinityaffinity_probability_binary1,affinity_probability_binary2: Individual model predictions for binding probabilityruntime_s: Wall-clock seconds for the whole target, structure and affinity together. Affinity targets also carrystructure_runtime_sandaffinity_runtime_s; the affinity leg is normally the larger of the two by several times, so read the split before pricing a screen
Advanced Usage
Input Format Details
Proteins with Custom MSA
- protein:
id: A
sequence: MVTPEGNVSLVDES...
msa: ./path/to/msa.a3m
Proteins with Modifications
- protein:
id: A
sequence: MVTPEGNVSLVDES...
modifications:
- position: 5
ccd: PTR # Modified residue code
Ligands
- ligand:
id: B
smiles: 'CC1=CC=CC=C1' # SMILES string
# OR
ccd: ATP # CCD code
Constraints
Pocket and contact constraints are Boltz-2 only (they need a trained constraint embedder). Covalent bond constraints work with Boltz-2, Protenix-v2, and OpenDDE. OpenFold3 does not support any constraints: block yet and rejects one with a named error rather than folding without it.
Pocket Constraints (binding site):
constraints:
- pocket:
binder: B # Ligand chain
contacts: [[A, 10], [A, 11], [A, 12]] # Binding site residues
max_distance: 6.0 # Angstroms (4-20A, default 6A)
force: false # Use potential to enforce (default: false)
Contact Constraints:
constraints:
- contact:
token1: [A, 10]
token2: [A, 50]
max_distance: 8.0
force: false
Bond Constraints (covalent link, e.g. a covalent inhibitor, glycosylation, or disulfide; works with Boltz-2, Protenix-v2, and OpenDDE):
constraints:
- bond:
atom1: [A, 10, SG] # [chain, residue, atom]
atom2: [B, 1, C12] # ligand atom by name; polymer atoms by residue
OpenDDE + covalent bonds: OpenDDE honors a
bondconstraint between a protein residue and a ligand atom (the covalent-inhibitor case) or between two protein residues (a disulfide or crosslink). Both ride the sametoken_bondsmachinery as Protenix-v2 and are honored in the output (device-verified against upstream OpenDDE within the reference's own seed noise floor); seeexamples/opendde_covalent_ligand.yamlandexamples/opendde_covalent_bond.yaml.
Templates
Use experimental structures as templates:
templates:
- cif: ./template.cif
chain_id: A
template_id: A
force: true # Enforce template alignment
threshold: 2.0 # Max deviation in Angstroms
openfold3, openbind, protenix-v2, opendde and opendde-abag take
templates per protein chain instead, as a precomputed alignment .npz (the
format the upstream benchmark cache ships). It is one file format across all
five. There is no template search; the referenced structures are fetched from
RCSB, and a missing one is a hard error rather than a silently dropped
template. See examples/7xi5_tmpl.yaml.
sequences:
- protein:
id: A
sequence: MSSATPDPAEILT...
templates: ./templates.npz
Command-Line Options
Model-specific options are labelled below.
Common Options:
| Option | Default | Description |
|---|---|---|
--model |
boltz2 |
boltz2, esmfold2, esmfold2-fast (single-sequence ESMFold2; protein / DNA / RNA / ligand complexes), protenix-v1 / protenix-v2 (AlphaFold3-family folder; protein / RNA / DNA / ligand complexes; protenix-v1 is upstream's v0.5.0 base checkpoint at 4 trunk recycles, protenix-v2 the wider one at 10), openfold3 (AlphaFold3-family folder; protein / RNA / DNA polymers, optional templates, OF3_CKPT weights), openbind (OpenBind-0; the OpenFold3 stack on upstream v0.5.0 weights, protein-ligand co-folding, TT_BIO_OPENBIND weights), opendde / opendde-abag (antibody-antigen co-folding on the Protenix-v2 stack plus a structural-token expander; opendde-abag selects the antibody-antigen checkpoint; protein-only for now), or rf3 (RoseTTAFold3, AlphaFold3-family folder; protein / RNA / DNA / ligand complexes; non-canonical residues, covalent modifications and cyclic chains need RF3's own JSON spec, not the YAML input) |
--out_dir |
./ |
Output directory |
--cache |
~/.boltz |
Weight cache directory. Whole-repo models (ESMFold2, ESMC, SaProt, OpenDDE) use the Hugging Face cache; TT_BIO_CACHE moves both, see docs/weights.md |
--accelerator |
tenstorrent |
(Boltz-2) tenstorrent, cpu, or gpu; other models run on Tenstorrent |
--recycling_steps |
model-specific | 3 for Boltz-2 and OpenFold3 (OpenFold3 runs recycles+1 = 4 trunk cycles, its upstream default); 4 for Protenix-v1 (its checkpoint's own N_cycle); 10 for Protenix-v2/OpenDDE/ESMFold2/RF3 (the ESMFold2 paper's benchmark setting) |
--sampling_steps |
model-specific | Requested diffusion sampling steps: 200 for Boltz-2/Protenix-v1/Protenix-v2/OpenFold3/OpenDDE; 100 for ESMFold2 (executes 68 after the sigma-schedule clip, the paper's protocol) |
--diffusion_samples |
1 |
Number of structure samples |
--partial_t |
0 |
rf3 only. Schedule index the diffusion rollout starts at, so it refines --partial_structure instead of folding from scratch. Higher stays closer to that structure |
--partial_structure |
— | rf3 only. The .cif/.pdb/.json structure --partial_t refines. It supplies the sequences too, so no MSA is attached |
--early_stop_plddt |
— | rf3 only. Abandon a target after the first trunk recycle if its mean pLDDT is below this. Writes no structure; the results entry carries early_stopped |
--max_parallel_samples |
5 |
Diffusion samples denoised in one batched forward. Higher is faster but costs device memory linearly; lower it if a large target runs out of memory |
--output_format |
cif |
cif or pdb. A PDB has one column for the chain id, so a longer name is rewritten A, B, C... and the originals go into a REMARK 999 block; cif keeps them as submitted. See docs/model-capabilities.md |
--seed |
0 |
Random seed for the diffusion sampler |
--trace |
False |
(Protenix-v1/Protenix-v2/OpenDDE) Replay a captured trace of the per-step diffusion device stream. Lossless, and removes the per-step host dispatch; reserves 1 GiB of device memory |
--diffusion_trace |
False |
(Boltz-2) The same for Boltz-2's diffusion DiT stream |
--write_pde |
False |
(Boltz-2) Write the PDE matrix to its own <name>_pde.npz. The Protenix family and OpenDDE put PDE next to PAE in one file under --write_pae instead |
--write_embeddings |
False |
(Boltz-2) Write the s/z embeddings per target |
--override |
False |
Re-run from scratch |
--use_msa_server |
auto | Use the online ColabFold API; auto-enabled for Boltz-2/Protenix-v1/Protenix-v2/OpenFold3/OpenBind-0/OpenDDE/RF3 when no local DB is found |
--single_sequence |
False |
(Boltz-2/Protenix-v1/Protenix-v2/OpenFold3/OpenDDE) Skip all MSA requests; lower accuracy |
--msa_endpoint |
— | Fetch unpaired MSAs from a tt-bio msa-server; OpenDDE pairing still uses --msa_server_url |
--write_pae |
False |
(Protenix-v1/Protenix-v2/OpenDDE) Write the token-token PAE/PDE matrices to <name>_pae.npz |
--use_potentials |
False |
(Boltz-2) Apply physical constraints |
--affinity_mw_correction |
False |
(Boltz-2) Apply MW correction to affinity |
--num_devices |
0 |
Number of TT devices (0=all available) |
--device_ids, --devices |
— | Comma-separated TT device IDs (e.g. 0,2); --devices is the shorter alias (matches tt-bio embed) |
--host_threads |
all cores | Total CPU threads this process may use, split across its cards. Set it when you run several single-card predicts side by side on one host: each one otherwise sizes its thread pools to every core and they fight for the CPU. Use cores ÷ concurrent predicts. At two threads per card or fewer the pools also stop spinning through device syncs (Tuning flags) |
--fast |
False |
Makes some operations use a lower-precision numeric format that runs faster; accuracy is typically very close |
--listen |
— | Accept worker connections from other machines; see Multi-Machine Prediction |
--report-energy |
False |
(Boltz-2) Enables optional energy profiling for one TT device (requires tt-mgmt add-on); writes power_profile.csv and power_profile.png |
--energy-metric |
both |
(Boltz-2) Choose power channel(s): tdp, input, or both |
--energy-sample-hz |
20.0 |
(Boltz-2) Sampling rate in Hz for both power_w and input_power_w channels |
Affinity-Specific Options (Boltz-2):
| Option | Default | Description |
|---|---|---|
--sampling_steps_affinity |
200 |
Sampling steps for affinity |
--diffusion_samples_affinity |
5 |
Number of affinity samples |
MSA Options (Boltz-2, Protenix-v1, Protenix-v2, OpenFold3, OpenBind-0, OpenDDE and RF3 use an MSA by default; ESMFold2 only when requested):
| Option | Default | Description |
|---|---|---|
--msa_db_path |
auto-detect | Path to local ColabFold database (~/.boltz/msa_db if present) |
--msa_dir |
<out_dir>/msa |
MSA cache directory. Point it at a shared persistent path to reuse {seq_hash}.a3m across runs |
--msa_cache_only |
False |
Treat --msa_dir as the only MSA source: never search, and fail rather than quietly fold a chain single-sequence |
--use_envdb |
False |
Also search environmental database |
--use_msa_server |
auto | Use ColabFold API for MSA (auto-enabled when no local DB is found) |
--single_sequence |
False |
Fold without an MSA (Boltz-2/Protenix-v1/Protenix-v2/OpenFold3/OpenDDE) |
--msa_server_url |
https://api.colabfold.com |
MSA server URL |
--msa_pairing_strategy |
greedy |
greedy or complete |
--max_msa_seqs |
8192 |
Maximum MSA depth. The default applies to Boltz-2 and ESMFold-2 only; Protenix, OpenDDE, RF3, OpenFold3 and OpenBind fold the whole alignment unless you set it. Each fold reports the depth it used as msa_depth |
--subsample_msa |
False |
Subsample MSA |
--num_subsampled_msa |
1024 |
Number of subsampled sequences |
MSA Database Setup Options:
| Option | Default | Description |
|---|---|---|
--db |
uniref30 |
uniref30 (~500GB), envdb (~800GB), or all |
--path |
~/.boltz/msa_db |
Where to store the databases |
--install-tools |
True |
Auto-install missing mmseqs/colabfold_search |
Tuning Flags
The engine ships its device optimizations on. Each one is an environment variable you can set to
0 to fall back to the path it replaced, which is what you want if you are bisecting a result.
| Flag | Default | What it does |
|---|---|---|
BOLTZ2_TOKEN_DIT_SDPA |
on | Boltz-2 only: runs the token-level DiT attention as one fused SDPA instead of materialising a 16x512x512 score matrix and reading it back. With the atom-axis flag below it folds 512 residues 1.105x faster on Blackhole (22.195 s to 20.079 s) and the diffusion sampler 1.400x; alone it is worth 1.100 s. Not bit-exact — the kernel holds its exponentiated scores in bf16, so a 298-residue control moves 0.1775 Å CA and 0.3837 Å all-atom inside its 0.35 Å CA bar, and pLDDT goes up, 0.909487 to 0.913597. |
TT_BIO_ATOM_AXIS_BUCKET |
on | Sizes the atom axis on the real atom count instead of assuming every token is a tryptophan: 4480 atoms at 512 residues where the old bound gave 7168, which takes the atom transformer from 224 attention windows to 140, of which 95 never held an atom. Worth 0.997 s of a 512-residue Boltz-2 fold on its own. Byte-identical at 298 residues; at 512 it reassociates one matmul’s contraction. The bucket is a multiple of 32 for any composition, which is what lets TT_BIO_TOKEN_BUCKET=0 and an off-lattice token count be used together. |
TT_BIO_ATOM_SHIFT_GATHER |
on | Builds each atom's attention key window by slicing the atom sequence instead of selecting it with a matrix multiply. Same structure, bit for bit. |
TT_BIO_DEVICE_CONDITIONING |
on | Boltz-2 only: runs the diffusion conditioning's pair track on the card, where the trunk already left the tensor. Not bit-exact — device bf16 where the host path was fp32. Scored against 1HCL it is flat to slightly closer. |
TT_BIO_DEVICE_CONFIDENCE |
on | Boltz-2 only: assembles the confidence head's pair input on the card, where the trunk already left the tensor, instead of building it on the host and uploading it. Together with the flag below it folds 512 residues 1.0474x faster on Blackhole. Coordinates are bit-identical; only the confidence scores move (pLDDT by at most 0.362 of 100). |
TT_BIO_DEVICE_CONF_HEADS |
on | Boltz-2 only: runs the confidence head's pae/pde projections and their bin contractions on the card, so three numbers per token pair come down instead of a tile of bin logits: 67.1 MB becomes 2.1 MB at 512 residues on Wormhole, and 16.8 MB on Blackhole, where reading the tile whole and slicing on the host is 3x faster than the narrower row-major read. Coordinates and per-residue pLDDT are bit-identical; the confidence scores shift by a bf16 rounding, 0.0031 of pTM at 512 residues against a 0.0758 four-seed spread. Measured with the flag above. |
TT_BIO_DEVICE_ZINIT |
on | Boltz-2 only: builds the trunk's z_init pair tensor on the card instead of in torch, so the 134 MB upload at 512 tokens never happens. Folds 512 residues 1.01955x faster on Blackhole, ten of ten paired reps positive. Not bit-exact — device bf16 where the host path was fp32. Moves a 298 aa structure 0.264 Å all-atom inside its 0.35 Å bar, and native CA-lDDT against 1HCL is flat over eight seeds. |
TT_BIO_FUSE_BIAS_STACKS |
on | Boltz-2 only: builds the diffusion conditioning's per-layer bias stack in one pass instead of one call per layer. Not bit-exact — moves a 298 aa structure 0.218 Å all-atom, inside its 0.35 Å bar. |
TT_BIO_FUSE_MASK_ADD |
on | Runs the gated-residual write-back as one ttnn.addcmul instead of a multiply then an add. Same structure, bit for bit at fold level; it deletes 1504 dispatches per 298-residue OpenFold3 fold. |
TT_BIO_FUSE_NORM_RESIDUAL |
on | Passes an add whose only consumer is a layer norm to the norm as its residual input instead of running the add first. Same structure, bit for bit; 1.880x on a [1,512,512,128] norm. Its one call site is Protenix-v2’s pde confidence branch, which the 298-residue protocol never reaches, so the fold-level saving is unpriced rather than measured. |
TT_BIO_FUSE_SCALE_ADD |
on | Runs attention’s scale-then-bias as one ttnn.addalpha instead of a multiply then an add, for fp32 operands only. At fp32 both arms round identically, measured bit-identical at every call shape, and 1500 of the 1503 calls a 298-residue fold makes are fp32. The three bf16 calls keep the chain, because fusing those alone moved an OpenFold3 structure 1.475 Å. Predicted saving 67.0 ms of a 6.92 s Protenix-v2 fold and 73.9 ms of a 9.93 s OpenFold3 fold, summed from measured per-call times; that is below what a fold A/B can resolve, so no wall-clock ratio is claimed. |
TT_BIO_GATE_GRANULARITY |
2 | Tiles per DST acquire in the reblock-permute gate kernel. Same structure, bit for bit at every value; 2 is the setting that wins on Blackhole without losing much on Wormhole. |
TT_BIO_HOST_LEVERS |
on | Master switch for the host-side Boltz-2 levers (TT_BIO_FUSE_BIAS_STACKS and TT_BIO_HOST_BLOCK_PAIRWISE). Set it to 0 to take the host path for all of them at once. |
TT_BIO_MSA_LADDER |
on | Boltz-2 and BoltzGen: pads the MSA depth axis to the smallest of 64, 128, 256, 512, 1024 that holds the alignment instead of always to 1024, so a shallow search stops carrying rows that are not there. Not bit-exact — a shorter rung reassociates the same terms. Scored against 1HCL it is as accurate or closer. |
TT_BIO_PAIR_FFN_L1_FC1 |
on | ESMFold2 only: keeps both halves of the pair transition's first matmul in L1, so the SiLU multiply that consumes them reads on chip instead of out of DRAM. Folds 512 residues 1.0879x faster on Blackhole. Same structure, bit for bit; it pays up to 512 residues and is inert above, where the block leaves it no room. |
TT_BIO_PWA_BATCH_HEAD_WEIGHTS |
on | Computes every attention head's MSA row weights from one projection of the pair tensor instead of one projection per head. Same structure, bit for bit. |
TT_BIO_REBLOCK_PERMUTE_GATED |
on | Folds a triangle multiplication’s chunk and its two sigmoid gates into the channel move that feeds them, instead of running the move and then three eltwise passes over the result. Same structure, bit for bit. Every triangle multiplication still opts in, so a model whose shapes the fused reader cannot address keeps the separate ops. |
TT_BIO_RESIDUAL_L1 |
on | Has the two Pairformer sub-layers whose residual update used to go to DRAM and come straight back write it to L1 instead. Same structure, bit for bit; the update stays in DRAM above 512 residues, where it no longer fits. |
TT_BIO_SDPA_ADD_GRANULARITY |
auto | Batches the fused SDPA kernel's running-sum/max and mask adds instead of doing them one tile at a time. Same structure, bit for bit at every granularity. |
TT_BIO_SDPA_FUSED_LARGE_S |
on | Runs triangle attention through the fused mask kernel above 1024 tokens, where the chunk ladder otherwise hands the call back to the stock attention. Worth 4.23x on the attention op at 1536 tokens and 1.1856x on a 1536-residue fold at the shipped 200 sampling steps (27.3 s saved). Set it to 0 for the stock ladder everywhere. Not bit-exact above 1024 tokens, where nothing reached this kernel before: it moves a 1536-residue structure 1.007 Å where a different seed moves it 36.6 Å, and pLDDT comes out 0.35 of 100 higher. At and below 1024 tokens the path is untouched, byte for byte. |
TT_BIO_SDPA_GRID_Q_CHUNK |
on | Sizes each attention's query chunk to the card's compute grid instead of a fixed cap, so a small attention fills the cores it has. Same structure, bit for bit. |
TT_BIO_TOKEN_BUCKET |
on | The one global off switch for token bucketing. Every model's bucket answers to it, and the legacy per-model flags are ANDed with it, so 0 turns all of them off at once and folds the exact token count instead of a padded one. Off-lattice counts are slower and are what docs/size-generality.md asks for when checking a size claim is not an artifact of the lattice. |
TT_BIO_TRANSITION_L1_ROWS |
on | Blackhole only: sizes each transition's row block from the card's own L1 budget instead of the 16 rows tuned for Wormhole, so a 512-residue pair tensor takes 11 row blocks where it used to take 32. Applies to Boltz-2, BoltzGen and OpenFold3, whose pair track is 128 channels wide; Protenix-v2 and OpenDDE have wider pair tracks and keep today's height. Bit-identical output on the reference fixture at 298, 512, 768 and 1024 residues; on other shapes the block boundary moves the structure a little, 0.165 Å on the no-MSA prot leg whose arms already sit 7 Å from the fp32 reference. Folds 512 residues 1.023-1.035x faster on Blackhole, 768 residues 1.030x and 1024 residues 1.013x; it does nothing at and above 1536 residues, where the fixed height already fills the budget. |
TT_BIO_TRIATT_FUSED_QKVG |
on | Projects a triangle attention's query, key, value and gate in one pass over the pair tensor instead of two. Same structure, bit for bit. |
TT_BIO_TRIATT_FUSED_QKVGB |
on | Adds the pair-bias projection to that same pass, so the pair tensor is read once instead of three times. Same structure, bit for bit; chains of 32 residues or fewer keep the separate projection. |
TT_BIO_TRIMUL_FUSED_GOUT |
on | Computes a triangle multiplication's output gate as a second output of its input projection. Same structure, bit for bit. |
TT_BIO_TRIMUL_GP_BANK_SPLIT |
on | Interleaves the gate and value columns of a triangle multiplication's fused input projection so the channel move reads each pair from two DRAM banks instead of one. Same structure, bit for bit; the gain is Blackhole's, free elsewhere. |
TT_BIO_TRIMUL_MASK_AFTER_MOVE |
on | Applies a triangle multiplication’s pair mask after the channel move rather than before it, which is what lets the fused move above reach a masked trimul at all. Same structure, bit for bit. |
TT_BIO_TRIMUL_MASK_L1 |
on | Keeps a triangle multiplication's pair mask in L1, where the channel-blocked multiply re-reads it without touching DRAM. Same structure, bit for bit. |
TT_BIO_TRIMUL_MM_TRANSPOSE |
on | Lets the matmul take a triangle multiplication's operand transpose instead of running a separate transpose first. Same structure, bit for bit; --fast keeps the separate op, because transposing inside the matmul re-quantises a block-float tile. |
TT_BIO_TRIMUL_TAIL_F1 |
on | Runs a triangle multiplication’s output projection, gate projection and gate multiply as one kernel. Same structure, bit for bit: torch.equal at 14 shapes from 32 to 1024 residues. ESMFold2 and Protenix-v2 fire it and fold 512 residues in 31.994 s against 32.329 s; Boltz-2, OpenDDE and OpenFold3 never reach it, because their triangle multiplications are not 8 tiles deep. |
TT_BIO_TRIMUL_TAIL_F1_L1_OUT |
on | Lands that fused tail’s product in L1 rather than DRAM, so the gate multiply that consumes it reads on chip. Same structure, bit for bit. With the product in DRAM the fused tail adds a round trip at a 128-channel pair track instead of deleting one. |
More on how these were measured, and what "same structure" means for each of them, in
docs/tuning-flags.md.
MSA Server Authentication
For --use_msa_server:
Basic Authentication:
export BOLTZ_MSA_USERNAME=myuser
export BOLTZ_MSA_PASSWORD=mypassword
tt-bio predict ... --model boltz2 --use_msa_server
API Key Authentication:
export MSA_API_KEY_VALUE=your-api-key
tt-bio predict ... --model boltz2 --use_msa_server
Optional: Multi-Machine Prediction
Combine the cards across any mix of Tenstorrent machines (a workstation, one or more QuietBoxes, one or more Galaxy servers) into a single run.
On the machine driving the run:
tt-bio predict ./proteins --model boltz2 --listen 8765 --use_msa_server --fast
On every additional machine, replace HOST with the driving machine's
hostname or IP:
tt-bio worker --connect http://HOST:8765
Optional: Energy Measurement (Boltz-2)
Use --report-energy to profile energy during prediction:
tt-bio predict examples/686.yaml --model boltz2 --override --device_ids 0 --report-energy --energy-metric both --energy-sample-hz 5
Behavior:
- Select metric channel(s) with
--energy-metric(tdp,input,both) - Uses one sampling rate (
--energy-sample-hz, default 20 Hz) - Supports only Tenstorrent runs with one selected device
- Records two power channels when available:
power_w:tt-mgmtUMD telemetry power (TDP channel)input_power_w:tt-mgmtUMD telemetry input power
- Requires optional
tt-mgmtinstallation:git clone --recursive https://github.com/aperezvicente-TT/tt-mgmt.gitpip install -e ./tt-mgmt
- Prints energy summary metrics for selected channels
- Always writes:
power_profile.csvpower_profile.png
Design
Design new binders and protein structures from a target or motif specification: one command, two models:
tt-bio design examples/binder.yaml --model boltzgen --num_designs 10
tt-bio design specs.json --model rfd3 --from_pdb --out_dir designs/
| Model | Designs | Input |
|---|---|---|
boltzgen (default) |
protein / peptide / nanobody / antibody binders against a target | design YAML, same entity grammar as predict |
rfd3 |
all-atom structures: binders, motif scaffolding, nucleic-acid binders | JSON spec with contig strings |
pxdesign |
binder backbones against a target structure | target YAML: structure file, chains to condition on, binder length |
BoltzGen designs binders against a target structure. The pipeline runs design → inverse folding → folding → analysis → filtering and writes the top-ranked binders to <out_dir>/final_ranked_designs/. Input grammar, protocols, pipeline subsets, and options: docs/boltzgen-design.md. Designability (scRMSD) QA: docs/boltzgen-designability.md.
RFdiffusion3 (RFD3) is an all-atom generative model that designs new protein structures and sequences from a specification, rather than folding an existing one. Design modes, the contig-string input grammar, and which conditioning fields a spec can and cannot ask for: docs/rfd3-design.md.
PXDesign generates binder backbones against a target structure, conditioned on a distogram of the target rather than its coordinates. Input is a target YAML naming a structure file, the chains to condition on (with optional per-chain crop and hotspots) and a binder_length; each design is written as a CIF in the target structure's own frame, so it opens alongside your input file. A designs.json lands beside them with each design's numbers: fit RMSD against the target, binder residue and atom counts, and how many target tokens it was conditioned on. The binder is written as GLY because PXDesign generates a backbone with no sequence. Hotspot residues are label_seq numbers, not the author numbering a viewer shows, and a number that names no residue is refused rather than dropped. --num_designs is also the batch axis for this model: every requested design comes from one batched diffusion trajectory, and 8 at a time runs about 1.25x faster per design than one at a time. A given --seed and --num_designs always reproduce the same designs, but --num_designs 1 and --num_designs 2 do not share their design 0: asking for more designs currently changes which ones you get, so pin both values when you want a run back. Selecting designs, which upstream does with a Protenix and an AF2-IG filter, is not on the CLI yet.
Each model downloads its weights automatically on first use. BoltzGen and RFdiffusion3 fan out across every available card (--devices 0,2 restricts); PXDesign runs on one card locally, or one design per card across a fleet with --controller http://host:8765. tt-bio gen still works as a deprecated alias for tt-bio design --model boltzgen.
Cite
If you use this code or the models in your research, please cite the following papers:
@article{passaro2025boltz2,
author = {Passaro, Saro and Corso, Gabriele and Wohlwend, Jeremy and Reveiz, Mateo and Thaler, Stephan and Somnath, Vignesh Ram and Getz, Noah and Portnoi, Tally and Roy, Julien and Stark, Hannes and Kwabi-Addo, David and Beaini, Dominique and Jaakkola, Tommi and Barzilay, Regina},
title = {Boltz-2: Towards Accurate and Efficient Binding Affinity Prediction},
year = {2025},
doi = {10.1101/2025.06.14.659707},
journal = {bioRxiv}
}
@article{stark2025boltzgen,
author = {Stark, Hannes and Faltings, Felix and Choi, MinGyu and Xie, Yuxin and Hur, Eunsu and O'Donnell, Timothy John and Bushuiev, Anton and U{\c c}ar, Talip and Passaro, Saro and Mao, Weian and Reveiz, Mateo and Bushuiev, Roman and Pluskal, Tom{\'a}{\v s} and Sivic, Josef and Kreis, Karsten and Vahdat, Arash and Ray, Shamayeeta and Goldstein, Jonathan T. and Savinov, Andrew and Hambalek, Jacob A. and Gupta, Anshika and Taquiri-Diaz, Diego A. and Zhang, Yaotian and Hatstat, A. Katherine and Arada, Angelika and Kim, Nam Hyeong and Tackie-Yarboi, Ethel and Boselli, Dylan and Schnaider, Lee and Liu, Chang C. and Li, Gene-Wei and Hnisz, Denes and Sabatini, David M. and DeGrado, William F. and Wohlwend, Jeremy and Corso, Gabriele and Barzilay, Regina and Jaakkola, Tommi},
title = {BoltzGen: Toward Universal Binder Design},
year = {2025},
doi = {10.1101/2025.11.20.689494},
journal = {bioRxiv}
}
@article{wohlwend2024boltz1,
author = {Wohlwend, Jeremy and Corso, Gabriele and Passaro, Saro and Getz, Noah and Reveiz, Mateo and Leidal, Ken and Swiderski, Wojtek and Atkinson, Liam and Portnoi, Tally and Chinn, Itamar and Silterra, Jacob and Jaakkola, Tommi and Barzilay, Regina},
title = {Boltz-1: Democratizing Biomolecular Interaction Modeling},
year = {2024},
doi = {10.1101/2024.11.19.624167},
journal = {bioRxiv}
}
@misc{candido2026language,
author = {Candido, Salvatore and Hayes, Thomas and Derry, Alexander and Rao, Roshan and Lin, Zeming and Verkuil, Robert and others},
title = {Language Modeling Materializes a World Model of Protein Biology},
year = {2026},
url = {https://biohub.ai/papers/esm_protein.pdf},
note = {Preprint; ESMC / ESMFold2}
}
@misc{protenix2025,
author = {{ByteDance AML AI4Science Team}},
title = {Protenix: An AlphaFold3 Reproduction for Biomolecular Structure Prediction},
year = {2025},
url = {https://github.com/bytedance/Protenix}
}
@misc{openfold3,
author = {{OpenFold Consortium}},
title = {OpenFold3: An Open-Source Reproduction of AlphaFold3},
year = {2026},
url = {https://github.com/aqlaboratory/openfold-3}
}
@article{butcher2025rfdiffusion3,
author = {Butcher, Jasper and Krishna, Rohith and Mitra, Raktim and Brent, Rafael Isaac and Li, Yanjing and Corley, Nathaniel and Kim, Paul T and Funk, Jonathan and Mathis, Simon Valentin and Salike, Saman and Muraishi, Aiko and Eisenach, Helen and Thompson, Tuscan Rock and Chen, Jie and Politanska, Yuliya and Sehgal, Enisha and Coventry, Brian and Zhang, Odin and Qiang, Bo and Didi, Kieran and Kazman, Maxwell and DiMaio, Frank and Baker, David},
title = {De novo Design of All-atom Biomolecular Interactions with RFdiffusion3},
year = {2025},
doi = {10.1101/2025.09.18.676967},
journal = {bioRxiv}
}
In addition if you use the automatic MSA generation, please cite:
@article{mirdita2022colabfold,
title={ColabFold: making protein folding accessible to all},
author={Mirdita, Milot and Sch{\"u}tze, Konstantin and Moriwaki, Yoshitaka and Heo, Lim and Ovchinnikov, Sergey and Steinegger, Martin},
journal={Nature methods},
year={2022}
}
License
tt-bio is released under the MIT License (see LICENSE) and is built on the MIT-licensed Boltz-2 / Boltz-1 code. It bundles third-party code, each under its upstream license: the ESMFold2 host-side reference under tt_bio/_vendor/ (the esm pipeline, MIT, © Chan Zuckerberg Biohub; and the HuggingFace ESMFold2 model definition, Apache-2.0), the OpenFold3 host-side data pipeline under tt_bio/_vendor/openfold3/ (Apache-2.0, OpenFold Consortium), the BoltzGen binder-design source under tt_bio/boltzgen/ (MIT, © Hannes Stärk), and RF3's host featurizer under tt_bio/_vendor/rf3/, tt_bio/_vendor/foundry/ and tt_bio/_vendor/atomworks/ (BSD-3-Clause, University of Washington / Institute for Protein Design). Protenix-v2, OpenFold3's on-device model, RFdiffusion3, RF3's on-device model, and PXDesign's are independent ttnn reimplementations (no upstream compute code is vendored); Protenix-v2's weights download from ByteDance's Hugging Face mirror under Apache-2.0, RFdiffusion3's and RF3's checkpoints download directly from the Institute for Protein Design (BSD-3-Clause), PXDesign's generator checkpoint downloads from ByteDance's release host under Apache-2.0 and its AF2-IG selection stage reads DeepMind's AlphaFold2 monomer pTM parameters (CC BY 4.0, from storage.googleapis.com/alphafold/), and OpenFold3's of3-p2-155k.pt and OpenBind-0's of3-ob-2025-06-30-174k.pt are the consortium's ungated public parameter releases, which you fetch yourself (the project is Apache-2.0, stated by upstream as free for academic and commercial use; the consortium publishes no separate parameter license). See NOTICE for sources, versions, and modifications.
Metadata
Release files for tt-bio 0.9.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tt_bio-0.9.0.tar.gz | 2.9 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tt_bio-0.9.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 5.5 MB
Release files / tt_bio-0.9.0.tar.gz
| Download URL | tt_bio-0.9.0.tar.gz |
|---|---|
| Size | 2.9 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
643167b88589691de67256d231339a6b9775ce4691dab82498c4a9fb4c025ebc
|
|
BLAKE2b-256 checksum How to use checksums |
6b5064431ff8f03b6cb1965fa57d00515fc0810e03a7d3e25015fd3808bb348a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.
Transparency logRelease files / tt_bio-0.9.0-py3-none-any.whl
| Download URL | tt_bio-0.9.0-py3-none-any.whl |
|---|---|
| Size | 2.6 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2fbe33aebaa651d5dd98d67f038e8d4fa9d8d1d6e19bfeb14a862462ed7b0e53
|
|
BLAKE2b-256 checksum How to use checksums |
e6967b462704a0e332311c1e2dbde612fafb864782d0c1d60ace4d334d4a0f09
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.
Transparency log