> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kallima.bio/llms.txt
> Use this file to discover all available pages before exploring further.

# Complex prediction

> Dock an antibody against an antigen target using Boltz-2 and get a PDB + confidence metrics.

Complex prediction runs [Boltz-2](https://github.com/jwohlwend/boltz) to predict the 3D structure of your antibody variant docked against a registered antigen. This is the most compute-intensive pipeline — expect **20–40 minutes** of GPU runtime and 25 credits per job.

## Register an antigen

Before submitting a complex prediction, you need an antigen in your project.

```python theme={null}
from kallima import KallimaClient

client = KallimaClient(api_key)

antigen = client.antigens.create(
    project_id=project_id,
    name="TNF-alpha",
    sequence="MSTESMIRDVELAEEALPKKTGGPQGSRRCLFLSLFSFIVAGATTLFCLLHFGVIG...",
)
antigen_id = antigen["id"]
```

Antigens are reusable across variants. Register once, use in any complex prediction under the same project.

## Submit a job

```python theme={null}
job = client.complex_predictions.submit(
    variant_id=variant_id,
    antigen_id=antigen_id,
)
job.wait(timeout=3600)  # up to 40 min for large antigens
```

## Read the result

```python theme={null}
result = job.results

print(result["confidence_score"])  # pTM — global fold confidence, 0–1
print(result["iptm"])              # interface pTM — confidence in the binding pose, 0–1
print(result["model_used"])        # "boltz2"
```

**Interpreting confidence:**

| Score                    | Meaning                                |
| ------------------------ | -------------------------------------- |
| `confidence_score` > 0.8 | High confidence in overall fold        |
| `iptm` > 0.75            | Plausible binding pose                 |
| `iptm` \< 0.5            | Low confidence — treat with skepticism |

`iptm` is the more useful signal for dock quality. A high `confidence_score` with low `iptm` means the individual chains fold well but the interface is uncertain.

### Per-chain confidence

```python theme={null}
for chain, plddt_array in (result["per_chain_plddt"] or {}).items():
    mean = sum(plddt_array) / len(plddt_array)
    print(f"Chain {chain}: mean pLDDT {mean:.2f}")
```

### Interface residues

```python theme={null}
interface = result["interface_residues"] or {}
# Keys are chain IDs; values are lists of residue positions at the interface
for chain, residues in interface.items():
    print(f"Chain {chain} interface residues: {residues}")
```

## Download the PDB

```python theme={null}
import httpx

pdb_url = job.results["pdb_url"]
pdb_bytes = httpx.get(pdb_url).content

with open("complex.pdb", "wb") as f:
    f.write(pdb_bytes)
```

`pdb_url` is a signed URL that expires **1 hour** after the job completes. Re-fetch the job to rotate it.

## List prior predictions for a variant

```python theme={null}
for job in client.complex_predictions.list(variant_id=variant_id):
    print(job.id, job.status, job["created_at"])
```

List responses omit `pdb_url`. Fetch by ID to get the signed URL.

## List antigens in a project

```python theme={null}
for antigen in client.antigens.list(project_id=project_id):
    print(antigen["id"], antigen["name"])
```
