Refua WetLab is a standalone project that exposes a unified HTTP API for wet-lab automation workflows.
It provides:
- A canonical protocol schema for common liquid-handling and assay operations.
- Provider adapters that compile canonical steps into provider-specific commands.
- Async run orchestration with status tracking and cancellation.
- A simulation-safe execution mode (
dry_run) for workflow development. - Inventory-aware simulation checks to catch impossible liquid moves before hardware time is spent.
- Priority-based background scheduling for urgent protocols.
- A built-in LMS layer for project/sample/plate/inventory/experiment management.
- End-to-end audit trails and LMS summaries (low-stock + expiring-material alerts).
cd refua-wetlab
pip install -e .
refua-wetlab --host 127.0.0.1 --port 8790Core WetLab API:
GET /api/healthGET /api/providersPOST /api/protocols/validatePOST /api/protocols/compilePOST /api/runsGET /api/runsGET /api/runs/{run_id}GET /api/runs/{run_id}/lineagePOST /api/runs/{run_id}/cancel
LMS API:
GET /api/lmsGET /api/lms/summaryGET /api/lms/auditGET /api/lms/projectsPOST /api/lms/projectsGET /api/lms/projects/{project_id}POST /api/lms/projects/{project_id}/statusGET /api/lms/samplesPOST /api/lms/samplesGET /api/lms/samples/{sample_id}POST /api/lms/samples/{sample_id}/statusGET /api/lms/samples/{sample_id}/eventsPOST /api/lms/samples/{sample_id}/eventsGET /api/lms/platesPOST /api/lms/platesGET /api/lms/plates/{plate_id}POST /api/lms/plates/{plate_id}/assignmentsGET /api/lms/inventory/itemsPOST /api/lms/inventory/itemsGET /api/lms/inventory/items/{item_id}POST /api/lms/inventory/items/{item_id}/transactionsGET /api/lms/inventory/items/{item_id}/transactionsGET /api/lms/experimentsPOST /api/lms/experimentsGET /api/lms/experiments/{experiment_id}POST /api/lms/experiments/{experiment_id}/statusPOST /api/lms/experiments/{experiment_id}/schedule-run
refua-wetlab now ships a direct Python LMS API so callers can use LMS workflows
without going through HTTP handlers.
from pathlib import Path
from refua_wetlab import LmsApi, LmsStore, UnifiedWetLabEngine
from refua_wetlab.runner import RunBackgroundRunner
from refua_wetlab.storage import RunStore
db_path = Path(".refua-wetlab") / "runs.sqlite3"
run_store = RunStore(db_path)
lms_store = LmsStore(db_path)
runner = RunBackgroundRunner(run_store, max_workers=2)
api = LmsApi(
lms_store=lms_store,
run_store=run_store,
runner=runner,
engine=UnifiedWetLabEngine(),
)
project = api.route_post(path="/api/lms/projects", payload={"name": "KRAS campaign"})
summary = api.route_get(path="/api/lms/summary")
api.shutdown(){
"name": "serial-dilution-screen",
"steps": [
{
"type": "transfer",
"source": "plate:A1",
"destination": "plate:B1",
"volume_ul": 50
},
{
"type": "mix",
"well": "plate:B1",
"volume_ul": 40,
"cycles": 5
},
{
"type": "incubate",
"duration_s": 900,
"temperature_c": 37
},
{
"type": "read_absorbance",
"plate": "plate",
"wavelength_nm": 450
}
]
}curl -s http://127.0.0.1:8790/api/protocols/compile \
-X POST \
-H "Content-Type: application/json" \
-d '{
"provider": "opentrons",
"protocol": {
"name": "serial-dilution-screen",
"steps": [
{"type":"transfer","source":"plate:A1","destination":"plate:B1","volume_ul":50}
]
}
}' | jqcurl -s http://127.0.0.1:8790/api/runs \
-X POST \
-H "Content-Type: application/json" \
-d '{
"provider": "hamilton",
"async_mode": true,
"dry_run": true,
"priority": 80,
"protocol": {
"name": "screen-v1",
"inventory": {
"plate:A1": 120.0,
"plate:B1": 0.0
},
"steps": [
{"type":"transfer","source":"plate:A1","destination":"plate:B1","volume_ul":20},
{"type":"incubate","duration_s":300}
]
}
}' | jq# 1) Create project
PROJECT_ID=$(curl -s http://127.0.0.1:8790/api/lms/projects \
-X POST -H "Content-Type: application/json" \
-d '{"name":"KRAS campaign","owner":"wetlab-team"}' | jq -r '.project.project_id')
# 2) Register sample
SAMPLE_ID=$(curl -s http://127.0.0.1:8790/api/lms/samples \
-X POST -H "Content-Type: application/json" \
-d '{
"project_id":"'"$PROJECT_ID"'",
"name":"KRAS_clone_1",
"sample_type":"cell_lysate",
"volume_ul":120
}' | jq -r '.sample.sample_id')
# 3) Create experiment with protocol
EXP_ID=$(curl -s http://127.0.0.1:8790/api/lms/experiments \
-X POST -H "Content-Type: application/json" \
-d '{
"project_id":"'"$PROJECT_ID"'",
"name":"KRAS absorbance screen",
"provider":"opentrons",
"sample_ids":["'"$SAMPLE_ID"'"],
"protocol": {
"name":"kras-screen",
"steps":[
{"type":"transfer","source":"plate:A1","destination":"plate:B1","volume_ul":20},
{"type":"mix","well":"plate:B1","volume_ul":15,"cycles":4},
{"type":"read_absorbance","plate":"plate","wavelength_nm":450}
]
}
}' | jq -r '.experiment.experiment_id')
# 4) Schedule run from experiment
curl -s http://127.0.0.1:8790/api/lms/experiments/$EXP_ID/schedule-run \
-X POST -H "Content-Type: application/json" \
-d '{"async_mode":false,"dry_run":true,"priority":85}' | jq
# 5) Get LMS summary
curl -s http://127.0.0.1:8790/api/lms/summary | jqrefua-wetlab is a simulation-first orchestration layer intended for protocol
design, dry-run validation, run metadata tracking, and LMS operations.
Current limitations:
- Provider execution in this package is mock/simulated; it does not drive real robotic hardware without an external adapter/runtime bridge.
- The canonical protocol model covers common liquid-handling and plate-read operations, not every vendor-native instruction.
- Scheduling is process-local and SQLite-backed; it is not a distributed queue.
- LMS data model is lightweight and embedded; it is not a replacement for enterprise LIMS/ELN systems.
- Auth is bearer-token based; there is no built-in SSO, RBAC policy engine, or audit-signature workflow.
- This package does not provide GxP/21 CFR Part 11 compliance guarantees.
- Treat this as an orchestration service, not as the final source of truth for regulated records.
- Run behind a trusted gateway (TLS termination, centralized authn/authz, request logging, and secrets management).
- Use routine backups for the SQLite database or replace storage with a managed backend in your deployment architecture.
cd refua-wetlab
python -m unittest discover -s tests -vBuild artifacts:
cd refua-wetlab
python -m build
python -m twine check dist/*- GitHub Actions CI:
.github/workflows/ci.yml - Pre-commit config:
.pre-commit-config.yaml
Run hooks locally:
cd refua-wetlab
pre-commit run --all-files