---
title: Design small molecules | Boltz API Docs
description: Generate novel small molecules against a protein target, monitor progress, fetch scored results, and stop early if needed.
---

Small molecule design generates novel molecules scored by binding confidence (likelihood of binding, for hit discovery), optimization score (binding strength ranking, for lead optimization), and structure confidence. Results stream in as they’re generated — you can fetch them before the run finishes and stop early if you’ve found what you need.

## Results and artifacts

Design runs generate molecule results over time. As soon as a molecule is computed, you can read and download the result without waiting for the full design run to finish.

Each generated molecule result includes scoring metrics such as binding confidence, optimization score, and structure confidence. Each result also includes downloadable artifacts for the predicted bound structure and PAE.

## Define a target

Targets are protein-only entities. The engine automatically identifies the binding pocket to use during the run. You can provide hints to help it find the right one:

- **`pocket_residues`** — If you already know the pocket residues, pass them directly as a map of chain ID to an array of 0-indexed residue indices.
- **`reference_ligands`** — If you have known binders, pass them as an array of SMILES strings. The engine uses these to locate the pocket region.

You can provide one or both. Either will help the engine use the correct binding pocket, and providing both gives it the strongest signal.

```
{
  "target": {
    "entities": [
      { "type": "protein", "value": "MKTIIALSYIFCLVFA...", "chain_ids": ["A"] }
    ],
    "pocket_residues": {
      "A": [10, 11, 12, 35, 36, 37]
    }
  }
}
```

## Chemical space

The `chemical_space` parameter controls the building blocks available for molecule generation. By default, design uses the `enamine_real` chemical space, which is constrained to commercially available and synthetically accessible building blocks. This ensures that generated molecules can actually be made in the lab — avoiding the common pitfall of generating computationally promising molecules that turn out to be impossible or prohibitively expensive to synthesize.

Contact `contact@boltz.bio` for access to other chemical spaces.

## Molecular filters

Filters control which generated molecules pass through to results. All custom filters use AND logic — a molecule must pass every filter.

### Built-in filter

The `boltz_smarts_catalog_filter_level` parameter controls Boltz’s built-in structural alert filtering. Our medicinal chemistry team has curated these filters from extensive drug discovery experience, encoding patterns known to cause toxicity, reactivity, or poor pharmacokinetics.

| Level                   | Description                                                                |
| ----------------------- | -------------------------------------------------------------------------- |
| `recommended` (default) | Balanced filtering that catches the most common problematic substructures. |
| `extra`                 | Stricter filtering with additional alerts.                                 |
| `aggressive`            | Most conservative — rejects anything with a known structural concern.      |
| `disabled`              | No built-in filtering.                                                     |

We strongly recommend keeping the built-in filter at `recommended` or higher. Disabling it may produce molecules with poor drug-likeness, toxicity liabilities, or reactive functional groups that would make them unsuitable as therapeutics. If you’re considering disabling the built-in filter, contact us at **<contact@boltz.bio>** — we’re happy to discuss which filter level is right for your use case.

### Custom filters

Add any combination of these to the `custom_filters` array:

| Filter type               | What it does                                                                                                                                                                                                                             |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `lipinski_filter`         | Lipinski’s Rule of Five — set `max_mw`, `max_logp`, `max_hbd`, `max_hba`. Optional `allow_single_violation`.                                                                                                                             |
| `rdkit_descriptor_filter` | RDKit descriptor ranges — `mol_wt`, `mol_logp`, `tpsa`, `num_h_donors`, `num_h_acceptors`, `num_rotatable_bonds`, `num_heteroatoms`, `num_aromatic_rings`, `num_rings`, `fraction_csp3`. Each accepts `{min, max}`.                      |
| `smarts_custom_filter`    | Reject molecules matching any of the provided SMARTS `patterns`.                                                                                                                                                                         |
| `smarts_catalog_filter`   | Reject molecules matching a named catalog: `PAINS`, `PAINS_A`, `PAINS_B`, `PAINS_C`, `BRENK`, `CHEMBL`, `CHEMBL_BMS`, `CHEMBL_Dundee`, `CHEMBL_Glaxo`, `CHEMBL_Inpharmatica`, `CHEMBL_LINT`, `CHEMBL_MLSMR`, `CHEMBL_SureChEMBL`, `NIH`. |
| `smiles_regex_filter`     | Reject molecules whose SMILES matches any of the provided regex `patterns`.                                                                                                                                                              |

- [Scientist Python](#tab-panel-60)
- [Scientist CLI](#tab-panel-61)
- [Platform Developer Python](#tab-panel-62)
- [Platform Developer Typescript](#tab-panel-63)
- [Agent CLI](#tab-panel-64)

## Run a design and download results

`run_small_molecule_design()` submits the design run, waits for generated molecules, downloads result archives, and returns a local run directory.

```
import os
from boltz_api import Boltz


client = Boltz(api_key=os.environ["BOLTZ_API_KEY"])


run_dir = client.experiments.run_small_molecule_design(
    target={
        "entities": [
            {"type": "protein", "value": "MKTIIALSYIFCLVFA", "chain_ids": ["A"]},
        ],
        "pocket_residues": {"A": [10, 11, 12, 35, 36, 37]},
    },
    num_molecules=100,
    molecule_filters={
        "boltz_smarts_catalog_filter_level": "recommended",
        "custom_filters": [
            {
                "type": "lipinski_filter",
                "max_mw": 500,
                "max_logp": 5,
                "max_hbd": 5,
                "max_hba": 10,
            },
        ],
    },
    name="small-molecule-design",
)
print(run_dir)
```

The run directory contains the sanitized run record, resumable download state, a result manifest, and downloaded files for each generated molecule:

```
boltz-experiments/small-molecule-design/
  .boltz-run.json
  run.json
  results/
    index.jsonl
    sm_des_result_.../
      metadata.json
      archive.tar.gz
      files/
        result/
          metrics.json
          predicted_structure.cif
          pae.npz
```

## Run a design and download results

The CLI starts the remote run, then `download-results` waits, resumes if interrupted, and writes results under `boltz-experiments/small-molecule-design/`.

Save your inputs to `small-molecule-design.yaml`:

```
target:
  entities:
    - type: protein
      value: MKTIIALSYIFCLVFA
      chain_ids: ["A"]
  pocket_residues:
    A: [10, 11, 12, 35, 36, 37]
num_molecules: 100
molecule_filters:
  boltz_smarts_catalog_filter_level: recommended
  custom_filters:
    - type: lipinski_filter
      max_mw: 500
      max_logp: 5
      max_hbd: 5
      max_hba: 10
```

Then start the run and download:

Terminal window

```
RUN_ID=$(
  boltz-api --format raw small-molecule:design start \
    --input @yaml://./small-molecule-design.yaml |
    jq -r '.id'
)


run_dir=$(boltz-api download-results --id "$RUN_ID" --name small-molecule-design)
echo "$run_dir"
```

Use `--input @json://./small-molecule-design.json` if your input file is JSON.

The run directory contains the sanitized run record, resumable download state, a result manifest, and downloaded files for each generated molecule:

```
boltz-experiments/small-molecule-design/
  .boltz-run.json
  run.json
  results/
    index.jsonl
    sm_des_result_.../
      metadata.json
      archive.tar.gz
      files/
        result/
          metrics.json
          predicted_structure.cif
          pae.npz
```

## Start a design run

```
import os
from boltz_api import Boltz


client = Boltz(api_key=os.environ["BOLTZ_API_KEY"])


design = client.small_molecule.design.start(
    target={
        "entities": [
            {"type": "protein", "value": "MKTIIALSYIFCLVFA", "chain_ids": ["A"]},
        ],
        "pocket_residues": {"A": [10, 11, 12, 35, 36, 37]},
    },
    num_molecules=100,
    molecule_filters={
        "boltz_smarts_catalog_filter_level": "recommended",
        "custom_filters": [
            {
                "type": "lipinski_filter",
                "max_mw": 500,
                "max_logp": 5,
                "max_hbd": 5,
                "max_hba": 10,
            },
        ],
    },
)
print(f"Design run ID: {design.id}, Status: {design.status}")
```

## Start a design run

```
import Boltz from "boltz-api";


const apiKey = process.env["BOLTZ_API_KEY"];


const client = new Boltz({ apiKey });


let design = await client.smallMolecule.design.start({
  target: {
    entities: [
      { type: "protein", value: "MKTIIALSYIFCLVFA", chain_ids: ["A"] },
    ],
    pocket_residues: { A: [10, 11, 12, 35, 36, 37] },
  },
  num_molecules: 100,
  molecule_filters: {
    boltz_smarts_catalog_filter_level: "recommended",
    custom_filters: [
      {
        type: "lipinski_filter",
        max_mw: 500,
        max_logp: 5,
        max_hbd: 5,
        max_hba: 10,
      },
    ],
  },
});
console.log(`Design run ID: ${design.id}, Status: ${design.status}`);
```

## Run a design and download results

Ask the agent to save the payload to `small-molecule-design.yaml`, estimate cost, then submit with a stable idempotency key.

```
target:
  entities:
    - type: protein
      value: MKTIIALSYIFCLVFA
      chain_ids: ["A"]
  pocket_residues:
    A: [10, 11, 12, 35, 36, 37]
num_molecules: 100
molecule_filters:
  boltz_smarts_catalog_filter_level: recommended
  custom_filters:
    - type: lipinski_filter
      max_mw: 500
      max_logp: 5
      max_hbd: 5
      max_hba: 10
```

Terminal window

```
boltz-api small-molecule:design estimate-cost \
  --input @yaml://./small-molecule-design.yaml


RUN_ID=$(
  boltz-api small-molecule:design start \
    --idempotency-key "small-molecule-design" \
    --input @yaml://./small-molecule-design.yaml \
    --raw-output --transform id
)


boltz-api download-results \
  --id "$RUN_ID" \
  --name "small-molecule-design" \
  --root-dir "./boltz-experiments" \
  --poll-interval-seconds 10
```

- [Scientist Python](#tab-panel-65)
- [Scientist CLI](#tab-panel-66)
- [Platform Developer Python](#tab-panel-67)
- [Platform Developer Typescript](#tab-panel-68)
- [Agent CLI](#tab-panel-69)

## Start now, download later

The main `run_small_molecule_design()` example already waits and downloads. To submit now and download later, use `start_small_molecule_design()` and resume with `wait_and_download()`.

```
run_dir = client.experiments.start_small_molecule_design(
    target={
        "entities": [
            {"type": "protein", "value": "MKTIIALSYIFCLVFA", "chain_ids": ["A"]},
        ],
        "pocket_residues": {"A": [10, 11, 12, 35, 36, 37]},
    },
    num_molecules=100,
    name="submit-now-finish-later",
)


client.experiments.wait_and_download(run_dir=run_dir)
```

## Resume downloads

`download-results` is the progress monitor and downloader. It can be rerun with the same name to resume from local checkpoint state.

Terminal window

```
boltz-api download-results --name small-molecule-design
boltz-api --format json download-status --name small-molecule-design
```

## Monitor progress

```
import time


while design.status not in ("succeeded", "failed", "stopped"):
    time.sleep(10)
    design = client.small_molecule.design.retrieve(design.id)
    progress = design.progress
    print(
        f"Status: {design.status}, Generated: {progress.num_molecules_generated}/{progress.total_molecules_to_generate}"
    )
```

## Monitor progress

```
while (!["succeeded", "failed", "stopped"].includes(design.status)) {
  await new Promise((r) => setTimeout(r, 10000));
  design = await client.smallMolecule.design.retrieve(design.id);
  const progress = design.progress;
  console.log(
    `Status: ${design.status}, Generated: ${progress.num_molecules_generated}/${progress.total_molecules_to_generate}`,
  );
}
```

## Resume downloads

Agents can rerun `download-results` with the same name and root directory to resume from local checkpoint state.

Terminal window

```
boltz-api download-results \
  --name "small-molecule-design" \
  --root-dir "./boltz-experiments" \
  --poll-interval-seconds 10


boltz-api --format json download-status \
  --name "small-molecule-design" \
  --root-dir "./boltz-experiments"
```

- [Scientist Python](#tab-panel-70)
- [Scientist CLI](#tab-panel-71)
- [Platform Developer Python](#tab-panel-72)
- [Platform Developer Typescript](#tab-panel-73)
- [Agent CLI](#tab-panel-74)

## Inspect downloaded results

Result pages and artifact archives are already downloaded into the run directory.

```
print(run_dir)
for result_dir in (run_dir / "results").iterdir():
    print(result_dir)
```

## Inspect downloaded results

Result pages and artifact archives are already downloaded into the run directory.

Terminal window

```
ls boltz-experiments/small-molecule-design/results
```

## Fetch paginated results

```
for result in client.small_molecule.design.list_results(design.id):
    print(f"Result {result.id}: {result.smiles}")
    print(f"  Binding confidence: {result.metrics.binding_confidence}")
    print(f"  Optimization score: {result.metrics.optimization_score}")
    print(f"  Structure confidence: {result.metrics.structure_confidence}")
    print(f"  Structure URL: {result.artifacts.structure.url}")
```

## Fetch paginated results

```
for await (const result of client.smallMolecule.design.listResults(design.id)) {
  console.log(`Result ${result.id}: ${result.smiles}`);
  console.log(`  Binding confidence: ${result.metrics.binding_confidence}`);
  console.log(`  Optimization score: ${result.metrics.optimization_score}`);
  console.log(`  Structure confidence: ${result.metrics.structure_confidence}`);
  console.log(`  Structure URL: ${result.artifacts.structure.url}`);
}
```

## Inspect downloaded results

Use the local result manifest and downloaded artifact directories after `download-results` completes or while it is resuming.

Terminal window

```
ls ./boltz-experiments/small-molecule-design/results
head -n 5 ./boltz-experiments/small-molecule-design/results/index.jsonl
```

Advanced: generated SDK clients and the CLI resource command can also list remote pages directly with `list_results` / `list-results` if you need streaming access before local download completes.

## Stop early

If you’ve collected enough molecules, stop the run. The status transitions to `stopped` and no further molecules are generated. Results already produced remain available.

- [Scientist Python](#tab-panel-75)
- [Scientist CLI](#tab-panel-76)
- [Platform Developer Python](#tab-panel-77)
- [Platform Developer Typescript](#tab-panel-78)
- [Agent CLI](#tab-panel-79)

```
client.experiments.stop(run_dir=run_dir)
```

Terminal window

```
boltz-api small-molecule:design stop --id "$RUN_ID"
```

```
client.small_molecule.design.stop(design.id)
```

```
await client.smallMolecule.design.stop(design.id);
```

Terminal window

```
boltz-api small-molecule:design stop --id "<run-id-from-start>"
```

## Metrics

| Metric                 | Range | What it measures                                         |
| ---------------------- | ----- | -------------------------------------------------------- |
| `binding_confidence`   | 0–1   | Likelihood of binding. Primary metric for hit discovery. |
| `optimization_score`   | —     | Binding strength ranking. Use for lead optimization.     |
| `structure_confidence` | 0–1   | Overall confidence in the predicted structure.           |
| `iptm`                 | 0–1   | Interface predicted TM-score.                            |
| `ptm`                  | 0–1   | Global predicted TM-score.                               |
| `plddt`                | 0–1   | Per-residue structure confidence.                        |
| `complex_plddt`        | 0–1   | pLDDT across the full complex.                           |
| `complex_iplddt`       | 0–1   | Interface pLDDT for the complex.                         |

## Status values

| Status      | Meaning                                                                     |
| ----------- | --------------------------------------------------------------------------- |
| `pending`   | The run is queued and has not started yet.                                  |
| `running`   | The run is actively generating molecules. Results may already be available. |
| `succeeded` | The run completed all requested molecules.                                  |
| `failed`    | The run encountered an error. Check the `error` field.                      |
| `stopped`   | The run was stopped early. Partial results are available.                   |
