A 72 h screen leaves no room for manual hand-offs
Chained timing windows
Cells must follow the compound within 60 min. By hand the compound step alone takes about 98 min in my model.
One layout, many files
The plate map, worklist and three protocols must agree on every well.
Faults with no one watching
Shortages, a dropped plate or a wrong barcode become silent deviations in the data.
One spec drives the whole run
Example assay: 384-well spheroid plate, 20 compounds × 5 doses × 3 replicates, 84 controls, CellTiter-Glo 3D readout.
Spec
One YAML file: compounds, doses, volumes, timing.
Validate
Coded checks on DMSO, volumes, tips, reservoirs and time windows.
Build
Plate map, iDOT worklist and three Flex protocols, simulator-checked.
Execute
Timed steps, logged plate custody, coded fault recovery.
Incubate
72 h ± 2 h. State is saved; the process can exit.
Package
Data, run record and AnIML, with a SHA-256 manifest that is checked on write.
Instruments in the workflow
Orchestrator (sequence, record, fault decisions) · iDOT (30 nL per well, 20 nL minimum) · Opentrons Flex (dilutions, media, cells, reagent) · robot arm (logged plate transfers) · incubator and centrifuge · plate reader (luminescence, barcode check).
Dose-response design
Every compound well receives the same 30 nL. The gradient comes from five stock concentrations made by 1:4 serial dilution on the prep plate, one source well per point.
| Point | Stock (µM) | iDOT volume (nL) | Final in well (µM) | DMSO (%) |
|---|---|---|---|---|
| 1 | 13,333 | 30 | 10 | 0.075 |
| 2 | 3,333 | 30 | 2.5 | 0.075 |
| 3 | 833 | 30 | 0.625 | 0.075 |
| 4 | 208 | 30 | 0.156 | 0.075 |
| 5 | 52.1 | 30 | 0.0391 | 0.075 |
| Negative control (solvent) | DMSO only | 30 | 0 | 0.075 |
| Positive control (kill) | 13,333 | 30 | 10 | 0.075 |
Volume per well = final concentration × assay volume ÷ stock. It must stay between the 20 nL iDOT minimum and the DMSO ceiling. It varies by point only when the stock factor differs from the final factor (specs/example_variable_volume.yaml).
Tested against fifteen ways a run can go wrong
All 15 failure scenarios and their outcomes
| Scenario | What happens | Outcome | Codes in the record |
|---|
Hands-on time falls by about 70%
| Measure | Fully by hand | With the system (simulated run) |
|---|---|---|
| Hands-on time per plate | 5.6 h | 1.7 h |
| Compound to cells (window 60 min) | 98 min, window missed | 16.4 min predicted |
| Reagent lag (window 15 min) | 11.2 min | 14.1 min predicted |
| Fit for automation | 86%, rated strong (nine-factor score) | |
| Payback at 4 plates/week | Flex and iDOT: 1.9 years. Full system with arm: 3.6 years. | |
Definitions and sensitivity
Timings and costs are model estimates; 42 inputs are placeholders until measured. Compound to cells is the longest wait from the end of iDOT dosing to the cells landing in any well. Reagent lag is the first-to-last-well delay. The Flex is slower than an 8-channel pipette by hand here, but both sit inside the 15 min window. Payback depends on throughput: for Flex and iDOT it is 1.9 years at 4 plates a week, 4.2 years at 2 and 11.5 years at 1.
From signal to a complete data package
The orchestrator stops at the data package. Hit selection, confirmation runs and hand-over to a LIMS or ELN come next in a real lab and are not built here.
What was measured
Every well: compound, dose, raw and normalised signal, timing and flags.
wells.csvreader_export.csvWhat it means
A dose-response fit and a call (active or not) for each compound.
analysis/curve_fits.csv What happened
Run record, deviations and a hash-chained custody log of every plate.
datapackage.jsonaudit/custody_log.json What was used
The exact spec, plate map, iDOT worklist and the three Flex protocols.
inputs/Ready to share
Standard AnIML export, validated against the core schema when the schema file is installed (the browser app skips it).
animl/experiment.animl Warnings and deviations are written into the flags column of every affected well.
What this is, and is not
Simulated
No real instrument has been connected.
Estimates
Timings and costs are placeholders until measured.
Not GxP
The validation pack shows the method, not a sign-off.
Portable
Spec, checks, custody, recovery, timing and package carry over. Only the instrument layer changes.
Simulate a run, then break it
Select a scenario and press Start. Codes are the ones the program writes to its record.
Show exactly what the program printed for this situation
Captured program output. [exit N] is the exit code.
The animation replays real scenario results; the program itself runs locally (see Run it).
Try it live, or run it on your computer
The live app runs in your browser with your own spec, nothing to install. For the full toolchain, use a terminal: Python 3.13, no lab equipment, runs offline once installed.
Open the live app View the code on GitHub Loads in 30 to 90 seconds on the first visit. Runs in your browser; nothing is sent to a server.
1. Get the project
Unzip hts-orchestrator and open a terminal in it.
2. Install it once
Installs the dependencies.
Optional: python scripts/fetch_animl_schemas.py downloads the official AnIML schema so the export can be validated.
3. Check the plan
Prints every finding; nothing runs yet.
4. Run a full simulated screen
Builds the files, runs the workflow, writes the package to out/.
5. Break it on purpose
Inject a fault: the arm drops the plate.
Try scenarios/nobody_there.yaml: the run pauses and prints the resume command.
6. Run every check
What the exit code means
| 0 | Complete: the data package was written. |
| 2 | Waiting or paused for an operator. State is saved; the output prints the resume command. |
| 3 | Aborted: no data package. |
Change the experiment
Edit specs/ctg3d_screen.yaml and re-run validate. See specs/example_*.yaml for typical mistakes.