Skip to main content

protocol-verification

Simulate and analyze Opentrons protocols to verify correctness. Use when asked to verify, simulate, analyze, validate, or check a protocol, or when needing to confirm a newly created protocol works.

Source facts

Repository
Opentrons/opentrons
Last source activity
September 16, 2026 at 15:01
Detected SKILL.md language
English
Stars
520
Forks
208

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
protocol-verification
description
Simulate and analyze Opentrons protocols to verify correctness. Use when asked to verify, simulate, analyze, validate, or check a protocol, or when needing to confirm a newly created protocol works.
# Protocol Verification — Simulate & Analyze After creating or modifying a protocol, verify it using the binaries in `api/.venv/bin/`. All commands run from the **monorepo root**. ## Prerequisites The `api/` venv must exist. If it doesn't (first time, or after teardown): ```bash make -C api setup ``` This creates `api/.venv/` with all entry points installed. You only need to do this once. ### OT-2 protocols (outside this repository's `api/.venv`) OT-2 robot software and the Python API live in a **separate fork** ([opentrons-ot2](https://github.com/Opentrons/opentrons-ot2)). This monorepo's `api/` package (and `api/.venv`) is **Flex-only**: `opentrons analyze` and `opentrons_simulate` **reject OT-2 protocols**. The same split applies on PyPI: **`opentrons==9.0.0` is the last release where one package could analyze or simulate both OT-2 and Flex.** That wheel supports **Python API through 2.28** (the last apiLevel shared across both robots before the fork). **`opentrons` 9.1+ analyzes Flex only**; use the OT-2 fork / OT-2 app stack for OT-2 protocols at 2.28 or below. For mixed OT-2/Flex reference checks at apiLevel 2.28, create a **separate** Python 3.12 venv (do not commit it): ```bash uv venv /path/to/opentrons-9.0-venv --python 3.12 uv pip install --python /path/to/opentrons-9.0-venv/bin/python 'opentrons==9.0.0' /path/to/opentrons-9.0-venv/bin/python -m opentrons.cli analyze tmp-protocols/my_protocol.py --check --json-output=- /path/to/opentrons-9.0-venv/bin/opentrons_simulate tmp-protocols/my_protocol.py ``` Flex-only checks use `api/.venv/bin/...` from this monorepo (or current PyPI `opentrons` for Flex). ## Entry Points | Tool | Binary | Notes | | ------------------------------------------ | ------------------------------------------------- | --------------------------------------------------- | | Simulate | `api/.venv/bin/opentrons_simulate` | Flex dev tree; OT-2 rejected | | Analyze | `api/.venv/bin/python -m opentrons.cli analyze` | Flex dev tree; OT-2 rejected | | Simulate / analyze (OT-2 or mixed @ ≤2.28) | Separate venv with `opentrons==9.0.0` (see above) | Last unified PyPI release; not monorepo `api/.venv` | > **Do not use `uv run`** for one-off simulate/analyze calls. It checks and potentially rebuilds the venv on every invocation, adding significant latency. Call the venv binaries directly. ## Working Directories All local dev artifacts are gitignored and live at the monorepo root: | Directory | Purpose | | --------------------- | ---------------------------------- | | `tmp-protocols/` | Protocol `.py` files | | `tmp-custom-labware/` | Custom labware `.json` definitions | | `tmp-csv/` | CSV files for RTP inputs | ## Simulation Produces a **human-readable runlog** of every command the robot would execute. Use for quick validation. > **⛔ RTP protocols cannot be simulated.** `opentrons_simulate` has no `--rtp-values` or `--rtp-files` flag. If the protocol defines `add_parameters()` (any RTP — including CSV, int, bool, str, or float), **you must tell the user this upfront and use `opentrons analyze` instead.** Do not attempt to simulate an RTP protocol and let it fail; explain the limitation first, then switch to analyze automatically. ```bash # Standard api/.venv/bin/opentrons_simulate tmp-protocols/my_protocol.py # With custom labware (can be specified multiple times) api/.venv/bin/opentrons_simulate tmp-protocols/my_protocol.py \ -L tmp-custom-labware/ ``` The current working directory is **always** searched for custom labware implicitly. ### Simulation Options | Flag | Description | | ----------------------------- | ----------------------------------------------------- | | `-l`, `--log-level` | `debug`, `info`, `warning` (default), `error`, `none` | | `-L`, `--custom-labware-path` | Directory to search for custom labware (repeatable) | | `-e`, `--estimate-duration` | Estimate protocol run time (experimental) | | `-o`, `--output` | `runlog` (default) or `nothing` | ### Interpreting Results - **Success**: runlog prints, exit code 0 - **Failure**: Python traceback with error message, exit code 1 Common errors: - `DeckConflictError` — labware placement conflict - `LabwareDefinitionDoesNotExist` — invalid labware name - `OutOfTipsError` — not enough tips for the protocol - `LiquidHeightUnknownError` — `.meniscus()` called on a well without `load_liquid()` — see `reference-source-map.md` - `IncompatibleAddressableAreaError` — wrong slot for robot type ## Analysis Produces **structured JSON** with predicted commands, labware layout, pipettes, modules, and errors. Use for deep inspection or CI validation. Also the only way to verify protocols with CSV RTPs. ```bash # Standard api/.venv/bin/python -m opentrons.cli analyze tmp-protocols/my_protocol.py \ --check --human-json-output=- # With custom labware — pass the JSON file(s) as extra positional arguments api/.venv/bin/python -m opentrons.cli analyze \ tmp-protocols/my_protocol.py \ tmp-custom-labware/my_custom_plate.json \ --check --json-output=- # With primitive RTP values (int, float, bool, str) api/.venv/bin/python -m opentrons.cli analyze tmp-protocols/my_protocol.py \ --check --json-output=- \ --rtp-values='{"sample_count": 8, "dry_run": false}' # With CSV RTP file api/.venv/bin/python -m opentrons.cli analyze tmp-protocols/my_protocol.py \ --check --json-output=- \ --rtp-files='{"transfer_map": "tmp-csv/transfer_map.csv"}' # Combined: custom labware + CSV RTP api/.venv/bin/python -m opentrons.cli analyze \ tmp-protocols/my_protocol.py \ tmp-custom-labware/my_custom_plate.json \ --check --json-output=- \ --rtp-files='{"transfer_map": "tmp-csv/transfer_map.csv"}' ``` ### Analysis Options | Flag | Description | | -------------------------- | ------------------------------------------------------------------- | | `--json-output=FILE` | Machine-readable JSON (`-` for stdout) | | `--human-json-output=FILE` | Pretty-printed JSON (`-` for stdout) | | `--check` | Exit non-zero if protocol has errors | | `--rtp-values=JSON` | Primitive RTP values as JSON string (`int`, `float`, `bool`, `str`) | | `--rtp-files=JSON` | CSV RTP file paths as JSON string — keys are `variable_name`s | | `--log-output=PATH` | Log destination (`-` stdout, `stderr` default, or file path) | | `--log-level` | `DEBUG`, `INFO`, `WARNING` (default), `ERROR` | > **Custom labware in analyze**: there is no `-L` flag. Pass each labware JSON as an extra positional file argument. The `analyze` command recognizes them by their JSON schema and registers them before running. ### JSON Output Structure ```json { "createdAt": "...", "result": "ok", "robotType": "OT-3", "config": {"protocolType": "python", "apiVersion": [2, 28]}, "metadata": {"protocolName": "..."}, "commands": [...], "labware": [...], "pipettes": [...], "modules": [...], "liquids": [...], "errors": [], "runTimeParameters": [...] } ``` Key fields: `result` (`"ok"` / `"not-ok"` / `"parameter-value-required"`), `errors` (empty = valid), `commands` (full ordered command list). ### With Runtime Parameters ```bash api/.venv/bin/python -m opentrons.cli analyze protocol.py \ --check --json-output=output.json \ --rtp-values='{"sample_count": 48, "dry_run": false}' # CSV parameter files api/.venv/bin/python -m opentrons.cli analyze protocol.py \ --check --json-output=output.json \ --rtp-files='{"plate_map": "/path/to/map.csv"}' ``` ## Standard Verification Workflow **Before running anything**, check whether the protocol defines `add_parameters()`. If it does, skip simulate entirely and go straight to analyze — then tell the user why. ```bash # 1. Quick check — simulate (only if protocol has NO add_parameters()) api/.venv/bin/opentrons_simulate tmp-protocols/my_protocol.py # 1b. Quick check — simulate with custom labware (still no RTPs) api/.venv/bin/opentrons_simulate tmp-protocols/my_protocol.py \ -L tmp-custom-labware/ # 2. Deep check — analyze (required for any protocol with add_parameters()) api/.venv/bin/python -m opentrons.cli analyze \ tmp-protocols/my_protocol.py \ [tmp-custom-labware/my_plate.json] \ --check --human-json-output=- \ [--rtp-values='{"key": value}'] \ [--rtp-files='{"csv_param": "tmp-csv/file.csv"}'] ``` **Decision guide:** | Scenario | Use | Agent behavior |
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub