Skill Tracer
Skills › Scientific Agent Skills › opentrons-integration › api_reference.md

api_reference.md

396 lines · skills/opentrons-integration/references/api_reference.md at 5f2bc03

Open on GitHub
1# Opentrons Protocol API v2 Quick Reference
2
3Verified against `opentrons==10.0.0` and the official documentation on
42026-10-01. This is a curated authoring reference, not a replacement for the
5[ProtocolContext API reference](https://docs.opentrons.com/python-api/reference/protocols/)
6and its linked class references.
7

Opentrons Protocol API v2 Quick Reference

Verified against opentrons==10.0.0 and the official documentation on 2026-10-01. This is a curated authoring reference, not a replacement for the ProtocolContext API reference and its linked class references.

Raw lines 1 to 7
8## Version Baseline
9
10| Robot | Supported API range on current software | Documented robot maximum |
11| --- | --- | --- |
12| Flex | 2.15–2.30 | 2.30 |
13| OT-2 | 2.0–2.28 | 2.28 |
15API versions are independent of the installed Python package and robot software.
16Choose the lowest API level that includes every required feature. A protocol
17specifying a higher level than the robot supports will fail analysis.
19```python
20metadata = {
21 "protocolName": "Example",
22 "author": "Your Name",
23 "description": "Purpose and scope.",
25requirements = {"robotType": "Flex", "apiLevel": "2.29"}
26```
28Rules:
30- Flex always requires `requirements`.
31- `requirements` is recommended for OT-2 protocols using API 2.15+.
32- Put `apiLevel` in exactly one place. When using `requirements`, remove it from
33 `metadata`.
34- `run(protocol: protocol_api.ProtocolContext)` is the required entry point.

Version Baseline

RobotSupported API range on current softwareDocumented robot maximum
Flex2.15–2.302.30
OT-22.0–2.282.28

API versions are independent of the installed Python package and robot software. Choose the lowest API level that includes every required feature. A protocol specifying a higher level than the robot supports will fail analysis.

metadata = {
    "protocolName": "Example",
    "author": "Your Name",
    "description": "Purpose and scope.",
}
requirements = {"robotType": "Flex", "apiLevel": "2.29"}

Rules:

  • Flex always requires requirements.
  • requirements is recommended for OT-2 protocols using API 2.15+.
  • Put apiLevel in exactly one place. When using requirements, remove it from metadata.
  • run(protocol: protocol_api.ProtocolContext) is the required entry point.
Raw lines 8 to 35
36## Features Added After API 2.19
38| API | High-value additions |
39| --- | --- |
40| 2.20 | CSV runtime parameters; liquid presence detection; row, single, and partial-column nozzle layouts |
41| 2.21 | `AbsorbanceReaderContext` and `absorbanceReaderV1` |
42| 2.22 | `Labware.load_liquid()`, `load_liquid_by_well()`, and `load_empty()`; robot motor control |
43| 2.23 | `Well.meniscus()`; labware lids and lid moves |
44| 2.24 | Liquid classes; advanced liquid-class complex commands; absolute flow-rate options |
45| 2.25 | `FlexStackerContext`; `flexStackerModuleV1`; `flex_96channel_200` |
46| 2.26 | Liquid-class support for `flex_96channel_200` |
47| 2.27 | Concurrent module actions; dynamic aspirate, dispense, and mix; `capture_image()`; explicit liquid-class tips |
48| 2.28 | Flex 20 µL tips; partial-tip return; thermocycler ramp rate; empty tip-rack tracking |
49| 2.29 | Protocol step grouping |
50| 2.30 | Start-only meniscus aspiration without an end location |
52See
53[Versioning](https://docs.opentrons.com/python-api/versioning/) for complete
54behavior changes and robot-software mappings.

Features Added After API 2.19

APIHigh-value additions
2.20CSV runtime parameters; liquid presence detection; row, single, and partial-column nozzle layouts
2.21AbsorbanceReaderContext and absorbanceReaderV1
2.22Labware.load_liquid(), load_liquid_by_well(), and load_empty(); robot motor control
2.23Well.meniscus(); labware lids and lid moves
2.24Liquid classes; advanced liquid-class complex commands; absolute flow-rate options
2.25FlexStackerContext; flexStackerModuleV1; flex_96channel_200
2.26Liquid-class support for flex_96channel_200
2.27Concurrent module actions; dynamic aspirate, dispense, and mix; capture_image(); explicit liquid-class tips
2.28Flex 20 µL tips; partial-tip return; thermocycler ramp rate; empty tip-rack tracking
2.29Protocol step grouping
2.30Start-only meniscus aspiration without an end location

See Versioning for complete behavior changes and robot-software mappings.

Raw lines 36 to 55
56## Pipette Load Names

Pipette Load Names

Raw lines 56 to 57
58### Flex
60| Pipette | Nominal range | Load name |
61| --- | ---: | --- |
62| 1-Channel 50 µL | 1–50 µL | `flex_1channel_50` |
63| 1-Channel 1000 µL | 5–1000 µL | `flex_1channel_1000` |
64| 8-Channel 50 µL | 1–50 µL | `flex_8channel_50` |
65| 8-Channel 1000 µL | 5–1000 µL | `flex_8channel_1000` |
66| 96-Channel 200 µL | 1–200 µL | `flex_96channel_200` |
67| 96-Channel 1000 µL | 5–1000 µL | `flex_96channel_1000` |
69Flex 50 µL pipettes need `configure_for_volume(1)` (or the intended 1–4.9 µL
70volume) before low-volume handling. Call it while empty, preferably before tip
71pickup. That mode permits 1–30 µL; normal mode permits 5–50 µL. Tip capacity
72can impose a lower maximum. These are documented ranges; the simulator's
73lower `min_volume` value does not qualify sub-1 µL dispensing. Changing mode
74resets flow rates. See the
75[volume-mode guide](https://docs.opentrons.com/python-api/pipettes/volume-modes/).
77The 96-channel pipette occupies both mounts. From API 2.16 onward its `mount`
78argument is optional.

Flex

PipetteNominal rangeLoad name
1-Channel 50 µL1–50 µLflex_1channel_50
1-Channel 1000 µL5–1000 µLflex_1channel_1000
8-Channel 50 µL1–50 µLflex_8channel_50
8-Channel 1000 µL5–1000 µLflex_8channel_1000
96-Channel 200 µL1–200 µLflex_96channel_200
96-Channel 1000 µL5–1000 µLflex_96channel_1000

Flex 50 µL pipettes need configure_for_volume(1) (or the intended 1–4.9 µL volume) before low-volume handling. Call it while empty, preferably before tip pickup. That mode permits 1–30 µL; normal mode permits 5–50 µL. Tip capacity can impose a lower maximum. These are documented ranges; the simulator's lower min_volume value does not qualify sub-1 µL dispensing. Changing mode resets flow rates. See the volume-mode guide.

The 96-channel pipette occupies both mounts. From API 2.16 onward its mount argument is optional.

Raw lines 58 to 79
80### OT-2 GEN2
82| Pipette | Nominal range | Load name |
83| --- | ---: | --- |
84| P20 single | 1–20 µL | `p20_single_gen2` |
85| P20 multi | 1–20 µL | `p20_multi_gen2` |
86| P300 single | 20–300 µL | `p300_single_gen2` |
87| P300 multi | 20–300 µL | `p300_multi_gen2` |
88| P1000 single | 100–1000 µL | `p1000_single_gen2` |
90GEN1 OT-2 pipettes have different load names. Check
91[Loading Pipettes](https://docs.opentrons.com/python-api/pipettes/loading/)
92instead of guessing.

OT-2 GEN2

PipetteNominal rangeLoad name
P20 single1–20 µLp20_single_gen2
P20 multi1–20 µLp20_multi_gen2
P300 single20–300 µLp300_single_gen2
P300 multi20–300 µLp300_multi_gen2
P1000 single100–1000 µLp1000_single_gen2

GEN1 OT-2 pipettes have different load names. Check Loading Pipettes instead of guessing.

Raw lines 80 to 93
94## Flex Tip Compatibility
96| Pipette family | Compatible Flex tip-rack capacities |
97| --- | --- |
98| `flex_1channel_50`, `flex_8channel_50` | 20 µL, 50 µL |
99| `flex_96channel_200` | 20 µL, 50 µL, 200 µL |
100| `flex_1channel_1000`, `flex_8channel_1000`, `flex_96channel_1000` | 50 µL, 200 µL, 1000 µL |
102Filter-tip load names insert `_filtertiprack_`, for example
103`opentrons_flex_96_filtertiprack_200ul`.
105Full-rack pickup by a Flex 96-channel pipette requires the Flex tip-rack
106adapter. Partial pickup by that pipette must use a rack directly on the deck,
107without the adapter.

Flex Tip Compatibility

Pipette familyCompatible Flex tip-rack capacities
flex_1channel_50, flex_8channel_5020 µL, 50 µL
flex_96channel_20020 µL, 50 µL, 200 µL
flex_1channel_1000, flex_8channel_1000, flex_96channel_100050 µL, 200 µL, 1000 µL

Filter-tip load names insert _filtertiprack_, for example opentrons_flex_96_filtertiprack_200ul.

Full-rack pickup by a Flex 96-channel pipette requires the Flex tip-rack adapter. Partial pickup by that pipette must use a rack directly on the deck, without the adapter.

Raw lines 94 to 108
109## ProtocolContext

ProtocolContext

Raw lines 109 to 110
111### Hardware and deck
113```python
114labware = protocol.load_labware(load_name, location, label=None)
115adapter = protocol.load_adapter(load_name, location)
116module = protocol.load_module(module_name, location=None)
117pipette = protocol.load_instrument(
118 instrument_name,
119 mount,
120 tip_racks=[tiprack],
122trash = protocol.load_trash_bin("A3") # Flex, API 2.16+
123chute = protocol.load_waste_chute() # Flex, fixed at D3
124```
126Useful methods:
128- `load_labware_from_definition(definition, location, label=None)`
129- `move_labware(labware, new_location, use_gripper=...)`
130- `load_lid_stack(load_name, location, quantity)`
131- `move_lid(source_location, new_location, use_gripper=...)`
132- `define_liquid(name, description=None, display_color=None)`
133- `get_liquid_class(name, version=None)` — API 2.24+
134- `define_liquid_class(name, properties, base_liquid_class=None, display_name=None)` — API 2.24+

Hardware and deck

labware = protocol.load_labware(load_name, location, label=None)
adapter = protocol.load_adapter(load_name, location)
module = protocol.load_module(module_name, location=None)
pipette = protocol.load_instrument(
    instrument_name,
    mount,
    tip_racks=[tiprack],
)
trash = protocol.load_trash_bin("A3")  # Flex, API 2.16+
chute = protocol.load_waste_chute()     # Flex, fixed at D3

Useful methods:

  • load_labware_from_definition(definition, location, label=None)
  • move_labware(labware, new_location, use_gripper=...)
  • load_lid_stack(load_name, location, quantity)
  • move_lid(source_location, new_location, use_gripper=...)
  • define_liquid(name, description=None, display_color=None)
  • get_liquid_class(name, version=None) — API 2.24+
  • define_liquid_class(name, properties, base_liquid_class=None, display_name=None) — API 2.24+
Raw lines 111 to 135
136### Execution and organization
138- `comment(msg)` — adds analysis-time text to the run log.
139- `pause(msg=None)` — waits for the operator to resume in the App/touchscreen.
140- `delay(seconds=0, minutes=0, msg=None)` — blocking delay.
141- `home()` — homes robot axes.
142- `is_simulating()` — identify local or App analysis.
143- `group_steps(name, description=None)` — context manager, API 2.29.
144- `create_and_start_step_group(name, description=None)` — returns a group whose
145 `end_group()` method closes it, API 2.29.
146- `capture_image()` — captures from the built-in camera, API 2.27.
148Step groups only organize source and visualization; they do not change
149execution.

Execution and organization

  • comment(msg) — adds analysis-time text to the run log.
  • pause(msg=None) — waits for the operator to resume in the App/touchscreen.
  • delay(seconds=0, minutes=0, msg=None) — blocking delay.
  • home() — homes robot axes.
  • is_simulating() — identify local or App analysis.
  • group_steps(name, description=None) — context manager, API 2.29.
  • create_and_start_step_group(name, description=None) — returns a group whose end_group() method closes it, API 2.29.
  • capture_image() — captures from the built-in camera, API 2.27.

Step groups only organize source and visualization; they do not change execution.

Raw lines 136 to 150
151## InstrumentContext

InstrumentContext

Raw lines 151 to 152
153### Tips
155```python
156pipette.pick_up_tip()
157pipette.drop_tip()
158pipette.return_tip()
159pipette.reset_tipracks()
160```
162In API 2.28+, `tiprack.set_empty()` can mark a rack empty so returned tips may be
163tracked there. Only return tips when the protocol's contamination policy allows
164it.

Tips

pipette.pick_up_tip()
pipette.drop_tip()
pipette.return_tip()
pipette.reset_tipracks()

In API 2.28+, tiprack.set_empty() can mark a rack empty so returned tips may be tracked there. Only return tips when the protocol's contamination policy allows it.

Raw lines 153 to 165
166### Building-block commands
168```python
169pipette.aspirate(volume, source)
170pipette.dispense(volume, destination, push_out=5)
171pipette.air_gap(volume)
172pipette.blow_out(destination.top())
173pipette.touch_tip(destination)
174pipette.mix(repetitions, volume, destination)
175pipette.move_to(destination.top())
176```
178Use `rate=` as a multiplier of the pipette's configured flow rate, or supported
179absolute flow-rate arguments when the API level provides them. Do not supply
180both forms for the same action.
182API 2.27 adds `end_location` and `movement_delay` to aspirate and dispense, plus
183`dynamic_mix()` for start-to-end movement during repeated aspiration and
184dispensing.

Building-block commands

pipette.aspirate(volume, source)
pipette.dispense(volume, destination, push_out=5)
pipette.air_gap(volume)
pipette.blow_out(destination.top())
pipette.touch_tip(destination)
pipette.mix(repetitions, volume, destination)
pipette.move_to(destination.top())

Use rate= as a multiplier of the pipette's configured flow rate, or supported absolute flow-rate arguments when the API level provides them. Do not supply both forms for the same action.

API 2.27 adds end_location and movement_delay to aspirate and dispense, plus dynamic_mix() for start-to-end movement during repeated aspiration and dispensing.

Raw lines 166 to 185
186### Complex commands
188```python
189pipette.transfer(volume, source, destination, new_tip="always")
190pipette.distribute(volume, source, destinations, new_tip="once")
191pipette.consolidate(volume, sources, destination, new_tip="always")
192```
194Common options include:
196- `new_tip`: `"always"`, `"once"`, or `"never"`; newer API levels add
197 additional policies for some commands.
198- `mix_before=(repetitions, volume)`
199- `mix_after=(repetitions, volume)`
200- `touch_tip=True`
201- `blow_out=True`
202- `blowout_location=...`
203- `disposal_volume=...`
204- `trash_location=...`
206Supported options differ by command and API level. Check the exact signature in
207the
208[Instrument API reference](https://docs.opentrons.com/python-api/reference/instruments/)
209before using uncommon options.

Complex commands

pipette.transfer(volume, source, destination, new_tip="always")
pipette.distribute(volume, source, destinations, new_tip="once")
pipette.consolidate(volume, sources, destination, new_tip="always")

Common options include:

  • new_tip: "always", "once", or "never"; newer API levels add additional policies for some commands.
  • mix_before=(repetitions, volume)
  • mix_after=(repetitions, volume)
  • touch_tip=True
  • blow_out=True
  • blowout_location=...
  • disposal_volume=...
  • trash_location=...

Supported options differ by command and API level. Check the exact signature in the Instrument API reference before using uncommon options.

Raw lines 186 to 210
211### Liquid-class commands, Flex only
213```python
214water = protocol.get_liquid_class("water")
216pipette.transfer_with_liquid_class(
217 liquid_class=water,
218 volume=50,
219 source=reservoir["A1"],
220 dest=plate["A1"],
221 new_tip="always",
222 trash_location=trash,
224```
226Related methods are `distribute_with_liquid_class()` and
227`consolidate_with_liquid_class()`. Opentrons-verified classes include water,
22880% ethanol, and 50% glycerol. Compatibility depends on the exact Flex pipette
229and tip combination. Omitted `version` selects the latest class for the declared
230API level; record and pin a qualified class version for assay reproducibility.

Liquid-class commands, Flex only

water = protocol.get_liquid_class("water")

pipette.transfer_with_liquid_class(
    liquid_class=water,
    volume=50,
    source=reservoir["A1"],
    dest=plate["A1"],
    new_tip="always",
    trash_location=trash,
)

Related methods are distribute_with_liquid_class() and consolidate_with_liquid_class(). Opentrons-verified classes include water, 80% ethanol, and 50% glycerol. Compatibility depends on the exact Flex pipette and tip combination. Omitted version selects the latest class for the declared API level; record and pin a qualified class version for assay reproducibility.

Raw lines 211 to 231
232## Labware and Wells

Labware and Wells

Raw lines 232 to 233
234### Accessors
236```python
237plate["A1"]
238plate.wells()
239plate.wells_by_name()
240plate.rows()
241plate.rows_by_name()
242plate.columns()
243plate.columns_by_name()
244```
246Labware iteration is generally column-major. Use named wells or explicit lists
247when order is safety-critical.

Accessors

plate["A1"]
plate.wells()
plate.wells_by_name()
plate.rows()
plate.rows_by_name()
plate.columns()
plate.columns_by_name()

Labware iteration is generally column-major. Use named wells or explicit lists when order is safety-critical.

Raw lines 234 to 248
249### Locations
251```python
252well.top(z=-1)
253well.bottom(z=2)
254well.center()
255well.meniscus(z=0, target="start") # API 2.23+
256```
258`meniscus()` depends on declared or measured liquid volume. Start-only aspiration
259without `end_location` requires API 2.30; at 2.29 and lower use the documented
260end-target or start-to-end pattern. Validate liquid
261height behavior on hardware before relying on it for low-volume aspiration.

Locations

well.top(z=-1)
well.bottom(z=2)
well.center()
well.meniscus(z=0, target="start")  # API 2.23+

meniscus() depends on declared or measured liquid volume. Start-only aspiration without end_location requires API 2.30; at 2.29 and lower use the documented end-target or start-to-end pattern. Validate liquid height behavior on hardware before relying on it for low-volume aspiration.

Raw lines 249 to 262
263### Liquid setup visualization, API 2.22+
265```python
266buffer = protocol.define_liquid(
267 name="Buffer",
268 description="Assay buffer",
269 display_color="#1F77B4",
272reservoir.load_liquid(
273 wells=["A1"],
274 volume=10_000,
275 liquid=buffer,
278plate.load_liquid_by_well(
279 volumes={"A1": 50, "B1": 50},
280 liquid=buffer,
283plate.load_empty(wells=["A2", "B2"])
284```
286`Well.load_liquid()` is deprecated for API 2.22+ protocols.

Liquid setup visualization, API 2.22+

buffer = protocol.define_liquid(
    name="Buffer",
    description="Assay buffer",
    display_color="#1F77B4",
)

reservoir.load_liquid(
    wells=["A1"],
    volume=10_000,
    liquid=buffer,
)

plate.load_liquid_by_well(
    volumes={"A1": 50, "B1": 50},
    liquid=buffer,
)

plate.load_empty(wells=["A2", "B2"])

Well.load_liquid() is deprecated for API 2.22+ protocols.

Raw lines 263 to 287
288## Runtime Parameters
290Define parameters outside `run()`:
292```python
293def add_parameters(parameters: protocol_api.ParameterContext) -> None:
294 parameters.add_int(
295 variable_name="sample_count",
296 display_name="Sample count",
297 default=8,
298 minimum=1,
299 maximum=96,
300 )
301 parameters.add_bool(
302 variable_name="dry_run",
303 display_name="Dry run",
304 default=False,
305 )
306```
308Read them during execution:
310```python
311sample_count = protocol.params.sample_count
312dry_run = protocol.params.dry_run
313```
315Methods:
317- `add_bool(...)`
318- `add_int(...)`
319- `add_float(...)`
320- `add_str(...)`
321- `add_csv_file(...)` — API 2.20+, no default, at most one CSV parameter per
322 run.
324Parameter display names are limited to 30 characters and descriptions to 100
325characters. Numeric parameters require either a min/max range or fixed choices.

Runtime Parameters

Define parameters outside run():

def add_parameters(parameters: protocol_api.ParameterContext) -> None:
    parameters.add_int(
        variable_name="sample_count",
        display_name="Sample count",
        default=8,
        minimum=1,
        maximum=96,
    )
    parameters.add_bool(
        variable_name="dry_run",
        display_name="Dry run",
        default=False,
    )

Read them during execution:

sample_count = protocol.params.sample_count
dry_run = protocol.params.dry_run

Methods:

  • add_bool(...)
  • add_int(...)
  • add_float(...)
  • add_str(...)
  • add_csv_file(...) — API 2.20+, no default, at most one CSV parameter per run.

Parameter display names are limited to 30 characters and descriptions to 100 characters. Numeric parameters require either a min/max range or fixed choices.

Raw lines 288 to 326
327## Liquid Presence and Height
329Flex pressure-sensing pipettes support:
331- `detect_liquid_presence(well)`
332- `require_liquid_presence(well)`
333- `measure_liquid_height(well)`
334- `liquid_presence_detection=True` in `load_instrument()`
335- Runtime toggling with `pipette.liquid_presence_detection`
337Detection requires a fresh, dry, empty tip for each check. Global detection plus
338a complex command may reuse a wet tip on a refill: use explicit building blocks
339with a fresh pickup immediately before each checked aspiration. It can add substantial run time,
340and not every channel on a multi-channel pipette contains a pressure sensor.

Liquid Presence and Height

Flex pressure-sensing pipettes support:

  • detect_liquid_presence(well)
  • require_liquid_presence(well)
  • measure_liquid_height(well)
  • liquid_presence_detection=True in load_instrument()
  • Runtime toggling with pipette.liquid_presence_detection

Detection requires a fresh, dry, empty tip for each check. Global detection plus a complex command may reuse a wet tip on a refill: use explicit building blocks with a fresh pickup immediately before each checked aspiration. It can add substantial run time, and not every channel on a multi-channel pipette contains a pressure sensor.

Raw lines 327 to 341
342## Partial Nozzle Layouts
344```python
345from opentrons.protocol_api import ALL, COLUMN
347pipette.configure_nozzle_layout(
348 style=COLUMN,
349 start="A12",
350 tip_racks=[partial_tip_rack],
353# Restore full-rack pickup later.
354pipette.configure_nozzle_layout(
355 style=ALL,
356 tip_racks=[full_tip_rack],
358```
360Available constants include `ALL`, `COLUMN`, `ROW`, `SINGLE`, and
361`PARTIAL_COLUMN`, subject to pipette and API support. An incorrect target well
362can place nozzles outside the labware and cause a physical crash. Follow the
363deck-edge and tip-rack-adapter rules in
364[Partial Tip Pickup](https://docs.opentrons.com/python-api/pipettes/partial-tip-pickup/).

Partial Nozzle Layouts

from opentrons.protocol_api import ALL, COLUMN

pipette.configure_nozzle_layout(
    style=COLUMN,
    start="A12",
    tip_racks=[partial_tip_rack],
)

# Restore full-rack pickup later.
pipette.configure_nozzle_layout(
    style=ALL,
    tip_racks=[full_tip_rack],
)

Available constants include ALL, COLUMN, ROW, SINGLE, and PARTIAL_COLUMN, subject to pipette and API support. An incorrect target well can place nozzles outside the labware and cause a physical crash. Follow the deck-edge and tip-rack-adapter rules in Partial Tip Pickup.

Raw lines 342 to 365
366## Module Load Names
368| Module | Load name | Minimum API |
369| --- | --- | ---: |
370| Temperature Module GEN1 | `temperature module` | 2.0 |
371| Temperature Module GEN2 | `temperature module gen2` | 2.3 |
372| Thermocycler GEN1 | `thermocycler module` | 2.0 |
373| Thermocycler GEN2 | `thermocyclerModuleV2` | 2.13 |
374| Heater-Shaker GEN1 | `heaterShakerModuleV1` | 2.13 |
375| Magnetic Block GEN1 | `magneticBlockV1` | 2.15 |
376| Absorbance Plate Reader | `absorbanceReaderV1` | 2.21 |
377| Flex Stacker | `flexStackerModuleV1` | 2.25 |
379Module availability also depends on robot model and physical generation. See
380`modules_and_deck.md` before choosing a load name.

Module Load Names

ModuleLoad nameMinimum API
Temperature Module GEN1temperature module2.0
Temperature Module GEN2temperature module gen22.3
Thermocycler GEN1thermocycler module2.0
Thermocycler GEN2thermocyclerModuleV22.13
Heater-Shaker GEN1heaterShakerModuleV12.13
Magnetic Block GEN1magneticBlockV12.15
Absorbance Plate ReaderabsorbanceReaderV12.21
Flex StackerflexStackerModuleV12.25

Module availability also depends on robot model and physical generation. See modules_and_deck.md before choosing a load name.

Raw lines 366 to 381
382## Simulation Entrypoints
384```bash
385# Flex API 2.29
386uv run --no-project --isolated --python 3.12 --with "opentrons==10.0.0" opentrons_simulate protocol.py
388# OT-2 API 2.28 compatibility simulation
389uv run --no-project --isolated --python 3.12 --with "opentrons==9.0.0" opentrons_simulate protocol.py
390```
392Python integrations may use `opentrons.simulate.simulate()` with an opened
393protocol file. `opentrons==10.0.0` rejects OT-2 protocols after the release-line
394split, so complete OT-2 validation in the current OT-2 App. Do not use
395`opentrons_execute` from a workstation as a substitute for App analysis and
396controlled robot operation.

Simulation Entrypoints

# Flex API 2.29
uv run --no-project --isolated --python 3.12 --with "opentrons==10.0.0" opentrons_simulate protocol.py

# OT-2 API 2.28 compatibility simulation
uv run --no-project --isolated --python 3.12 --with "opentrons==9.0.0" opentrons_simulate protocol.py

Python integrations may use opentrons.simulate.simulate() with an opened protocol file. opentrons==10.0.0 rejects OT-2 protocols after the release-line split, so complete OT-2 validation in the current OT-2 App. Do not use opentrons_execute from a workstation as a substitute for App analysis and controlled robot operation.

Raw lines 382 to 396