
Germinal is a pipeline for designing de novo antibodies against specified epitopes on target proteins. The pipeline follows a 3-step process: hallucination based on ColabDesign, selective sequence redesign with AbMPNN, and cofolding with a structure prediction model. Germinal is capable of designing both nanobodies and scFvs against user-specified residues on target proteins.
We describe Germinal in the preprint: "Efficient generation of epitope-targeted de novo antibodies with Germinal"
⚠️ We are still actively working on code improvements See our recommendations/tips. The Protenix and AbLang integrations are under active development — if you run into any issues please open a GitHub issue.
Last user-validated commit:
2c0a13b(PR #61 "Fix tokenizer for IgLM"). Commits after this point have been runtime- and review-validated separately on branchfix/post-pr67-review.
2c0a13bThe commits below are bundled in PRs #55, #64, #67, #68, #69, #70 (merged) plus
the in-flight branch fix/post-pr67-review (~22 follow-up fixes). User-visible
behavior changes you should know about:
structure_model: "protenix" is now
fully supported alongside af3 and chai. Set protenix_conda_env and
protenix_model_name in your run config.ablm_model: "ablang" is now
available alongside iglm. Method controlled by ablm_method ("pll"
default, or "unmasked").msa_mode: "colabfold" for a real binder MSA.cache_binder_msa: true) — reuses the first binder's
ColabFold MSA across all subsequent designs by rewriting only the query
line. Requires msa_mode: "colabfold"; raises ValueError otherwise.af3_structure_select_mode): pick the
"best" (highest ranking_score) or "worst" AF3/Protenix sample.multi_relax: true, n_relax: 5,
relax_score_mode: "average"|"best"): post-prediction PyRosetta relax can
now spawn N parallel relaxes and aggregate their interface scores.vh_first: false now correctly
identify H-CDR3 from the last CDR (was previously mis-sliced into VL).evaluate_filters fail-loud on None metrics: any filter whose metric is
None (e.g. Protenix without full_data) now FAILS the filter loudly
instead of silently passing. If you relied on the old silent-pass, either
fix the upstream metric or remove the filter.([], False) and the trajectory loop continued silently.
Now a [ABMPNN PIPELINE FATAL] message is printed and the job exits so
the underlying issue can be diagnosed._relax_worker now
writes a traceback to {pdb}.err; pr_relax_parallel reads and prints
it inside a [RELAX ERROR] block.grad_merge_method defaults to pcgrad with a [CONFIG WARNING]
(was: silent drop of the AbLang/IgLM gradient).get_grad_mlm removed from colabdesign.ablang (CUDA RNG state leak;
callers should use method="pll" or method="unmasked")._get_or_generate_msas now generates a real binder
MSA when msa_mode in {"local", "colabfold"} (was target-only regardless)._unwrap recursion: handles arbitrary depth of single-element list
wrapping in Protenix's tensor serialization (was: [[scalar]] → [scalar]).interface_cdrs zero-division guard: empty interface no longer kills
the trajectory after structure prediction completed.idx_from_ranges empty input: returns [] instead of IndexError.lm_ll = -100 sentinel for unknown ablm_model (was -1, easily
confused with a real bad pseudolikelihood).pdockq2/LIS directly).ablm_method AttributeError (PR #69 follow-up): defensive
getattr(..., None) for models that don't set this attribute.All five tracked configs in configs/run/ now expose:
- multi_relax, n_relax, relax_score_mode (only scfv_pdl1.yaml had
these before)
- cache_binder_msa (was missing everywhere)
- ablm_model is now present in vhh_il3.yaml (was missing → KeyError)
Prerequisites: - PyRosetta (academic license required) - ColabDesign/AlphaFold-Multimer parameters (click link for download or see below for cli) - AlphaFold3 parameters (optional) - JAX with GPU support
System Requirements: - GPU: NVIDIA GPU with CUDA support - Memory: 40GB+ VRAM - Storage (recommended)*: 50GB+ space for results
*The pipeline has been tested on: A100 40GB, H100 40GB MIG, L40S 48GB, A100 80GB, and H100 80GB. These runs tested a 130 amino acid target with a 131 amino acid nanobody. For larger runs, we recommend 60GB+ VRAM.
bash
nvidia-smiInstall Miniconda or Anaconda if not already available.
Follow the instructions in environment_setup.md
Copy AlphaFold-Multimer parameters to params/ and untar them.
Alternatively, you can run the following lines inside params/ to download and untar:
bash
aria2c -x 16 https://storage.googleapis.com/alphafold/alphafold_params_2022-12-06.tar
tar -xf alphafold_params_2022-12-06.tar -C .
Activate the environment:
bash
conda activate germinal
(Optional) Run validation at any time to ensure all packages have installed correctly:
bash
python validate_install.py
Notes: - AlphaFold-Multimer and AlphaFold3 parameters are large and must be downloaded manually.
Germinal can be run using Docker:
docker build -t germinal .
docker run -it --rm --gpus all \
-v "$PWD/results:/workspace/results" \
-v "$PWD/pdbs:/workspace/pdbs" \
germinal bash
and Singularity (shown)/Apptainer:
mkdir -p results
singularity pull germinal.sif docker://jwang003/germinal:latest
singularity shell --nv \
--bind "$PWD/results:/workspace/results" \
--bind "$PWD/pdbs:/workspace/pdbs" \
--pwd /workspace \
germinal.sif
Note: Pulling may hang on
Creating SIF file...If so, check if the command is done withsingularity exec germinal.sif python -c "print('ok')"
Volumes are mounted to save generated input complexes and results from sampling.
Once inside the container you can test:
python run_germinal.py
The main entry point to the pipeline is run_germinal.py. Germinal uses Hydra for orchestrating different configurations. An example main configuration file is located in configs/config.yaml. This yaml file contains high level run parameters as well as pointers to more granular configuration settings.
These detailed options are stored in four main settings files:
configs/run/vhh.yamlconfigs/target/[your_target].yamlconfigs/filter/initial/[vhh/scfv].yamlconfigs/filters/final/[vhh/scfv].yamlconfigs/
├── config.yaml # Main configuration yaml
├── run/ # Main run settings
│ ├── vhh.yaml # Example VHH (nanobody) settings
│ └── ... # Other settings
├── target/ # Target protein configurations
│ ├── pdl1.yaml # PDL1 target example
│ └── ... # other targets
└── filter/ # Filter configurations
├── initial/
│ ├── vhh.yaml # Post-hallucination (initial) filters
│ └── ...
└── final/
├── vhh.yaml # Final acceptance filters
└── ...
To design nanobodies targeting PD-L1 using default configs (with chai as the default structure predictor):
python run_germinal.py
To design scFvs targeting PD-L1 using default configs:
python run_germinal.py run=scfv filter/initial=scfv filter/final=scfv
Note: Default configs are not meant to work well out of the box but rather be a set of reasonable default parameters that we used as a starting point for parameter exploration and sweep experiments.
If you wish to change the configuration of runs, you can:
Run with defaults:
python run_germinal.py
Switch to a different run config (e.g., new_config):
python run_germinal.py run=new_config
Use different target:
python run_germinal.py target=my_target
Use a different config file with Hydra:
python run_germinal.py --config_name new_config.yaml
Use different filters:
python run_germinal.py filter/initial=new_init_filter filter/final=new_final_filter
Hydra provides powerful CLI override capabilities. You can override any parameter in any configuration file.
!NOTE Settings in
configs/run/folder use the global namespace and do not need arunprefix before overriding. See example below.
Basic parameter overrides:
# Override trajectory limits
python run_germinal.py max_trajectories=100 max_passing_designs=50
# Override experiment settings
python run_germinal.py experiment_name=my_experiment run_config=test_run
# Override loss weights. Note: no run prefix since run settings are global
python run_germinal.py weights_plddt=1.5 weights_iptm=0.8
Filter threshold overrides:
# Make initial filters less stringent
python run_germinal.py filter.initial.clashes.value=2
# Adjust final filter thresholds
python run_germinal.py filter.final.external_plddt.value=0.9 filter.final.external_iptm.value=0.8
# Change filter operators
python run_germinal.py filter.final.sc_rmsd.operator='<=' filter.final.sc_rmsd.value=5.0
Target configuration overrides:
# Change target hotspots
python run_germinal.py target.target_hotspots=\'A26,A30,A36,A44\'
# Use different PDB file
python run_germinal.py target.target_pdb_path=\'pdbs/my_target.pdb\' target.target_name=\'my_target\'
Complex multi-parameter overrides:
# Complete scFv run with custom settings
python run_germinal.py \
run=scfv \
target=pdl1 \
max_trajectories=500 \
experiment_name=\'scfv_pdl1_test\' \
target.target_hotspots=\'A37,A39,A41\' \
filter.final.external_plddt.value=0.85 \
weights_iptm=1.0
For each new target, you will need to define a target settings yaml file which contains all relevant information about the target protin. Here is an example:
target_name: "pdl1"
target_pdb_path: "pdbs/pdl1.pdb"
target_chain: "A"
binder_chain: "B"
target_hotspots: "25,26,39,41"
dimer: false # support coming soon!
length: 133
There are two sets of filters: post-hallucination (initial) filters and final filters. The post-hallucination filters are applied after the hallucination step to determine which sequences to proceed to the redesign step. This filter set is a
$ claude mcp add germinal \
-- python -m otcore.mcp_server <graph>