opentrons-protocol-api
Python API v2 for Opentrons OT-2/Flex liquid handlers: protocols as Python files with metadata and run(); control pipettes, labware, and modules (thermocycler, heater-shaker, magnetic, temperature). Simulate via opentrons_simulate then upload.
Install / Use
npx skills add jaechang-hits/SciAgent-Skills --skill opentrons-protocol-apiInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
Development & EngineeringSupported Platforms
Our assessment of opentrons-protocol-api
opentrons-protocol-api scores 91/100 on our quality scale, 1166th of 4,619 Development & Engineering skills we index (top 26%).
Its SKILL.md is 30 KB long, well organised into 28 sections with 18 code examples: a thorough specification that gives an agent plenty to work with.
It has 367 GitHub stars, a meaningful sign that others use it.
Maintenance, license and trust
- The repository was last updated 37 days ago, so opentrons-protocol-api is actively maintained.
- No license is declared. By default that means all rights are reserved: you can read it, but reusing or redistributing it is not clearly permitted. Ask the author before building on it commercially.
- Its trust signals score 88/100, with 1 caution from licensing, adoption, age or documentation. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
Safety scan
No issues foundOur scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands.
Automated pattern scan on 2026-10-05. It catches known dangerous patterns, not every risk — read a skill before letting an agent act on it.
opentrons-protocol-api compared with similar skills
All 4 of these similar skills score higher than opentrons-protocol-api; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| opentrons-protocol-api (this skill)by jaechang-hits | 91 | 367 | 37d ago | SKILL.md |
| Agent-Reachby Panniantong | 100 | 90.8k | 19d ago | CLAUDE.md |
| headroomby headroomlabs-ai | 100 | 74.4k | today | CLAUDE.md |
| ai-job-searchby MadsLorentzen | 100 | 45.0k | 1d ago | CLAUDE.md |
| claude-howtoby luongnv89 | 100 | 41.7k | 4d ago | CLAUDE.md |
Frequently asked questions
- How do I install opentrons-protocol-api?
- Run
npx skills add jaechang-hits/SciAgent-Skills --skill opentrons-protocol-api. The install tabs above show the steps for each supported agent. - Which AI agents does opentrons-protocol-api work with?
- It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is opentrons-protocol-api safe to use?
- Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. It declares no license and scores 88/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is opentrons-protocol-api still maintained?
- The repository was last updated 37 days ago, so opentrons-protocol-api is actively maintained.
Skill content
View source on GitHubname: "opentrons-protocol-api" description: "Python API v2 for Opentrons OT-2/Flex liquid handlers: protocols as Python files with metadata and run(); control pipettes, labware, and modules (thermocycler, heater-shaker, magnetic, temperature). Simulate via opentrons_simulate then upload. Use PyLabRobot for vendor-agnostic scripts (Hamilton, Tecan)." license: "Apache-2.0"
Opentrons Python Protocol API
Overview
The Opentrons Protocol API v2 lets you write liquid handling protocols as plain Python files that run on OT-2 or Flex robots. Every protocol defines a metadata dictionary, an optional requirements dictionary, and a run(protocol) function. The ProtocolContext object passed to run() exposes all deck setup, pipette operations, module control, and utility methods. Protocols can be simulated on any computer with opentrons_simulate before uploading to the robot through the Opentrons App or HTTP API.
When to Use
- Setting up PCR reactions: Distribute master mix from a tube rack into a thermocycler plate, add template DNA from individual tubes, then execute a PCR profile automatically.
- Running serial dilutions: Programmatically step a multi-channel pipette across a 96-well plate to create 2-fold or custom dilution curves with defined diluent volumes.
- Performing ELISA plate layouts: Add blocking buffer, primary antibody, secondary antibody, and substrate to defined wells with tip changes between each reagent.
- Automating magnetic bead cleanups: Engage/disengage the magnetic module, aspirate supernatant, wash with ethanol, and elute — in a fully automated loop.
- Plate reformatting and stamping: Transfer an entire 96-well plate to a destination plate with one command; reformat from tubes to plates.
- Integrating hardware modules: Coordinate temperature control, shaking, and liquid handling steps in a single protocol with precise timing.
- Use
PyLabRobotinstead when writing protocols that must run on Hamilton STAR, Tecan Freedom EVO, or other vendors without Opentrons-specific hardware; for Opentrons-only workflows the native Protocol API provides tighter integration and module support. - For retrieving and parsing published protocols before automation, use
protocolsio-integrationto search protocols.io alongside this skill.
Prerequisites
- Python packages:
opentrons - Robot types: OT-2 (slots 1-11, Gen2 pipettes) or Flex (slots A1-D3, Flex pipettes)
- Environment: Python 3.10+; Opentrons App for uploading to physical robot
- CLI tool:
opentrons_simulateships with the package for local testing
pip install opentrons
# Verify installation and simulate a protocol locally
opentrons_simulate my_protocol.py
Quick Start
A minimal protocol showing all required elements — metadata, labware, instrument, and a transfer:
from opentrons import protocol_api
metadata = {
"protocolName": "Simple Reagent Distribution",
"author": "Lab Automation Team",
"apiLevel": "2.19",
}
def run(protocol: protocol_api.ProtocolContext):
# Load labware onto deck slots
tips = protocol.load_labware("opentrons_96_tiprack_300ul", "1")
source = protocol.load_labware("nest_12_reservoir_15ml", "2")
plate = protocol.load_labware("corning_96_wellplate_360ul_flat", "3")
# Load pipette and attach tip rack
pipette = protocol.load_instrument("p300_single_gen2", "left", tip_racks=[tips])
# Distribute 50 µL from reservoir A1 to first 12 wells using one tip
pipette.distribute(50, source["A1"], plate.wells()[:12], new_tip="once")
protocol.comment("Distribution complete")
# Simulate locally — no robot needed
opentrons_simulate simple_reagent_distribution.py
Core API
Module 1: Protocol Metadata and Deck Setup
Every protocol requires a metadata dict specifying at minimum apiLevel. The optional requirements dict sets the target robot type. All labware and instruments are loaded through the ProtocolContext.
from opentrons import protocol_api
# Minimum required metadata
metadata = {
"protocolName": "My Assay Protocol",
"author": "Jane Smith <jane@lab.org>",
"description": "96-well assay setup with temperature control",
"apiLevel": "2.19",
}
# Optional: target a specific robot type (Flex or OT-2)
requirements = {"robotType": "OT-2", "apiLevel": "2.19"}
def run(protocol: protocol_api.ProtocolContext):
# OT-2: slots numbered 1-11 in a 3×4 grid
tips_300 = protocol.load_labware("opentrons_96_tiprack_300ul", "1")
tips_20 = protocol.load_labware("opentrons_96_tiprack_20ul", "4")
source = protocol.load_labware("nest_12_reservoir_15ml", "2", label="Buffer Reservoir")
plate = protocol.load_labware("corning_96_wellplate_360ul_flat", "3")
tube_rack = protocol.load_labware("opentrons_24_tuberack_nest_1.5ml_snapcap", "5")
# Load both pipettes (optional: one or two mounts)
p300 = protocol.load_instrument("p300_single_gen2", "left", tip_racks=[tips_300])
p20 = protocol.load_instrument("p20_single_gen2", "right", tip_racks=[tips_20])
print(f"Deck has {len(protocol.deck)} slots; pipettes: {[p300.name, p20.name]}")
OT-2 deck layout (3 columns × 4 rows, numbered left-to-right, bottom-to-top):
Slot map (OT-2): Slot map (Flex, A-D rows, 1-3 cols):
10 | 11 | Trash D1 | D2 | D3
7 | 8 | 9 C1 | C2 | C3
4 | 5 | 6 B1 | B2 | B3
1 | 2 | 3 A1 | A2 | A3
Common OT-2 pipette names: p20_single_gen2, p300_single_gen2, p1000_single_gen2, p20_multi_gen2, p300_multi_gen2.
Common Flex pipette names: p50_single_flex, p1000_single_flex, p50_multi_flex, p1000_multi_flex, flex_96channel_1000.
Module 2: Pipette Operations
Low-level aspirate/dispense/blow-out operations for precise step-by-step control.
def run(protocol: protocol_api.ProtocolContext):
tips = protocol.load_labware("opentrons_96_tiprack_300ul", "1")
source = protocol.load_labware("nest_12_reservoir_15ml", "2")
dest = protocol.load_labware("corning_96_wellplate_360ul_flat", "3")
p300 = protocol.load_instrument("p300_single_gen2", "left", tip_racks=[tips])
p300.pick_up_tip()
# Aspirate and dispense — basic liquid movement
p300.aspirate(100, source["A1"]) # draw 100 µL from reservoir
p300.dispense(100, dest["A1"]) # expel into plate well
# Air gap to prevent dripping during transport
p300.aspirate(80, source["A2"])
p300.air_gap(20) # draw 20 µL air to cap the tip
p300.dispense(100, dest["A2"]) # dispenses liquid + air
# Mix in place (repetitions, volume)
p300.mix(3, 60, dest["A1"]) # mix 60 µL × 3 times
# Remove exterior droplets / expel residual
p300.touch_tip(dest["A1"]) # wipe tip on well rim
p300.blow_out(dest["A1"].top()) # expel last drop at top
p300.drop_tip()
protocol.comment("Low-level operations complete")
def run(protocol: protocol_api.ProtocolContext):
tips = protocol.load_labware("opentrons_96_tiprack_300ul", "1")
p300 = protocol.load_instrument("p300_single_gen2", "left", tip_racks=[tips])
# Adjust flow rates (µL/s) for viscous or sensitive samples
p300.flow_rate.aspirate = 50 # slow down for viscous liquids (default ~150)
p300.flow_rate.dispense = 150 # default dispense speed
p300.flow_rate.blow_out = 300 # fast blow-out for complete expulsion
print(f"Aspirate rate: {p300.flow_rate.aspirate} µL/s")
Module 3: transfer() Shortcut
transfer(), distribute(), and consolidate() handle tip management automatically and accept mix, blow-out, and air-gap options.
def run(protocol: protocol_api.ProtocolContext):
tips = protocol.load_labware("opentrons_96_tiprack_300ul", "1")
source = protocol.load_labware("corning_96_wellplate_360ul_flat", "2")
dest = protocol.load_labware("corning_96_wellplate_360ul_flat", "3")
p300 = protocol.load_instrument("p300_single_gen2", "left", tip_racks=[tips])
# transfer(): one source → one destination, with optional per-well tip changes
p300.transfer(
100,
source["A1"],
dest["A1"],
new_tip="always", # options: "always", "once", "never"
mix_after=(3, 50), # mix 50 µL × 3 reps after each dispense
blow_out=True,
touch_tip=True,
)
# transfer() with lists: pairwise source-destination mapping
sources = source.wells()[:8]
dests = dest.wells()[:8]
p300.transfer(75, sources, dests, new_tip="always")
# distribute(): one source → many destinations (single tip, multi-dispense)
p300.distribute(
50,
source["A1"],
dest.wells()[:12],
new_tip="once", # use one tip for all destinations
disposal_volume=10, # extra volume drawn to ensure accuracy
)
# consolidate(): many sources → one destination (collect, then dispense)
p300.consolidate(
50,
source.wells()[:8],
dest["A1"],
mix_after=(3, 100),
)
print("Compound transfer operations complete")
Module 4: Labware, Liquids, and Well Access
Load labware from the library, navigate wells by name/row/column, and define liquids for visual tracking in the Opentrons App.
def run(protocol: protocol_api.ProtocolContext):
plate = protocol.load_labware("corning_96_wellplate_360ul_flat", "1")
p300 = protocol.load_instrument("p300_single_gen2", "left",
tip_racks=[protocol.load_labware("opentrons_96_tiprack_300ul", "2")])
# Access wells by alphanumeric name
well_a1 = plate["A1"]
# Access all wells (column-major order: A1, B1, C1, ..., H1, A2, ...)
all_wells = plate.wells()
print(f"Total wells: {len(all_wells)}") # 96
# Access by row (8 rows, A-H; each row has 12 wells)
row_a = plate.rows()[0] # [A1, A2, ..., A12]
row_b = plate.rows()[1] # [B1, B2, ..., B12]
# Access by column (12 columns, 1-12; each column has 8 wells)
col_1 = plate.columns()[0] # [A1, B1, C1, D1, E1, F1, G1, H1]
# Vertical position control within a well
p300.pick_up_tip()
p300.aspirate(80, well_a1.bottom(z=1)) # 1 mm above well bottom
p300.dispense(80, well_a1.top(z=-2)) # 2 mm below well top
p300.aspirate(80, well_a1.center()) # geometric center
p300.drop_tip()
def run(protocol: protocol_api.ProtocolContext):
reservoir = protocol.load_labware("nest_12_reservoir_15ml", "1")
plate = protocol.load_labware("corning_96_wellplate_360ul_flat", "2")
# Define liquids for visual tracking in Opentrons App
pbs = protocol.define_liquid(name="1× PBS", description="Phosphate buffered saline", display_color="#0077BB")
sample = protocol.define_liquid(name="Sample", description="Cell lysate, 1 mg/mL protein", display_color="#EE7733")
# Assign liquids to wells with known starting volumes (µL)
reservoir["A1"].load_liquid(liquid=pbs, volume=10000)
reservoir["A2"].load_liquid(liquid=sample, volume=5000)
# Mark destination wells as empty
for well in plate.wells():
well.load_empty()
print("Liquids defined and assigned")
Module 5: Hardware Modules
Control temperature, magnetic, thermocycler, and heater-shaker modules. Each module is loaded by its model name string and occupies specific deck slots.
def run(protocol: protocol_api.ProtocolContext):
# --- Temperature Module (Gen2) ---
temp_mod = protocol.load_module("temperature module gen2", "3")
temp_plate = temp_mod.load_labware("corning_96_wellplate_360ul_flat")
temp_mod.set_temperature(celsius=4) # blocks until target reached
print(f"Temp module: {temp_mod.temperature}°C")
# temp_mod.deactiva
Truncated for display — read the full file on GitHub.
Related Skills
Agent-Reach
90.8kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
headroom
74.4kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
ai-job-search
45.0kThe job search that runs on your machine. AI job application framework built on Claude Code: evaluate postings, tailor CVs, write cover letters, prep interviews. Fork it and own it.
claude-howto
41.7kA visual, example-driven guide to Claude Code — from basic concepts to advanced agents, with copy-paste templates that bring immediate value.
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
