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

# Constructs

> Combining segments into complete biological designs

# Constructs

A **Construct** is an ordered collection of [Segments](/docs/language/concepts/segments) representing a complete biological design. Just as a gene is assembled from regulatory and coding parts (a promoter, ribosome binding site, coding sequence, and terminator), a Construct assembles Segment objects into a coherent whole.

<div className="block dark:hidden">
  <svg viewBox="0 0 800 250" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Construct assembling ordered segments" style={{width:"100%",height:"auto",display:"block"}}><defs><pattern id="gridconstructs1L" width="22" height="22" patternUnits="userSpaceOnUse"><circle cx="2" cy="2" r="1.2" fill="#344649" fillOpacity="0.10" /></pattern><marker id="arrconstructs1L" viewBox="0 0 10 10" refX="8.5" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 L3,5 z" fill="#768b8e" /></marker></defs><rect x="12" y="12" width="776" height="226" rx="16" fill="#f9fcfc" stroke="#dee9e8" strokeWidth="1.2" /><rect x="12" y="12" width="776" height="226" rx="16" fill="url(#gridconstructs1L)" /><rect x="38" y="42" width="722" height="172" rx="14" fill="#eef5f4" stroke="#ced9d7" strokeWidth="1.3" fillOpacity="0.55" strokeDasharray="5 4" /><text x="56" y="63" fontFamily="'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace" fontSize="10.5" fontWeight="500" fill="#768b8e" textAnchor="start" letterSpacing="1.6">Construct: gene\_construct</text><path d="M214,138 L240,138" fill="none" stroke="#9eb4b2" strokeWidth="1.6" /><path d="M386,138 L412,138" fill="none" stroke="#9eb4b2" strokeWidth="1.6" /><path d="M558,138 L584,138" fill="none" stroke="#9eb4b2" strokeWidth="1.6" /><rect x="68" y="90" width="146" height="96" rx="10" fill="#eef2f4" stroke="#dbe3e6" strokeWidth="1.2" /><rect x="127" y="102" width="28" height="3.5" rx="2" fill="#768b8e" /><text x="141" y="128" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="14" fontWeight="600" fill="#344649" textAnchor="middle">Promoter</text><text x="141" y="146" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#768b8e" textAnchor="middle">100 bp</text><text x="141" y="161" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#768b8e" textAnchor="middle">Segment</text><rect x="240" y="90" width="146" height="96" rx="10" fill="#eef2f4" stroke="#dbe3e6" strokeWidth="1.2" /><rect x="299" y="102" width="28" height="3.5" rx="2" fill="#768b8e" /><text x="313" y="128" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="14" fontWeight="600" fill="#344649" textAnchor="middle">RBS</text><text x="313" y="146" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#768b8e" textAnchor="middle">AGGAGG</text><text x="313" y="161" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#768b8e" textAnchor="middle">Segment</text><rect x="412" y="90" width="146" height="96" rx="10" fill="#eef2f4" stroke="#dbe3e6" strokeWidth="1.2" /><rect x="471" y="102" width="28" height="3.5" rx="2" fill="#768b8e" /><text x="485" y="128" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="14" fontWeight="600" fill="#344649" textAnchor="middle">CDS</text><text x="485" y="146" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#768b8e" textAnchor="middle">900 bp</text><text x="485" y="161" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#768b8e" textAnchor="middle">Segment</text><rect x="584" y="90" width="146" height="96" rx="10" fill="#eef2f4" stroke="#dbe3e6" strokeWidth="1.2" /><rect x="643" y="102" width="28" height="3.5" rx="2" fill="#768b8e" /><text x="657" y="128" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="14" fontWeight="600" fill="#344649" textAnchor="middle">Terminator</text><text x="657" y="146" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#768b8e" textAnchor="middle">50 bp</text><text x="657" y="161" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#768b8e" textAnchor="middle">Segment</text><g fill="#ffffff" stroke="#9eb4b2" strokeWidth="1.4"><circle cx="214" cy="138" r="3.2" /><circle cx="240" cy="138" r="3.2" /><circle cx="386" cy="138" r="3.2" /><circle cx="412" cy="138" r="3.2" /><circle cx="558" cy="138" r="3.2" /><circle cx="584" cy="138" r="3.2" /></g></svg>
</div>

<div className="hidden dark:block">
  <svg viewBox="0 0 800 250" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Construct assembling ordered segments" style={{width:"100%",height:"auto",display:"block"}}><defs><pattern id="gridconstructs1D" width="22" height="22" patternUnits="userSpaceOnUse"><circle cx="2" cy="2" r="1.2" fill="#9eb4b2" fillOpacity="0.10" /></pattern><marker id="arrconstructs1D" viewBox="0 0 10 10" refX="8.5" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 L3,5 z" fill="#7e9498" /></marker></defs><rect x="12" y="12" width="776" height="226" rx="16" fill="#0e1718" stroke="#2b3c3e" strokeWidth="1.2" /><rect x="12" y="12" width="776" height="226" rx="16" fill="url(#gridconstructs1D)" /><rect x="38" y="42" width="722" height="172" rx="14" fill="#15211f" stroke="#33474a" strokeWidth="1.3" fillOpacity="0.5" strokeDasharray="5 4" /><text x="56" y="63" fontFamily="'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace" fontSize="10.5" fontWeight="500" fill="#7e9498" textAnchor="start" letterSpacing="1.6">Construct: gene\_construct</text><path d="M214,138 L240,138" fill="none" stroke="#566b6e" strokeWidth="1.6" /><path d="M386,138 L412,138" fill="none" stroke="#566b6e" strokeWidth="1.6" /><path d="M558,138 L584,138" fill="none" stroke="#566b6e" strokeWidth="1.6" /><rect x="68" y="90" width="146" height="96" rx="10" fill="#1b2829" stroke="#33474a" strokeWidth="1.2" /><rect x="127" y="102" width="28" height="3.5" rx="2" fill="#7e9498" /><text x="141" y="128" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="14" fontWeight="600" fill="#d6e1df" textAnchor="middle">Promoter</text><text x="141" y="146" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#9eb4b2" textAnchor="middle">100 bp</text><text x="141" y="161" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#9eb4b2" textAnchor="middle">Segment</text><rect x="240" y="90" width="146" height="96" rx="10" fill="#1b2829" stroke="#33474a" strokeWidth="1.2" /><rect x="299" y="102" width="28" height="3.5" rx="2" fill="#7e9498" /><text x="313" y="128" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="14" fontWeight="600" fill="#d6e1df" textAnchor="middle">RBS</text><text x="313" y="146" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#9eb4b2" textAnchor="middle">AGGAGG</text><text x="313" y="161" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#9eb4b2" textAnchor="middle">Segment</text><rect x="412" y="90" width="146" height="96" rx="10" fill="#1b2829" stroke="#33474a" strokeWidth="1.2" /><rect x="471" y="102" width="28" height="3.5" rx="2" fill="#7e9498" /><text x="485" y="128" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="14" fontWeight="600" fill="#d6e1df" textAnchor="middle">CDS</text><text x="485" y="146" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#9eb4b2" textAnchor="middle">900 bp</text><text x="485" y="161" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#9eb4b2" textAnchor="middle">Segment</text><rect x="584" y="90" width="146" height="96" rx="10" fill="#1b2829" stroke="#33474a" strokeWidth="1.2" /><rect x="643" y="102" width="28" height="3.5" rx="2" fill="#7e9498" /><text x="657" y="128" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="14" fontWeight="600" fill="#d6e1df" textAnchor="middle">Terminator</text><text x="657" y="146" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#9eb4b2" textAnchor="middle">50 bp</text><text x="657" y="161" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#9eb4b2" textAnchor="middle">Segment</text><g fill="#13201f" stroke="#566b6e" strokeWidth="1.4"><circle cx="214" cy="138" r="3.2" /><circle cx="240" cy="138" r="3.2" /><circle cx="386" cy="138" r="3.2" /><circle cx="412" cy="138" r="3.2" /><circle cx="558" cy="138" r="3.2" /><circle cx="584" cy="138" r="3.2" /></g></svg>
</div>

The Construct handles validation (all segments must share the same type), auto-labeling, and, crucially, **joined sequence concatenation**, which gives the full designed sequence after optimization.

***

## Creating Constructs

Pass an ordered list of Segments to create a Construct:

```python python icon="python" theme={null}
from proto_language.core import Segment, Construct

promoter = Segment(length=100, sequence_type="dna", label="promoter")
rbs = Segment(sequence="AGGAGG", sequence_type="dna", label="rbs")
cds = Segment(length=900, sequence_type="dna", label="cds")
terminator = Segment(length=50, sequence_type="dna", label="terminator")

gene_construct = Construct(
    [promoter, rbs, cds, terminator],
    label="gene_construct"
)
```

Segment order matters; it defines the physical arrangement of the final biological sequence.

***

## Validation Rules

Constructs enforce several rules at creation time to catch design errors early:

<Warning>
  **All segments must share the same sequence type.** DNA and protein segments cannot be mixed in one Construct. To represent a gene and its protein product, use separate Constructs.
</Warning>

<Warning>
  **All segments must share the same valid character set.** If one segment uses custom `valid_chars`, all segments in the Construct must use the same set.
</Warning>

<Warning>
  **Segment labels must be unique** within a Construct. Duplicate labels cause a `ValueError`.
</Warning>

```python python icon="python" theme={null}
# Valid: all DNA segments
construct = Construct([
    Segment(length=50, sequence_type="dna", label="upstream"),
    Segment(length=100, sequence_type="dna", label="target"),
])

# Invalid: mixed types -> raises ValueError
construct = Construct([
    Segment(length=50, sequence_type="dna", label="gene"),
    Segment(length=100, sequence_type="protein", label="protein"),  # Error!
])

# Invalid: duplicate labels -> raises ValueError
construct = Construct([
    Segment(length=50, sequence_type="dna", label="region"),
    Segment(length=100, sequence_type="dna", label="region"),  # Error!
])
```

***

## Joined Sequences

The most important property of a Construct is `joined_sequences`. After optimization, this gives the full concatenated sequence from all segments, with merged metadata from each segment.

<div className="block dark:hidden">
  <svg viewBox="0 0 720 380" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Joined sequences concatenated from segment results" style={{width:"100%",height:"auto",display:"block"}}><defs><pattern id="gridconstructs2L" width="22" height="22" patternUnits="userSpaceOnUse"><circle cx="2" cy="2" r="1.2" fill="#344649" fillOpacity="0.10" /></pattern><marker id="arrconstructs2L" viewBox="0 0 10 10" refX="8.5" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 L3,5 z" fill="#768b8e" /></marker></defs><rect x="12" y="12" width="696" height="356" rx="16" fill="#f9fcfc" stroke="#dee9e8" strokeWidth="1.2" /><rect x="12" y="12" width="696" height="356" rx="16" fill="url(#gridconstructs2L)" /><rect x="44" y="50" width="208" height="288" rx="14" fill="#eef5f4" stroke="#ced9d7" strokeWidth="1.3" fillOpacity="0.55" strokeDasharray="5 4" /><text x="62" y="71" fontFamily="'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace" fontSize="10.5" fontWeight="500" fill="#768b8e" textAnchor="start" letterSpacing="1.6">Individual Segments</text><path d="M226,128 C 348,128 348,186 470,186" fill="none" stroke="#9eb4b2" strokeWidth="1.6" markerEnd="url(#arrconstructs2L)" /><path d="M226,206 L470,206" fill="none" stroke="#9eb4b2" strokeWidth="1.6" markerEnd="url(#arrconstructs2L)" /><path d="M226,284 C 348,284 348,226 470,226" fill="none" stroke="#9eb4b2" strokeWidth="1.6" markerEnd="url(#arrconstructs2L)" /><rect x="70" y="98" width="156" height="60" rx="10" fill="#f4f9f9" stroke="#dbe6e4" strokeWidth="1.2" /><rect x="80" y="110" width="4" height="36" rx="2" fill="#768b8e" /><text x="148" y="126" fontFamily="'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace" fontSize="14" fontWeight="600" fill="#1d2c2f" textAnchor="middle">ATGC</text><text x="148" y="144" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#768b8e" textAnchor="middle">Seg 1 result:</text><rect x="70" y="176" width="156" height="60" rx="10" fill="#f4f9f9" stroke="#dbe6e4" strokeWidth="1.2" /><rect x="80" y="188" width="4" height="36" rx="2" fill="#768b8e" /><text x="148" y="204" fontFamily="'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace" fontSize="14" fontWeight="600" fill="#1d2c2f" textAnchor="middle">GGAA</text><text x="148" y="222" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#768b8e" textAnchor="middle">Seg 2 result:</text><rect x="70" y="254" width="156" height="60" rx="10" fill="#f4f9f9" stroke="#dbe6e4" strokeWidth="1.2" /><rect x="80" y="266" width="4" height="36" rx="2" fill="#768b8e" /><text x="148" y="282" fontFamily="'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace" fontSize="14" fontWeight="600" fill="#1d2c2f" textAnchor="middle">TTCC</text><text x="148" y="300" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#768b8e" textAnchor="middle">Seg 3 result:</text><rect x="470" y="168" width="210" height="76" rx="10" fill="#2f8f6b" /><rect x="480" y="180" width="4" height="52" rx="2" fill="#d4ebe0" /><text x="575" y="204" fontFamily="'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace" fontSize="14" fontWeight="600" fill="#ffffff" textAnchor="middle">ATGCGGAATTCC</text><text x="575" y="222" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#d4ebe0" textAnchor="middle">joined\_sequences:</text><g fill="#ffffff" stroke="#9eb4b2" strokeWidth="1.4"><circle cx="226" cy="128" r="3.2" /><circle cx="226" cy="206" r="3.2" /><circle cx="226" cy="284" r="3.2" /><circle cx="470" cy="186" r="3.2" /><circle cx="470" cy="206" r="3.2" /><circle cx="470" cy="226" r="3.2" /></g></svg>
</div>

<div className="hidden dark:block">
  <svg viewBox="0 0 720 380" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Joined sequences concatenated from segment results" style={{width:"100%",height:"auto",display:"block"}}><defs><pattern id="gridconstructs2D" width="22" height="22" patternUnits="userSpaceOnUse"><circle cx="2" cy="2" r="1.2" fill="#9eb4b2" fillOpacity="0.10" /></pattern><marker id="arrconstructs2D" viewBox="0 0 10 10" refX="8.5" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 L3,5 z" fill="#7e9498" /></marker></defs><rect x="12" y="12" width="696" height="356" rx="16" fill="#0e1718" stroke="#2b3c3e" strokeWidth="1.2" /><rect x="12" y="12" width="696" height="356" rx="16" fill="url(#gridconstructs2D)" /><rect x="44" y="50" width="208" height="288" rx="14" fill="#15211f" stroke="#33474a" strokeWidth="1.3" fillOpacity="0.5" strokeDasharray="5 4" /><text x="62" y="71" fontFamily="'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace" fontSize="10.5" fontWeight="500" fill="#7e9498" textAnchor="start" letterSpacing="1.6">Individual Segments</text><path d="M226,128 C 348,128 348,186 470,186" fill="none" stroke="#566b6e" strokeWidth="1.6" markerEnd="url(#arrconstructs2D)" /><path d="M226,206 L470,206" fill="none" stroke="#566b6e" strokeWidth="1.6" markerEnd="url(#arrconstructs2D)" /><path d="M226,284 C 348,284 348,226 470,226" fill="none" stroke="#566b6e" strokeWidth="1.6" markerEnd="url(#arrconstructs2D)" /><rect x="70" y="98" width="156" height="60" rx="10" fill="#1a2a2b" stroke="#33474a" strokeWidth="1.2" /><rect x="80" y="110" width="4" height="36" rx="2" fill="#7e9498" /><text x="148" y="126" fontFamily="'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace" fontSize="14" fontWeight="600" fill="#eef5f4" textAnchor="middle">ATGC</text><text x="148" y="144" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#9eb4b2" textAnchor="middle">Seg 1 result:</text><rect x="70" y="176" width="156" height="60" rx="10" fill="#1a2a2b" stroke="#33474a" strokeWidth="1.2" /><rect x="80" y="188" width="4" height="36" rx="2" fill="#7e9498" /><text x="148" y="204" fontFamily="'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace" fontSize="14" fontWeight="600" fill="#eef5f4" textAnchor="middle">GGAA</text><text x="148" y="222" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#9eb4b2" textAnchor="middle">Seg 2 result:</text><rect x="70" y="254" width="156" height="60" rx="10" fill="#1a2a2b" stroke="#33474a" strokeWidth="1.2" /><rect x="80" y="266" width="4" height="36" rx="2" fill="#7e9498" /><text x="148" y="282" fontFamily="'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace" fontSize="14" fontWeight="600" fill="#eef5f4" textAnchor="middle">TTCC</text><text x="148" y="300" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#9eb4b2" textAnchor="middle">Seg 3 result:</text><rect x="470" y="168" width="210" height="76" rx="10" fill="#2f8f6b" /><rect x="480" y="180" width="4" height="52" rx="2" fill="#cfeadd" /><text x="575" y="204" fontFamily="'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace" fontSize="14" fontWeight="600" fill="#ffffff" textAnchor="middle">ATGCGGAATTCC</text><text x="575" y="222" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11.5" fontWeight="400" fill="#cfeadd" textAnchor="middle">joined\_sequences:</text><g fill="#13201f" stroke="#566b6e" strokeWidth="1.4"><circle cx="226" cy="128" r="3.2" /><circle cx="226" cy="206" r="3.2" /><circle cx="226" cy="284" r="3.2" /><circle cx="470" cy="186" r="3.2" /><circle cx="470" cy="206" r="3.2" /><circle cx="470" cy="226" r="3.2" /></g></svg>
</div>

```python python icon="python" theme={null}
# After optimization, get the full sequences
for seq in construct.joined_sequences:
    print(f"Full sequence ({len(seq)} bp): {seq.sequence[:50]}...")
    print(f"Segments: {list(seq.metadata.get('segments', {}).keys())}")
```

### Multiple Results (Top-K)

When the optimizer selects multiple results per segment (e.g., top-3), `joined_sequences` pairs them by index:

```python python icon="python" theme={null}
# If each segment has 3 result sequences:
# segment_1.result_sequences = [Seq("AAA"), Seq("TTT"), Seq("GGG")]
# segment_2.result_sequences = [Seq("CCC"), Seq("AAA"), Seq("TTT")]

construct.joined_sequences
# [Sequence("AAACCC"),   # index 0 from each segment
#  Sequence("TTTAAA"),   # index 1 from each segment
#  Sequence("GGGTTT")]   # index 2 from each segment
```

<Note>
  All segments in a Construct must have the **same number** of result sequences. `joined_sequences` raises a `RuntimeError` if the per-segment result pools have mismatched lengths.
</Note>

***

## Auto-Labeling

Both Constructs and Segments support automatic labeling:

```python python icon="python" theme={null}
# Unlabeled segments get position-based labels
construct = Construct([
    Segment(length=50, sequence_type="dna"),         # -> "segment_0"
    Segment(length=100, sequence_type="dna"),        # -> "segment_1"
    Segment(length=30, sequence_type="dna", label="my_term"),  # -> "my_term"
])

construct.segments[0].label  # "segment_0"
construct.segments[2].label  # "my_term"
```

<Tip>
  Always provide explicit labels for clarity. They appear in constraint metadata and make optimization results easier to interpret.
</Tip>

***

## Biological Design Patterns

<Tabs>
  <Tab title="Gene Expression">
    The classic pattern for designing gene circuits: promoter, RBS, coding sequence, and terminator in series.

    ```python python icon="python" theme={null}
    # Bacterial gene
    promoter = Segment(length=100, sequence_type="dna", label="promoter")
    rbs = Segment(sequence="AGGAGG", sequence_type="dna", label="rbs")
    cds = Segment(length=900, sequence_type="dna", label="cds")
    terminator = Segment(
        sequence="AACAAAATCGCAATGATTTCGATTTTAAAAGGTCTG",
        sequence_type="dna",
        label="terminator"
    )

    gene_construct = Construct(
        [promoter, rbs, cds, terminator],
        label="gene_construct"
    )
    ```

    Use cross-segment constraints to evaluate predicted expression levels considering all elements together.
  </Tab>

  <Tab title="Multi-Domain Protein">
    Design fusion proteins with fixed structural elements and variable functional domains.

    ```python python icon="python" theme={null}
    # Antibody-like fusion protein
    signal = Segment(
        sequence="MKFLILLFNILCLFPVLAAD",
        sequence_type="protein",
        label="signal_peptide"
    )
    vh = Segment(length=120, sequence_type="protein", label="vh_domain")
    linker = Segment(
        sequence="GGGGSGGGGSGGGGS",
        sequence_type="protein",
        label="linker"
    )
    vl = Segment(length=110, sequence_type="protein", label="vl_domain")

    scfv = Construct(
        [signal, vh, linker, vl],
        label="scfv_construct"
    )
    ```

    The linker and signal peptide are fixed; only the VH and VL domains are optimized.
  </Tab>

  <Tab title="CRISPR System">
    Design guide RNA components with fixed scaffold and variable spacer.

    ```python python icon="python" theme={null}
    # CRISPR-Cas9 guide RNA
    spacer = Segment(length=20, sequence_type="rna", label="spacer")
    scaffold = Segment(
        sequence="GUUUUAGAGCUAGAAAUAGCAAGUUAAAAUAAGGCUAGUCCGUUAUCAACUUGAAAAAGUGGCACCGAGUCGGUGC",
        sequence_type="rna",
        label="scaffold"
    )

    guide_rna = Construct(
        [spacer, scaffold],
        label="sgrna"
    )
    ```

    Only the spacer is optimized; the scaffold stays constant. Constraints can score on-target specificity and off-target avoidance.
  </Tab>

  <Tab title="Plasmid Insert">
    Design a multi-gene insert with regulatory elements.

    ```python python icon="python" theme={null}
    # Two-gene operon
    promoter = Segment(length=80, sequence_type="dna", label="promoter")
    gene1 = Segment(length=600, sequence_type="dna", label="gene1")
    intergenic = Segment(length=30, sequence_type="dna", label="intergenic")
    gene2 = Segment(length=450, sequence_type="dna", label="gene2")
    terminator = Segment(length=40, sequence_type="dna", label="terminator")

    operon = Construct(
        [promoter, gene1, intergenic, gene2, terminator],
        label="operon_insert"
    )
    ```

    Cross-segment constraints can evaluate the entire operon for predicted expression balance between the two genes.
  </Tab>
</Tabs>

***

## Working with Optimizers

Optimizers take a list of Constructs to optimize. Multiple optimizers in a [Program](/docs/language/concepts/programs) must share the **same Construct objects by identity** so that results persist between stages.

```python python icon="python" theme={null}
# Correct: same construct object passed to both stages
construct = Construct([promoter, cds], label="my_design")

stage1 = RejectionSamplingOptimizer(
    constructs=[construct],  # same object
    generators=[broad_gen],
    constraints=[fast_constraint],
    config=RejectionSamplingOptimizerConfig(num_samples=5000, num_results=50)
)

stage2 = MCMCOptimizer(
    constructs=[construct],  # same object: results flow through
    generators=[fine_gen],
    constraints=[expensive_constraint],
    config=MCMCOptimizerConfig(num_steps=500)
)

program = Program(optimizers=[stage1, stage2], num_results=10)
program.run()

# Results are in the construct's segments
for seq in construct.joined_sequences:
    print(seq.sequence)
```

<Warning>
  Do **not** create separate Construct instances for each optimizer stage. The result sequences from stage 1 would be lost. Always reuse the same Construct object.
</Warning>

***

## Properties

| Property           | Type                  | Description                                 |
| ------------------ | --------------------- | ------------------------------------------- |
| `segments`         | `tuple[Segment, ...]` | Ordered tuple of Segment objects            |
| `sequence_type`    | `SequenceType`        | Shared type across all segments (read-only) |
| `valid_chars`      | `Optional[Set[str]]`  | Shared valid characters (read-only)         |
| `joined_sequences` | `List[Sequence]`      | Concatenated sequences from result pools    |
| `label`            | `Optional[str]`       | Identifier for this construct               |

***

## Serialization

Constructs serialize to dictionaries, including all their segments and both sequence pools:

<CodeGroup>
  ```python python icon="python" title="Serialize" theme={null}
  data = construct.to_dict()
  # {
  #     "segments": [
  #         { "label": "promoter", "sequence_length": 100, ... },
  #         { "label": "cds", "sequence_length": 900, ... },
  #     ],
  #     "sequence_type": "dna",
  #     "valid_chars": ["A", "C", "G", "T"],
  #     "label": "gene_construct"
  # }
  ```

  ```python python icon="python" title="Deserialize" theme={null}
  restored = Construct.from_dict(data)
  restored.label                     # "gene_construct"
  len(restored.segments)             # 2
  restored.segments[0].label         # "promoter"
  ```
</CodeGroup>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Generators" icon="cpu" href="/docs/language/concepts/generators">
    How generators propose candidate sequences for each segment
  </Card>

  <Card title="Constraints" icon="square-function" href="/docs/language/concepts/constraints">
    Scoring functions for design objectives
  </Card>

  <Card title="Programs" icon="list-tree" href="/docs/language/concepts/programs">
    Chain optimizers into multi-stage pipelines
  </Card>

  <Card title="Overview" icon="book-open" href="/docs/language/concepts/overview">
    See how Constructs fit into the full architecture
  </Card>
</CardGroup>
