Metadata-Version: 2.4
Name: ipdassembly
Version: 0.4.0
Summary: Golden Gate assembly library design: greedy + GA overhang selection, synonymous rescue, per-design fidelity correction, in-silico QC
License-Expression: MIT
Project-URL: Documentation, https://github.com/baker-laboratory/IPDassembly/tree/main/docs
Project-URL: Source, https://github.com/baker-laboratory/IPDassembly
Keywords: golden gate,assembly,synthetic biology,oligo,overhang,DNA
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: numpy>=1.21
Requires-Dist: pandas>=1.3
Requires-Dist: biopython>=1.79
Requires-Dist: tqdm>=4.60
Provides-Extra: fast
Requires-Dist: numba>=0.56; extra == "fast"
Provides-Extra: domesticator
Requires-Dist: dnachisel>=3.2; extra == "domesticator"
Provides-Extra: mcp
Requires-Dist: mcp>=1.2; extra == "mcp"
Provides-Extra: all
Requires-Dist: numba>=0.56; extra == "all"
Requires-Dist: dnachisel>=3.2; extra == "all"
Requires-Dist: mcp>=1.2; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: numba>=0.56; extra == "dev"
Dynamic: license-file

# ipdassembly

Golden Gate assembly library design: split designs to a chip oligo length, pick overhangs with a
greedy solver and/or a genetic algorithm, reverse-translate protein input, clear enzyme sites by
synonymous substitution, add adapters/primers/padding, report a per-design success probability,
and QC by in-silico digest and re-assembly.

```bash
pip install "ipdassembly[all]"
```

or use it with **no install at all** — it is pure Python with its data bundled, so
`sys.path.insert(0, "IPDassembly/src")` is enough if you already have numpy, pandas, biopython and
tqdm. See [docs/install.md](docs/install.md).
```python
from ipd_assembly import Config, Designer

d = Designer(Config(vector="LM0627", oligo_length=230, designs_per_rxn=8))
df = d.run(fasta_files=["library.fa"])
```
```bash
ipdassembly run library.fa --oligo-length 230 --designs-per-rxn 8
```

Or use a notebook — two ship, differing only in how they install and where files come from:

| | |
|---|---|
| [`notebooks/IPDassembly_colab.ipynb`](notebooks/IPDassembly_colab.ipynb) | open in Colab: installs the package, upload widget, downloads a zip. No local setup at all |
| [`notebooks/IPDassembly_local.ipynb`](notebooks/IPDassembly_local.ipynb) | run it in your own Jupyter. Defaults to the bundled example, so it works top to bottom before you change anything |

## Documentation

| | |
|---|---|
| [docs/install.md](docs/install.md) | pip, uv, from a git tag, Colab, development install |
| [docs/input-modes.md](docs/input-modes.md) | designs vs. **predefined sets**, giving the vector, the `None` backbones, **additional overhangs to avoid** |
| [docs/chip-orders.md](docs/chip-orders.md) | several libraries in **one oligo order**, subpool addressing, plates and wells |
| [docs/pooling.md](docs/pooling.md) | how many designs per reaction, the `off_target_allowed` ladder, the two solvers, fidelity correction |
| [docs/api.md](docs/api.md) | `Config` field by field, `Designer` methods, every module-level function |
| [docs/cli.md](docs/cli.md) | the `ipdassembly` command |
| [docs/enzymes.md](docs/enzymes.md) | enzyme table, the five bundled ligation matrices, registering your own |
| [docs/mcp.md](docs/mcp.md) | driving it from an AI client instead — optional, one config entry |
| [docs/provenance.md](docs/provenance.md) | what each module came from, the bugs fixed on the way, how the tests pin it |

## What it takes as input

| | you give | what it does |
|---|---|---|
| **designs** | whole sequences, protein or DNA, mixed is fine | reverse-translate, domesticate, split to the oligo length, choose overhangs, pool |
| **predefined sets** | the fragments themselves, named `Set<N>-...` | takes them as given, reads the assembly order back out of the overhangs they carry, scores the well |

Either way the vector is separate from the FASTA and can be a registered name, a backbone
sequence, the two sticky ends outright, or nothing at all (`"None"` / `"None-BsaI"`) when the
fragments carry their own ends. See [docs/input-modes.md](docs/input-modes.md).

**Several libraries in one order.** Pass more than one FASTA and each becomes a *subpool* with its
own plates and its own primers, so they share a chip but still amplify apart. Libraries needing
different vectors or oligo lengths — or a predefined set alongside protein designs — go through
`order_chip`. See [docs/chip-orders.md](docs/chip-orders.md).

Designing and ordering are two steps, because the slow half (splitting, choosing overhangs) and
the instant half (adapters, primers, padding, addressing) have different scopes — so changing the
chip layout costs a second, not a re-solve.

```python
from ipd_assembly import Config, Subpool, design_campaign, build_order

lib = design_campaign([
    Subpool("binders",  "binders.fa",  input_type="protein", vector="LM0627", pooled=True),
    Subpool("controls", "controls.fa", input_type="protein", vector="LM0627", pooled=False),
    Subpool("presets",  "presets.fa",  vector="None-BsaI", input_mode="predefined_set"),
], base=Config(oligo_length=300))

order = build_order(lib, output_prefix="out/run7_")
```

## Three things to decide before anything else

Everything downstream follows from these, and none of them has a defensible default.

| | why it cannot be guessed |
|---|---|
| **oligo length** | what the vendor will synthesise. It sets how many fragments each design splits into |
| **vector** | a registered name, a backbone (plus the enzyme), or the two sticky ends outright |
| **multiplexed or single** | one design per reaction or multiplexed pooling designs |

The fourth number — designs per reaction — you should *not* decide: it is measured from your own
sequences in well under a second.

```python
d.recommend_designs_per_rxn(sequences, off_target_allowed=12)
# -> {"designs_per_rxn": 7, "n_fragments": 4, "pool_fidelity": 0.79, ...}

d.plan_pooling(sequences, target=15)      # or ask for a number and be told what it costs
```

[docs/pooling.md](docs/pooling.md) has the measured tables behind both.

## Pipeline

```
FASTA ─┬─ DNA ───────────────────────────────┐
       ├─ protein → reverse translate ───────┤
       └─ Set<N>- names → predefined set ────┤   (fragments taken as given)
            ↓  domesticate (clear pre-existing enzyme sites)
            ↓  split to the oligo length
     greedy MRV/LCV overhang pick (~5 ms) ── pool filled → done
            ↓  pool not filled
     GA seeded from the greedy solution (~10 s)
            ↓  designs still unplaced
     synonymous codon swap → reshuffle → retry
            ↓
     pool fidelity → per-design success probability
            ↓
     enzyme adapters / vector sticky ends / nested PCR primers / padding
            ↓
     QC: primer placement, cut counts, re-assembly, translation
            ↓
     CSV + fragments / oligos / new-template FASTA
```

Oligo layout — the pad sits on the **3'** side, so the forward primer abuts the enzyme site:

```
F1 ── enzyme site ── (sticky) ── fragment ── (sticky) ── enzyme site ── pad ── R2 ── R1
└──────────────────── oligo_length when pad_to_fixed_length=True ────────────────────┘
```

## Tests

```bash
pip install -e ".[dev]"
pytest -q          # ~140 tests, ~3 min
```

`tests/test_golden.py` pins output against the validated reference implementation — discrete
columns byte-for-byte, fidelity floats to 16 ULP. `tests/test_determinism.py` runs the pipeline
under two different `PYTHONHASHSEED` values and requires identical output.
`tests/test_notebook.py` executes every cell of the shipped notebook.

## License

Code: MIT — see [LICENSE](LICENSE).

Bundled data: the overhang-ligation matrices are from Pryor JM *et al.* (2020) PLoS ONE 15(9):
e0238592, used under CC BY 4.0 — see [NOTICE](NOTICE), [docs/enzymes.md](docs/enzymes.md) and
`src/ipd_assembly/data/SOURCES.md`.
