Multi-stage protein design pipelines with DuckDB caching, resumability, and dependency resolution. See Python SDK overview for SDK onboarding.
Overview
The pipeline framework provides:
Multi-stage orchestration with automatic dependency resolution
DuckDB caching for predictions, embeddings, and structures
Resumability — skip completed stages on re-run
Streaming for large datasets
Visualization — funnel plots, PCA/UMAP, distributions
Quick start
from biolm.pipeline import GenerativePipeline, SaturationMutagenesisConfig
config = SaturationMutagenesisConfig(
parent_sequence="MKTAYIAKQRQ",
scoring_model="esm2-650m",
scoring_action="predict",
score_field="logits",
top_n=10,
)
pipeline = GenerativePipeline(configs=[config])
results = pipeline.run()
Config hierarchy
All pipeline configs inherit from ScoringProtocolConfig.
Use isinstance to dispatch on config type:
from biolm.pipeline.generative import (
ScoringProtocolConfig,
GenerativeProtocolConfig,
SaturationMutagenesisConfig,
IterativeMaskingDMSConfig,
DirectGenerationConfig,
)
if isinstance(config, SaturationMutagenesisConfig):
pipeline = GenerativePipeline(configs=[config])
elif isinstance(config, DirectGenerationConfig):
pipeline = GenerativePipeline(configs=[config])
ScoringProtocolConfig
├── SaturationMutagenesisConfig
├── IterativeMaskingDMSConfig
└── DirectGenerationConfig (extends GenerativeProtocolConfig)
Model quick-reference
Config type |
Model |
Action |
Notes |
|---|---|---|---|
SaturationMutagenesisConfig |
esm2-650m |
predict |
Single-mutant library + scoring |
IterativeMaskingDMSConfig |
esm2-650m |
predict |
Greedy MLM argmax DMS |
DirectGenerationConfig |
proteinmpnn / dsm / antifold |
generate |
Structure-conditioned generation |
Config classes
Field details are documented on each class below.
- class biolm.pipeline.generative.ScoringProtocolConfig
Bases:
objectMarker base class for stages that score sequences and return a ranked subset.
Subclasses call a BioLM prediction model to assign a numeric score to each variant sequence enumerated by the config (e.g. all single-point mutants), then sort and return the top-N results. They do not produce wholly new sequences — the output is a scored, ranked subset of the candidate library built internally by the config (no separate generation step is needed).
The
scoring_actionfield on concrete subclasses selects the client method:'predict'callsBioLMApiClient.predict()and'score'callsBioLMApiClient.score(). Both are allowlisted ('predict','score') to prevent arbitrary method dispatch.Use
isinstance(config, ScoringProtocolConfig)()to branch on config type in pipeline dispatch functions.Example:
defaultfrom biolm.pipeline.generative import ( ScoringProtocolConfig, SaturationMutagenesisConfig, ) def dispatch(config): if isinstance(config, ScoringProtocolConfig): return run_scoring_stage(config) # returns ranked variant library return run_generative_stage(config) # returns novel sequences config = SaturationMutagenesisConfig( parent_sequence="MKTAYIAKQRQ", scoring_model="thermompnn-d", score_field="ddg", ) assert isinstance(config, ScoringProtocolConfig) # True
- class biolm.pipeline.generative.GenerativeProtocolConfig
Bases:
objectMarker base class for stages that produce new amino-acid sequences.
Subclasses drive generative or masked-language models to emit novel sequences — either via autoregressive sampling (ProteinMPNN, DSM, AntiFold) or by greedy-argmax masking over an MLM (ESM2, ESMC). Unlike
ScoringProtocolConfigsubclasses, these stages expand the candidate pool rather than filtering it; they are the source stage in a generative design pipeline.Use
isinstance(config, GenerativeProtocolConfig)()to branch on config type in pipeline dispatch functions.Example:
defaultfrom biolm.pipeline.generative import ( GenerativeProtocolConfig, DirectGenerationConfig, IterativeMaskingDMSConfig, ) def dispatch(config): if isinstance(config, GenerativeProtocolConfig): return run_generative_stage(config) # emits new sequences return run_scoring_stage(config) # returns ranked variants cfg_direct = DirectGenerationConfig( "dsm-150m-base", sequence="MKTAYIAKQRQ", num_sequences=50 ) cfg_dms = IterativeMaskingDMSConfig( parent_sequence="MKTAYIAKQRQ", model_name="esm2-650m" ) assert isinstance(cfg_direct, GenerativeProtocolConfig) # True assert isinstance(cfg_dms, GenerativeProtocolConfig) # True
- class biolm.pipeline.generative.SaturationMutagenesisConfig(parent_sequence: str, scoring_model: str, positions: list[int] | None = None, alphabet: str = 'ACDEFGHIKLMNPQRSTVWY', scoring_action: str = 'predict', scoring_params: dict[str, typing.Any] = <factory>, score_field: str = 'ddg', top_n: int | None = 50, ascending: bool = True, exclude_synonymous: bool = True, batch_size: int = 8, label: str | None = None, pdb_str: str | None = None, chain: str = 'A')
Bases:
ScoringProtocolConfigSource config that generates a single-mutant library and filters by a prediction model.
Enumerates every single amino-acid substitution at the specified positions, scores each variant with scoring_model using scoring_action, then returns the top-top_n variants ranked by score_field.
Typical use: ThermoMPNN-D or ESM2StabP-guided design — predict ΔΔG for all single-point mutants, keep the most stabilising ones.
- Args:
parent_sequence: Wild-type sequence to mutate. scoring_model: BioLM model slug used to score variants (e.g.
'thermompnn-d'). positions: 0-indexed positions to enumerate. IfNone, all positionsin the sequence are enumerated.
alphabet: Amino acids to substitute. Defaults to the 20 canonical AAs. scoring_action: API action for the scoring model (default
'predict'). scoring_params: Extra params forwarded to the scoring model API. score_field: Key inside each model response that holds the numeric score(default
'ddg'). Supports nested access with'.'separator, e.g.'result.ddg'.- top_n: Number of top-scoring variants to retain (default 50).
None keeps all variants that receive a valid score.
- ascending: If
True, lower scores are better (e.g. negative ΔΔG means stabilising). Defaults to
True.- exclude_synonymous: If
True(default), skip substitutions that are identical to the wild-type residue.
batch_size: Sequences per API request when scoring (default 8). label: Optional label stored as
source_labelin results. pdb_str: Raw PDB file contents as a string (not a file path). Whenprovided, each scoring item is built as
{"pdb": pdb_str, "mutations": ["instead of"], "chain": chain} {"sequence": mutant_sequence}. Required by structure-aware models such as ThermoMPNN-D. PassNone(default) for sequence-only models like ESM2StabP.- chain: Chain identifier forwarded in structure-aware scoring items
(default
'A').
- top_n: Number of top-scoring variants to retain (default 50).
Example:
defaultfrom biolm.pipeline.generative import SaturationMutagenesisConfig, GenerativePipeline # Score all single-mutant variants at three positions with ThermoMPNN-D config = SaturationMutagenesisConfig( parent_sequence="MKTAYIAKQRQ", scoring_model="thermompnn-d", positions=[3, 7, 10], # 0-indexed; None → all positions score_field="ddg", # key in API response holding ΔΔG top_n=25, # keep top-25 most stabilising variants ascending=True, # lower ΔΔG = more stabilising pdb_str=open("protein.pdb").read(), # required by structure-aware models ) pipeline = GenerativePipeline(configs=[config]) pipeline.add_prediction("esmfold", extractions="mean_plddt", columns="plddt") results = pipeline.run()- alphabet: str = 'ACDEFGHIKLMNPQRSTVWY'
- ascending: bool = True
- batch_size: int = 8
- chain: str = 'A'
- exclude_synonymous: bool = True
- label: str | None = None
- parent_sequence: str
- pdb_str: str | None = None
- positions: list[int] | None = None
- score_field: str = 'ddg'
- scoring_action: str = 'predict'
- scoring_model: str
- scoring_params: dict[str, Any]
- to_spec() → dict
- top_n: int | None = 50
- class biolm.pipeline.generative.IterativeMaskingDMSConfig(parent_sequence: str, model_name: str, positions: list[int] | None = None, rounds: int = 2, mask_token: str = '<mask>', alphabet: str = 'ACDEFGHIKLMNPQRSTVWY', exclude_synonymous: bool = True, batch_size: int = 32, label: str | None = None, action: str = 'predict')
Bases:
GenerativeProtocolConfigSource config that builds multi-point variants via sequential greedy masking.
Implements an iterative argmax masking procedure using a masked language model:
For each target position, mask it in the parent sequence and query the model for the highest-probability residue (greedy argmax — not sampled).
If
rounds > 1, apply the round-1 preferred substitution at each position and repeat for round 2: mask each other target position in the round-1 sequence and collect the argmax residue.Yield all resulting sequences as pipeline outputs.
This matches the ESM2 two-round DMS design pattern in the EGF generation notebook.
- Args:
parent_sequence: Starting sequence. model_name: MLM model slug (e.g.
'esm2-650m','esmc-300m'). positions: 0-indexed positions to probe. Defaults to all positions. rounds: Number of sequential masking rounds (default 2). Round N usesthe variant produced by round N-1 as its starting sequence.
mask_token: Token inserted at masked positions (default
'). alphabet: Vocabulary used to identify valid AA positions in logits.' Defaults to the 20 canonical amino acids.
- exclude_synonymous: Skip round-1 variants where the argmax matches WT
(default
True).
batch_size: Sequences per API request (default 32). label: Optional label stored as
source_labelin results. action: API action for the model (default'predict'; the model mustreturn logits). Only
'predict'is allowed because the greedy-argmax procedure requires per-token logit arrays.
Example:
defaultfrom biolm.pipeline.generative import IterativeMaskingDMSConfig, GenerativePipeline # Two-round greedy DMS at three positions using ESM2-650M config = IterativeMaskingDMSConfig( parent_sequence="MKTAYIAKQRQ", model_name="esm2-650m", positions=[2, 5, 8], # 0-indexed; None → all positions rounds=2, # round 1: per-position; round 2: 2-point combos exclude_synonymous=True, ) pipeline = GenerativePipeline(configs=[config]) results = pipeline.run() # results DataFrame has columns: # sequence, dms_round, dms_pos1, dms_aa1, dms_pos2, dms_aa2- action: str = 'predict'
- alphabet: str = 'ACDEFGHIKLMNPQRSTVWY'
- batch_size: int = 32
- exclude_synonymous: bool = True
- label: str | None = None
- mask_token: str = '<mask>'
- model_name: str
- parent_sequence: str
- positions: list[int] | None = None
- rounds: int = 2
- to_spec() → dict
- class biolm.pipeline.generative.DirectGenerationConfig(model_name: str, structure_path: str | None = None, structure_column: str | None = None, sequence: str | None = None, item_field: str = 'pdb', params: dict[str, typing.Any] = <factory>, num_sequences: int = 100, temperature: float = 1.0, structure_from_stage: str | None = None, structure_from_model: str | None = None, n_runs: int = 1, label: str | None = None)
Bases:
GenerativeProtocolConfigConfiguration for structure- or sequence-conditioned generation.
Use with models such as ProteinMPNN, AntiFold, HyperMPNN, LigandMPNN, DSM.
The caller is responsible for providing the correct
item_fieldandparamsfor the target model — these vary per model and are documented in the BioLM API schema (/schema/). Common values:/generate/ - Args:
- model_name: BioLM model slug (e.g.
'protein-mpnn','antifold', 'dsm-150m-base').
structure_path: Path to a PDB or CIF file. structure_column: DataFrame column holding PDB strings (for chained
pipelines where structure was predicted upstream).
sequence: Parent sequence string for sequence-conditioned models (DSM). item_field: The item dict key expected by the model API —
'pdb'forstructure-conditioned models,
'sequence'for DSM. Defaults to'pdb'.- params: Model-specific params dict (required for non-trivial calls).
Keys must exactly match the model’s API param names. When empty the stage sends
{'num_sequences': num_sequences, 'temperature': temperature}as a simple fallback — useful only for models that accept these exact param names.
num_sequences: Fallback when
paramsis empty (default 100). temperature: Fallback whenparamsis empty (default 1.0).- model_name: BioLM model slug (e.g.
Example:
defaultfrom biolm.pipeline.generative import DirectGenerationConfig, GenerativePipeline # Structure-conditioned design with ProteinMPNN cfg_mpnn = DirectGenerationConfig( model_name="protein-mpnn", structure_path="/path/to/protein.pdb", item_field="pdb", params={"num_sequences": 50, "temperature": 0.1}, ) # Sequence-conditioned design with DSM cfg_dsm = DirectGenerationConfig( model_name="dsm-150m-base", sequence="MKTAYIAKQRQ", item_field="sequence", params={ "num_sequences": 100, "temperature": 1.0, "remasking": "low_confidence", "step_divisor": 8, }, ) pipeline = GenerativePipeline(configs=[cfg_mpnn]) results = pipeline.run()- item_field: str = 'pdb'
- label: str | None = None
- model_name: str
- n_runs: int = 1
- num_sequences: int = 100
- params: dict[str, Any]
- sequence: str | None = None
- structure_column: str | None = None
- structure_from_model: str | None = None
- structure_from_stage: str | None = None
- structure_path: str | None = None
- temperature: float = 1.0
- to_spec() → dict
Return a serializable dict for pipeline definition persistence.
Pipeline examples
Saturation mutagenesis funnel:
from biolm.pipeline import GenerativePipeline, SaturationMutagenesisConfig
config = SaturationMutagenesisConfig(
parent_sequence="MKTAYIAKQRQ",
scoring_model="esm2-650m",
scoring_action="predict",
score_field="logits",
top_n=10,
)
pipeline = GenerativePipeline(configs=[config])
results = pipeline.run()
Direct generation (ProteinMPNN):
from biolm.pipeline import GenerativePipeline, DirectGenerationConfig
config = DirectGenerationConfig(
model_name="protein-mpnn",
structure_path="design.pdb",
num_sequences=10,
)
pipeline = GenerativePipeline(configs=[config])
results = pipeline.run()
Serialization and resumability
Pipeline definitions can be serialized with PipelineDef
for round-trip storage. DuckDB caches predictions and embeddings so re-runs skip
completed work.