[{"data":1,"prerenderedAt":1865},["ShallowReactive",2],{"navigation":3,"\u002Fautomate\u002Fworkflow-template":750,"\u002Fautomate\u002Fworkflow-template-surround":1860},[4,80,134,364,428,530,567,646],{"title":5,"path":6,"stem":7,"children":8,"page":42},"Get Started","\u002Fget-started","01.get-started",[9,13,17,43,47],{"title":10,"path":11,"stem":12},"Welcome to UniteLabs","\u002Fget-started\u002Fwelcome","01.get-started\u002F00.welcome",{"title":14,"path":15,"stem":16},"How it works","\u002Fget-started\u002Fhow-it-works","01.get-started\u002F01.how-it-works",{"title":18,"path":19,"stem":20,"children":21,"page":42},"Use Cases","\u002Fget-started\u002Fuse-cases","01.get-started\u002F02.use-cases",[22,26,30,34,38],{"title":23,"path":24,"stem":25},"Instrument Control","\u002Fget-started\u002Fuse-cases\u002Flow-level-instrument-control","01.get-started\u002F02.use-cases\u002F10.low-level-instrument-control",{"title":27,"path":28,"stem":29},"Multi-device Control","\u002Fget-started\u002Fuse-cases\u002Fmulti-device-control","01.get-started\u002F02.use-cases\u002F20.multi-device-control",{"title":31,"path":32,"stem":33},"Workflow Orchestration","\u002Fget-started\u002Fuse-cases\u002Fworkflow-orchestration","01.get-started\u002F02.use-cases\u002F30.workflow-orchestration",{"title":35,"path":36,"stem":37},"Custom Apps and LIMS Integration","\u002Fget-started\u002Fuse-cases\u002Fcustom-apps-lims","01.get-started\u002F02.use-cases\u002F40.custom-apps-lims",{"title":39,"path":40,"stem":41},"Scale and Fleet Management","\u002Fget-started\u002Fuse-cases\u002Fscale-and-fleet","01.get-started\u002F02.use-cases\u002F50.scale-and-fleet",false,{"title":44,"path":45,"stem":46},"Lab as Code","\u002Fget-started\u002Fwhy-code","01.get-started\u002F03.why-code",{"title":48,"path":49,"stem":50,"children":51,"page":42},"Setup","\u002Fget-started\u002Fsetup","01.get-started\u002F20.setup",[52,56,60,64,68,72,76],{"title":53,"path":54,"stem":55},"GroundControl","\u002Fget-started\u002Fsetup\u002Fgroundcontrol","01.get-started\u002F20.setup\u002F10.groundcontrol",{"title":57,"path":58,"stem":59},"Network requirements","\u002Fget-started\u002Fsetup\u002Fnetwork-requirements","01.get-started\u002F20.setup\u002F20.network-requirements",{"title":61,"path":62,"stem":63},"Multi-device Networking","\u002Fget-started\u002Fsetup\u002Fmultiple-devices","01.get-started\u002F20.setup\u002F30.multiple-devices",{"title":65,"path":66,"stem":67},"Connect to Platform","\u002Fget-started\u002Fsetup\u002Fconnect-to-platform","01.get-started\u002F20.setup\u002F40.connect-to-platform",{"title":69,"path":70,"stem":71},"Headless install","\u002Fget-started\u002Fsetup\u002Fheadless-install","01.get-started\u002F20.setup\u002F50.headless-install",{"title":73,"path":74,"stem":75},"Raspberry Pi","\u002Fget-started\u002Fsetup\u002Fraspberry-pi","01.get-started\u002F20.setup\u002F55.raspberry-pi",{"title":77,"path":78,"stem":79},"Installation","\u002Fget-started\u002Fsetup\u002Fsdk-installation","01.get-started\u002F20.setup\u002F60.sdk-installation",{"title":81,"path":82,"stem":83,"children":84,"page":42},"Integrate","\u002Fintegrate","02.integrate",[85,89,93,118],{"title":86,"path":87,"stem":88},"What is a connector?","\u002Fintegrate\u002Fwhat-is-a-connector","02.integrate\u002F00.what-is-a-connector",{"title":90,"path":91,"stem":92},"Calling a Connector","\u002Fintegrate\u002Fcontrol-with-code","02.integrate\u002F05.control-with-code",{"title":94,"path":95,"stem":96,"children":97,"page":42},"Concepts","\u002Fintegrate\u002Fconcepts","02.integrate\u002F10.concepts",[98,102,106,110,114],{"title":99,"path":100,"stem":101},"Connector","\u002Fintegrate\u002Fconcepts\u002Fconnector","02.integrate\u002F10.concepts\u002F10.connector",{"title":103,"path":104,"stem":105},"Module","\u002Fintegrate\u002Fconcepts\u002Fmodule","02.integrate\u002F10.concepts\u002F20.module",{"title":107,"path":108,"stem":109},"Action","\u002Fintegrate\u002Fconcepts\u002Faction","02.integrate\u002F10.concepts\u002F30.action",{"title":111,"path":112,"stem":113},"Subscription","\u002Fintegrate\u002Fconcepts\u002Fsubscription","02.integrate\u002F10.concepts\u002F40.subscription",{"title":115,"path":116,"stem":117},"Device","\u002Fintegrate\u002Fconcepts\u002Fdevice","02.integrate\u002F10.concepts\u002F50.device",{"title":119,"path":120,"stem":121,"children":122,"page":42},"Use a connector","\u002Fintegrate\u002Fuse-a-connector","02.integrate\u002F30.use-a-connector",[123,126,130],{"title":53,"path":124,"stem":125},"\u002Fintegrate\u002Fuse-a-connector\u002Fgroundcontrol","02.integrate\u002F30.use-a-connector\u002F10.groundcontrol",{"title":127,"path":128,"stem":129},"Platform","\u002Fintegrate\u002Fuse-a-connector\u002Fplatform","02.integrate\u002F30.use-a-connector\u002F20.platform",{"title":131,"path":132,"stem":133},"UniteLabs SDK & REST API","\u002Fintegrate\u002Fuse-a-connector\u002Fpython","02.integrate\u002F30.use-a-connector\u002F30.python",{"title":135,"path":136,"stem":137,"children":138,"page":42},"Operate","\u002Foperate","03.operate",[139,142,146,186,259],{"title":135,"path":140,"stem":141},"\u002Foperate\u002Foverview","03.operate\u002F00.overview",{"title":143,"path":144,"stem":145},"Your First Protocol","\u002Foperate\u002Fyour-first-protocol","03.operate\u002F05.your-first-protocol",{"title":94,"path":147,"stem":148,"children":149,"page":42},"\u002Foperate\u002Fconcepts","03.operate\u002F10.concepts",[150,154,158,162,166,170,174,178,182],{"title":151,"path":152,"stem":153},"Liquid Handling","\u002Foperate\u002Fconcepts\u002Fliquid-handling","03.operate\u002F10.concepts\u002F10.liquid-handling",{"title":155,"path":156,"stem":157},"Modules","\u002Foperate\u002Fconcepts\u002Fmodules","03.operate\u002F10.concepts\u002F20.modules",{"title":159,"path":160,"stem":161},"Deck","\u002Foperate\u002Fconcepts\u002Fdeck","03.operate\u002F10.concepts\u002F30.deck",{"title":163,"path":164,"stem":165},"Labware","\u002Foperate\u002Fconcepts\u002Flabware","03.operate\u002F10.concepts\u002F40.labware",{"title":167,"path":168,"stem":169},"Liquids","\u002Foperate\u002Fconcepts\u002Fliquids","03.operate\u002F10.concepts\u002F50.liquids",{"title":171,"path":172,"stem":173},"Liquid Classes","\u002Foperate\u002Fconcepts\u002Fliquid-classes","03.operate\u002F10.concepts\u002F60.liquid-classes",{"title":175,"path":176,"stem":177},"Tips and Tip Tracking","\u002Foperate\u002Fconcepts\u002Ftips","03.operate\u002F10.concepts\u002F70.tips",{"title":179,"path":180,"stem":181},"Simulation","\u002Foperate\u002Fconcepts\u002Fsimulation","03.operate\u002F10.concepts\u002F80.simulation",{"title":183,"path":184,"stem":185},"Error Handling","\u002Foperate\u002Fconcepts\u002Ferror-handling","03.operate\u002F10.concepts\u002F90.error-handling",{"title":187,"path":188,"stem":189,"children":190,"page":42},"Guides","\u002Foperate\u002Fguides","03.operate\u002F20.guides",[191,220,232,256],{"title":163,"path":192,"stem":193,"children":194},"\u002Foperate\u002Fguides\u002Flabware","03.operate\u002F20.guides\u002F10.labware\u002Findex",[195,196,200,204,208,212,216],{"title":163,"path":192,"stem":193},{"title":197,"path":198,"stem":199},"Standard Labware","\u002Foperate\u002Fguides\u002Flabware\u002Fstandard-labware","03.operate\u002F20.guides\u002F10.labware\u002F05.standard-labware",{"title":201,"path":202,"stem":203},"Plates","\u002Foperate\u002Fguides\u002Flabware\u002Fplates","03.operate\u002F20.guides\u002F10.labware\u002F10.plates",{"title":205,"path":206,"stem":207},"Tips and Tip Racks","\u002Foperate\u002Fguides\u002Flabware\u002Ftips-and-racks","03.operate\u002F20.guides\u002F10.labware\u002F20.tips-and-racks",{"title":209,"path":210,"stem":211},"Tubes and Tube Racks","\u002Foperate\u002Fguides\u002Flabware\u002Ftubes-and-tube-racks","03.operate\u002F20.guides\u002F10.labware\u002F30.tubes-and-tube-racks",{"title":213,"path":214,"stem":215},"Troughs","\u002Foperate\u002Fguides\u002Flabware\u002Ftroughs","03.operate\u002F20.guides\u002F10.labware\u002F35.troughs",{"title":217,"path":218,"stem":219},"Carriers and Adapters","\u002Foperate\u002Fguides\u002Flabware\u002Fcarriers-and-adapters","03.operate\u002F20.guides\u002F10.labware\u002F40.carriers-and-adapters",{"title":159,"path":221,"stem":222,"children":223,"page":42},"\u002Foperate\u002Fguides\u002Fdeck","03.operate\u002F20.guides\u002F20.deck",[224,228],{"title":225,"path":226,"stem":227},"Building a Deck","\u002Foperate\u002Fguides\u002Fdeck\u002Fbuilding-a-deck","03.operate\u002F20.guides\u002F20.deck\u002F10.building-a-deck",{"title":229,"path":230,"stem":231},"Save\u002FLoad a Deck","\u002Foperate\u002Fguides\u002Fdeck\u002Fsave-load-deck","03.operate\u002F20.guides\u002F20.deck\u002F20.save-load-deck",{"title":233,"path":234,"stem":235,"children":236,"page":42},"Pipetting","\u002Foperate\u002Fguides\u002Fpipetting","03.operate\u002F20.guides\u002F30.pipetting",[237,241,245,249,252],{"title":238,"path":239,"stem":240},"Basic Pipetting","\u002Foperate\u002Fguides\u002Fpipetting\u002Fbasic-pipetting","03.operate\u002F20.guides\u002F30.pipetting\u002F10.basic-pipetting",{"title":242,"path":243,"stem":244},"Advanced Pipetting","\u002Foperate\u002Fguides\u002Fpipetting\u002Fadvanced-pipetting","03.operate\u002F20.guides\u002F30.pipetting\u002F20.advanced-pipetting",{"title":246,"path":247,"stem":248},"Tip Handling","\u002Foperate\u002Fguides\u002Fpipetting\u002Ftip-handling","03.operate\u002F20.guides\u002F30.pipetting\u002F30.tip-handling",{"title":171,"path":250,"stem":251},"\u002Foperate\u002Fguides\u002Fpipetting\u002Fliquid-classes","03.operate\u002F20.guides\u002F30.pipetting\u002F40.liquid-classes",{"title":253,"path":254,"stem":255},"Labware Transport","\u002Foperate\u002Fguides\u002Fpipetting\u002Flabware-transport","03.operate\u002F20.guides\u002F30.pipetting\u002F50.labware-transport",{"title":179,"path":257,"stem":258},"\u002Foperate\u002Fguides\u002Fsimulation","03.operate\u002F20.guides\u002F40.simulation",{"title":260,"path":261,"stem":262,"children":263,"page":42},"Liquid Handler Guides","\u002Foperate\u002Fdevices","03.operate\u002F30.devices",[264,305,330,347],{"title":265,"path":266,"stem":267,"children":268,"page":42},"Hamilton STAR","\u002Foperate\u002Fdevices\u002Fhamilton-star","03.operate\u002F30.devices\u002F10.hamilton-star",[269,273,277,281,285,289,293,297,301],{"title":270,"path":271,"stem":272},"Positioning & Movement","\u002Foperate\u002Fdevices\u002Fhamilton-star\u002Fpositioning","03.operate\u002F30.devices\u002F10.hamilton-star\u002F10.positioning",{"title":274,"path":275,"stem":276},"Gripper Module","\u002Foperate\u002Fdevices\u002Fhamilton-star\u002Fcore-gripper","03.operate\u002F30.devices\u002F10.hamilton-star\u002F20.core-gripper",{"title":278,"path":279,"stem":280},"iSWAP Module","\u002Foperate\u002Fdevices\u002Fhamilton-star\u002Fiswap","03.operate\u002F30.devices\u002F10.hamilton-star\u002F30.iswap",{"title":282,"path":283,"stem":284},"Using TADM","\u002Foperate\u002Fdevices\u002Fhamilton-star\u002Ftadm","03.operate\u002F30.devices\u002F10.hamilton-star\u002F40.tadm",{"title":286,"path":287,"stem":288},"Autoload Module","\u002Foperate\u002Fdevices\u002Fhamilton-star\u002Fautoload","03.operate\u002F30.devices\u002F10.hamilton-star\u002F50.autoload",{"title":290,"path":291,"stem":292},"Waste Block","\u002Foperate\u002Fdevices\u002Fhamilton-star\u002Fwaste-block","03.operate\u002F30.devices\u002F10.hamilton-star\u002F60.waste-block",{"title":294,"path":295,"stem":296},"Complex Mixing","\u002Foperate\u002Fdevices\u002Fhamilton-star\u002Fcomplex-mixing","03.operate\u002F30.devices\u002F10.hamilton-star\u002F66.complex-mixing",{"title":298,"path":299,"stem":300},"Teaching Gripper Paddle Positions","\u002Foperate\u002Fdevices\u002Fhamilton-star\u002Fgripper-positions","03.operate\u002F30.devices\u002F10.hamilton-star\u002F70.gripper-positions",{"title":302,"path":303,"stem":304},"Training a Custom Deck Position With the iSWAP","\u002Foperate\u002Fdevices\u002Fhamilton-star\u002Fcustom-deck-position","03.operate\u002F30.devices\u002F10.hamilton-star\u002F75.custom-deck-position",{"title":306,"path":307,"stem":308,"children":309,"page":42},"Hamilton Vantage","\u002Foperate\u002Fdevices\u002Fhamilton-vantage","03.operate\u002F30.devices\u002F20.hamilton-vantage",[310,314,318,322,326],{"title":311,"path":312,"stem":313},"Waste Configuration","\u002Foperate\u002Fdevices\u002Fhamilton-vantage\u002Fwaste-configuration","03.operate\u002F30.devices\u002F20.hamilton-vantage\u002F05.waste-configuration",{"title":315,"path":316,"stem":317},"Covers and Lights","\u002Foperate\u002Fdevices\u002Fhamilton-vantage\u002Fcovers-and-lights","03.operate\u002F30.devices\u002F20.hamilton-vantage\u002F10.covers-and-lights",{"title":319,"path":320,"stem":321},"IDL Module","\u002Foperate\u002Fdevices\u002Fhamilton-vantage\u002Fidl","03.operate\u002F30.devices\u002F20.hamilton-vantage\u002F20.idl",{"title":323,"path":324,"stem":325},"IPG Module","\u002Foperate\u002Fdevices\u002Fhamilton-vantage\u002Fipg","03.operate\u002F30.devices\u002F20.hamilton-vantage\u002F30.ipg",{"title":327,"path":328,"stem":329},"XL Pipettes","\u002Foperate\u002Fdevices\u002Fhamilton-vantage\u002Fxl-channels","03.operate\u002F30.devices\u002F20.hamilton-vantage\u002F40.xl-channels",{"title":331,"path":332,"stem":333,"children":334,"page":42},"Agilent Bravo","\u002Foperate\u002Fdevices\u002Fagilent-bravo","03.operate\u002F30.devices\u002F30.agilent-bravo",[335,338,341,344],{"title":246,"path":336,"stem":337},"\u002Foperate\u002Fdevices\u002Fagilent-bravo\u002Ftip-handling","03.operate\u002F30.devices\u002F30.agilent-bravo\u002F10.tip-handling",{"title":238,"path":339,"stem":340},"\u002Foperate\u002Fdevices\u002Fagilent-bravo\u002Fbasic-pipetting","03.operate\u002F30.devices\u002F30.agilent-bravo\u002F20.basic-pipetting",{"title":171,"path":342,"stem":343},"\u002Foperate\u002Fdevices\u002Fagilent-bravo\u002Fliquid-classes","03.operate\u002F30.devices\u002F30.agilent-bravo\u002F25.liquid-classes",{"title":274,"path":345,"stem":346},"\u002Foperate\u002Fdevices\u002Fagilent-bravo\u002Fusing-the-gripper","03.operate\u002F30.devices\u002F30.agilent-bravo\u002F30.using-the-gripper",{"title":348,"path":349,"stem":350,"children":351,"page":42},"Tecan FluentControl","\u002Foperate\u002Fdevices\u002Ftecan-fluentcontrol","03.operate\u002F30.devices\u002F40.tecan-fluentcontrol",[352,356,360],{"title":353,"path":354,"stem":355},"Connect & Run a Method","\u002Foperate\u002Fdevices\u002Ftecan-fluentcontrol\u002Fconnect-and-run","03.operate\u002F30.devices\u002F40.tecan-fluentcontrol\u002F10.connect-and-run",{"title":357,"path":358,"stem":359},"Sending XML Commands","\u002Foperate\u002Fdevices\u002Ftecan-fluentcontrol\u002Fsending-xml-commands","03.operate\u002F30.devices\u002F40.tecan-fluentcontrol\u002F20.sending-xml-commands",{"title":361,"path":362,"stem":363},"Full Workflow Example","\u002Foperate\u002Fdevices\u002Ftecan-fluentcontrol\u002Ffull-workflow-example","03.operate\u002F30.devices\u002F40.tecan-fluentcontrol\u002F30.full-workflow-example",{"title":365,"path":366,"stem":367,"children":368,"page":42},"Device Guides","\u002Fdevice-guides","06.device-guides",[369,372,385,402,415],{"title":365,"path":370,"stem":371},"\u002Fdevice-guides\u002Foverview","06.device-guides\u002F00.overview",{"title":373,"path":374,"stem":375,"children":376,"page":42},"Incubation","\u002Fdevice-guides\u002Fincubation","06.device-guides\u002F20.incubation",[377,381],{"title":378,"path":379,"stem":380},"Inheco ODTC","\u002Fdevice-guides\u002Fincubation\u002Finheco-odtc","06.device-guides\u002F20.incubation\u002F10.inheco-odtc",{"title":382,"path":383,"stem":384},"Inheco SCILA","\u002Fdevice-guides\u002Fincubation\u002Finheco-scila","06.device-guides\u002F20.incubation\u002F20.inheco-scila",{"title":386,"path":387,"stem":388,"children":389,"page":42},"Heater-Shakers","\u002Fdevice-guides\u002Fheater-shakers","06.device-guides\u002F30.heater-shakers",[390,394,398],{"title":391,"path":392,"stem":393},"Inheco Thermoshake","\u002Fdevice-guides\u002Fheater-shakers\u002Finheco-thermoshake","06.device-guides\u002F30.heater-shakers\u002F10.inheco-thermoshake",{"title":395,"path":396,"stem":397},"QInstruments Bioshake","\u002Fdevice-guides\u002Fheater-shakers\u002Fqinstruments-bioshake","06.device-guides\u002F30.heater-shakers\u002F20.qinstruments-bioshake",{"title":399,"path":400,"stem":401},"QInstruments ColdPlate","\u002Fdevice-guides\u002Fheater-shakers\u002Fqinstruments-coldplate","06.device-guides\u002F30.heater-shakers\u002F30.qinstruments-coldplate",{"title":403,"path":404,"stem":405,"children":406,"page":42},"Readers","\u002Fdevice-guides\u002Freaders","06.device-guides\u002F40.readers",[407,411],{"title":408,"path":409,"stem":410},"Biotek Gen5","\u002Fdevice-guides\u002Freaders\u002Fbiotek-gen5","06.device-guides\u002F40.readers\u002F10.biotek-gen5",{"title":412,"path":413,"stem":414},"Biotek Synergy H1","\u002Fdevice-guides\u002Freaders\u002Fbiotek-synergy-h1","06.device-guides\u002F40.readers\u002F20.biotek-synergy-H1",{"title":416,"path":417,"stem":418,"children":419,"page":42},"Tilt & Turn","\u002Fdevice-guides\u002Ftilt-and-turn","06.device-guides\u002F50.tilt-and-turn",[420,424],{"title":421,"path":422,"stem":423},"TurnStation","\u002Fdevice-guides\u002Ftilt-and-turn\u002Fqinstruments-turnstation","06.device-guides\u002F50.tilt-and-turn\u002F10.qinstruments-turnstation",{"title":425,"path":426,"stem":427},"TiltStation","\u002Fdevice-guides\u002Ftilt-and-turn\u002Fqinstruments-tiltstation","06.device-guides\u002F50.tilt-and-turn\u002F20.qinstruments-tiltstation",{"title":429,"path":430,"stem":431,"children":432,"page":42},"Automate","\u002Fautomate","07.automate",[433,437,441,445,494],{"title":434,"path":435,"stem":436},"What is a workflow?","\u002Fautomate\u002Fwhat-is-a-workflow","07.automate\u002F00.what-is-a-workflow",{"title":438,"path":439,"stem":440},"Workflow template","\u002Fautomate\u002Fworkflow-template","07.automate\u002F05.workflow-template",{"title":442,"path":443,"stem":444},"Your First Workflow","\u002Fautomate\u002Fyour-first-workflow","07.automate\u002F08.your-first-workflow",{"title":94,"pages":446,"path":456,"stem":457,"children":458,"page":42},[447,448,449,450,451,452,453,454,455],"workflow","phase","step","runs","input","artifacts","logs","human-in-the-loop","error-handling","\u002Fautomate\u002Fconcepts","07.automate\u002F10.concepts",[459,463,467,471,475,479,483,487,491],{"title":460,"path":461,"stem":462},"Workflow","\u002Fautomate\u002Fconcepts\u002Fworkflow","07.automate\u002F10.concepts\u002F10.workflow",{"title":464,"path":465,"stem":466},"Phase","\u002Fautomate\u002Fconcepts\u002Fphase","07.automate\u002F10.concepts\u002F20.phase",{"title":468,"path":469,"stem":470},"Step","\u002Fautomate\u002Fconcepts\u002Fstep","07.automate\u002F10.concepts\u002F30.step",{"title":472,"path":473,"stem":474},"Runs","\u002Fautomate\u002Fconcepts\u002Fruns","07.automate\u002F10.concepts\u002F40.runs",{"title":476,"path":477,"stem":478},"Input","\u002Fautomate\u002Fconcepts\u002Finput","07.automate\u002F10.concepts\u002F50.input",{"title":480,"path":481,"stem":482},"Artifacts","\u002Fautomate\u002Fconcepts\u002Fartifacts","07.automate\u002F10.concepts\u002F60.artifacts",{"title":484,"path":485,"stem":486},"Logs","\u002Fautomate\u002Fconcepts\u002Flogs","07.automate\u002F10.concepts\u002F70.logs",{"title":488,"path":489,"stem":490},"Human in the Loop","\u002Fautomate\u002Fconcepts\u002Fhuman-in-the-loop","07.automate\u002F10.concepts\u002F80.human-in-the-loop",{"title":183,"path":492,"stem":493},"\u002Fautomate\u002Fconcepts\u002Ferror-handling","07.automate\u002F10.concepts\u002F90.error-handling",{"title":187,"path":495,"stem":496,"children":497,"page":42},"\u002Fautomate\u002Fguides","07.automate\u002F25.guides",[498,502,506,510,514,518,522,526],{"title":499,"path":500,"stem":501},"Deploy a workflow","\u002Fautomate\u002Fguides\u002Fdeploy-a-workflow","07.automate\u002F25.guides\u002F30.deploy-a-workflow",{"title":503,"path":504,"stem":505},"Run a workflow","\u002Fautomate\u002Fguides\u002Frun-a-workflow","07.automate\u002F25.guides\u002F35.run-a-workflow",{"title":507,"path":508,"stem":509},"CI\u002FCD for workflows","\u002Fautomate\u002Fguides\u002Fcicd-for-workflows","07.automate\u002F25.guides\u002F40.cicd-for-workflows",{"title":511,"path":512,"stem":513},"HITL basics","\u002Fautomate\u002Fguides\u002Fbasic-hitl","07.automate\u002F25.guides\u002F50.basic-hitl",{"title":515,"path":516,"stem":517},"Typed operator inputs","\u002Fautomate\u002Fguides\u002Ftyped-operator-inputs","07.automate\u002F25.guides\u002F55.typed-operator-inputs",{"title":519,"path":520,"stem":521},"Error recovery","\u002Fautomate\u002Fguides\u002Fbasic-error-handling","07.automate\u002F25.guides\u002F60.basic-error-handling",{"title":523,"path":524,"stem":525},"Advanced error handling","\u002Fautomate\u002Fguides\u002Fadvanced-error-handling","07.automate\u002F25.guides\u002F70.advanced-error-handling",{"title":527,"path":528,"stem":529},"Workflows REST API","\u002Fautomate\u002Fguides\u002Fworkflows-api","07.automate\u002F25.guides\u002F80.workflows-api",{"title":531,"path":532,"stem":533,"children":534,"page":42},"Observe","\u002Fobserve","08.observe",[535,539,555],{"title":536,"path":537,"stem":538},"Overview","\u002Fobserve\u002Foverview","08.observe\u002F10.overview",{"title":94,"path":540,"stem":541,"children":542,"page":42},"\u002Fobserve\u002Fconcepts","08.observe\u002F20.concepts",[543,547,551],{"title":544,"path":545,"stem":546},"Object Storage","\u002Fobserve\u002Fconcepts\u002Fstorage","08.observe\u002F20.concepts\u002F10.storage",{"title":548,"path":549,"stem":550},"Secrets","\u002Fobserve\u002Fconcepts\u002Fsecrets","08.observe\u002F20.concepts\u002F20.secrets",{"title":552,"path":553,"stem":554},"Data sources","\u002Fobserve\u002Fconcepts\u002Fdata-sources","08.observe\u002F20.concepts\u002F30.data-sources",{"title":187,"path":556,"stem":557,"children":558,"page":42},"\u002Fobserve\u002Fguides","08.observe\u002F30.guides",[559,563],{"title":560,"path":561,"stem":562},"File System Connector","\u002Fobserve\u002Fguides\u002Ffilesystem-connector","08.observe\u002F30.guides\u002F10.filesystem-connector",{"title":564,"path":565,"stem":566},"Building an ETL","\u002Fobserve\u002Fguides\u002Fbuilding-an-etl","08.observe\u002F30.guides\u002F20.building-an-etl",{"title":568,"path":569,"stem":570,"children":571,"page":42},"Technical Reference","\u002Ftechnical-reference","10.technical-reference",[572,576,580,592,603,614,624,635],{"title":573,"path":574,"stem":575},"Introduction","\u002Ftechnical-reference\u002Fplatform-blueprint","10.technical-reference\u002F00.platform-blueprint",{"title":577,"path":578,"stem":579},"REST API","\u002Ftechnical-reference\u002Frest-api","10.technical-reference\u002F01.rest-api",{"title":53,"path":581,"stem":582,"children":583,"page":42},"\u002Ftechnical-reference\u002Fgroundcontrol","10.technical-reference\u002F10.groundcontrol",[584,588],{"title":585,"path":586,"stem":587},"Install & Setup","\u002Ftechnical-reference\u002Fgroundcontrol\u002Finstall","10.technical-reference\u002F10.groundcontrol\u002F10.install",{"title":589,"path":590,"stem":591},"Changelog","\u002Ftechnical-reference\u002Fgroundcontrol\u002Fchangelog","10.technical-reference\u002F10.groundcontrol\u002F20.changelog",{"title":593,"path":594,"stem":595,"children":596,"page":42},"UniteLabs SDK","\u002Ftechnical-reference\u002Fpython-sdk","10.technical-reference\u002F20.python-sdk",[597,600],{"title":585,"path":598,"stem":599},"\u002Ftechnical-reference\u002Fpython-sdk\u002Finstall","10.technical-reference\u002F20.python-sdk\u002F10.install",{"title":589,"path":601,"stem":602},"\u002Ftechnical-reference\u002Fpython-sdk\u002Fchangelog","10.technical-reference\u002F20.python-sdk\u002F20.changelog",{"title":604,"path":605,"stem":606,"children":607,"page":42},"Liquid Handling SDK","\u002Ftechnical-reference\u002Fpython-liquid-handling-sdk","10.technical-reference\u002F30.python-liquid-handling-sdk",[608,611],{"title":585,"path":609,"stem":610},"\u002Ftechnical-reference\u002Fpython-liquid-handling-sdk\u002Finstall","10.technical-reference\u002F30.python-liquid-handling-sdk\u002F10.install",{"title":589,"path":612,"stem":613},"\u002Ftechnical-reference\u002Fpython-liquid-handling-sdk\u002Fchangelog","10.technical-reference\u002F30.python-liquid-handling-sdk\u002F20.changelog",{"title":163,"path":615,"stem":616,"children":617,"page":42},"\u002Ftechnical-reference\u002Flabware","10.technical-reference\u002F40.labware",[618,621],{"title":585,"path":619,"stem":620},"\u002Ftechnical-reference\u002Flabware\u002Finstall","10.technical-reference\u002F40.labware\u002F10.install",{"title":589,"path":622,"stem":623},"\u002Ftechnical-reference\u002Flabware\u002Fchangelog","10.technical-reference\u002F40.labware\u002F20.changelog",{"title":625,"path":626,"stem":627,"children":628,"page":42},"Python Omnibus","\u002Ftechnical-reference\u002Fpython-omnibus","10.technical-reference\u002F50.python-omnibus",[629,632],{"title":585,"path":630,"stem":631},"\u002Ftechnical-reference\u002Fpython-omnibus\u002Finstall","10.technical-reference\u002F50.python-omnibus\u002F10.install",{"title":589,"path":633,"stem":634},"\u002Ftechnical-reference\u002Fpython-omnibus\u002Fchangelog","10.technical-reference\u002F50.python-omnibus\u002F20.changelog",{"title":636,"path":637,"stem":638,"children":639,"page":42},"Python CDK","\u002Ftechnical-reference\u002Fpython-cdk","10.technical-reference\u002F60.python-cdk",[640,643],{"title":585,"path":641,"stem":642},"\u002Ftechnical-reference\u002Fpython-cdk\u002Finstall","10.technical-reference\u002F60.python-cdk\u002F10.install",{"title":589,"path":644,"stem":645},"\u002Ftechnical-reference\u002Fpython-cdk\u002Fchangelog","10.technical-reference\u002F60.python-cdk\u002F20.changelog",{"title":647,"path":648,"stem":649,"children":650},"Connector Development (CDK)","\u002Fconnector-development","20.connector-development",[651,653,672,705,713,744],{"title":647,"path":648,"stem":652},"20.connector-development\u002Findex",{"title":654,"path":655,"stem":656,"children":657,"page":42},"Getting Started","\u002Fconnector-development\u002Fgetting-started","20.connector-development\u002F10.getting-started",[658,661,665,668],{"title":536,"path":659,"stem":660},"\u002Fconnector-development\u002Fgetting-started\u002Foverview","20.connector-development\u002F10.getting-started\u002F10.overview",{"title":662,"path":663,"stem":664},"What's new","\u002Fconnector-development\u002Fgetting-started\u002Fwhats-new","20.connector-development\u002F10.getting-started\u002F20.whats-new",{"title":77,"path":666,"stem":667},"\u002Fconnector-development\u002Fgetting-started\u002Finstallation","20.connector-development\u002F10.getting-started\u002F30.installation",{"title":669,"path":670,"stem":671},"Contributing","\u002Fconnector-development\u002Fgetting-started\u002Fcontributing","20.connector-development\u002F10.getting-started\u002F40.contributing",{"title":673,"path":674,"stem":675,"children":676,"page":42},"Tutorial","\u002Fconnector-development\u002Ftutorial","20.connector-development\u002F20.tutorial",[677,681,685,689,693,697,701],{"title":678,"path":679,"stem":680},"Walkthrough","\u002Fconnector-development\u002Ftutorial\u002Fwalkthrough","20.connector-development\u002F20.tutorial\u002F00.walkthrough",{"title":682,"path":683,"stem":684},"SiLA Endpoints","\u002Fconnector-development\u002Ftutorial\u002Fsila-endpoints","20.connector-development\u002F20.tutorial\u002F10.sila-endpoints",{"title":686,"path":687,"stem":688},"Data Endpoints","\u002Fconnector-development\u002Ftutorial\u002Fdata-endpoints","20.connector-development\u002F20.tutorial\u002F20.data-endpoints",{"title":690,"path":691,"stem":692},"Controls","\u002Fconnector-development\u002Ftutorial\u002Fcontrols","20.connector-development\u002F20.tutorial\u002F30.controls",{"title":694,"path":695,"stem":696},"SiLA Data Types","\u002Fconnector-development\u002Ftutorial\u002Fdata-types","20.connector-development\u002F20.tutorial\u002F40.data-types",{"title":698,"path":699,"stem":700},"Feature","\u002Fconnector-development\u002Ftutorial\u002Fconnector-structure","20.connector-development\u002F20.tutorial\u002F70.connector-structure",{"title":702,"path":703,"stem":704},"Hardware Communication","\u002Fconnector-development\u002Ftutorial\u002Fhardware-communication","20.connector-development\u002F20.tutorial\u002F90.hardware-communication",{"title":94,"path":706,"stem":707,"children":708,"page":42},"\u002Fconnector-development\u002Fconcepts","20.connector-development\u002F30.concepts",[709],{"title":710,"path":711,"stem":712},"SiLA","\u002Fconnector-development\u002Fconcepts\u002Fsila","20.connector-development\u002F30.concepts\u002Fsila",{"title":187,"path":714,"stem":715,"children":716,"page":42},"\u002Fconnector-development\u002Fguides","20.connector-development\u002F40.guides",[717,721,725,729,733,736,740],{"title":718,"path":719,"stem":720},"Configuration","\u002Fconnector-development\u002Fguides\u002Fconfiguration","20.connector-development\u002F40.guides\u002F20.configuration",{"title":722,"path":723,"stem":724},"Deployment","\u002Fconnector-development\u002Fguides\u002Fdeployment","20.connector-development\u002F40.guides\u002F30.deployment",{"title":726,"path":727,"stem":728},"Security","\u002Fconnector-development\u002Fguides\u002Fsecurity","20.connector-development\u002F40.guides\u002F40.security",{"title":730,"path":731,"stem":732},"Subscriptions","\u002Fconnector-development\u002Fguides\u002Fsubscriptions","20.connector-development\u002F40.guides\u002F45.subscriptions",{"title":183,"path":734,"stem":735},"\u002Fconnector-development\u002Fguides\u002Ferror-handling","20.connector-development\u002F40.guides\u002F50.error-handling",{"title":737,"path":738,"stem":739},"Serial Troubleshooting","\u002Fconnector-development\u002Fguides\u002Fserial-troubleshooting","20.connector-development\u002F40.guides\u002F70.serial-troubleshooting",{"title":741,"path":742,"stem":743},"Testing","\u002Fconnector-development\u002Fguides\u002Ftesting","20.connector-development\u002F40.guides\u002F80.testing",{"title":745,"path":746,"stem":747,"children":748},"References","\u002Fconnector-development\u002Freference","20.connector-development\u002F50.reference\u002Findex",[749],{"title":745,"path":746,"stem":747},{"id":751,"title":438,"body":752,"description":1854,"extension":1855,"links":1856,"meta":1857,"navigation":1401,"path":439,"seo":1858,"stem":440,"__hash__":1859},"docs\u002F07.automate\u002F05.workflow-template.md",{"type":753,"value":754,"toc":1838},"minimark",[755,778,783,804,895,913,917,930,940,951,965,969,972,977,1010,1028,1032,1043,1059,1146,1162,1166,1173,1225,1238,1242,1245,1248,1268,1271,1284,1288,1291,1309,1318,1331,1335,1338,1361,1374,1447,1454,1457,1461,1468,1471,1485,1488,1506,1509,1527,1554,1570,1574,1585,1592,1677,1696,1700,1709,1774,1780,1784,1834],[756,757,758,759,766,767,770,771,770,774,777],"p",{},"The ",[760,761,765],"a",{"href":762,"rel":763},"https:\u002F\u002Fgitlab.com\u002Funitelabs\u002Fworkflows\u002Fworkflow-template",[764],"nofollow","workflow template"," is a reference implementation of the UniteLabs three-layer taxonomy: ",[760,768,460],{"href":769},"\u002Fautomate\u002Fconcepts\u002Fworkflow\u002F"," → ",[760,772,464],{"href":773},"\u002Fautomate\u002Fconcepts\u002Fphase\u002F",[760,775,468],{"href":776},"\u002Fautomate\u002Fconcepts\u002Fstep\u002F",". Clone it to learn the structure, or fork it as the starting point for your own project. You can run the first workflow in this template without any access credentials or special setup. Try it out!",[779,780,782],"h2",{"id":781},"three-reference-workflows","Three reference workflows",[756,784,785,786,790,791,795,796,799,800,803],{},"The template ships three progressive examples, each as an ",[787,788,789],"strong",{},"independent standalone package"," under its own top-level directory. Each has its own ",[792,793,794],"code",{},"pyproject.toml",", ",[792,797,798],{},"uv.lock",", version, and ",[792,801,802],{},"[tool.unitelabs.workflow]"," metadata, so bumping one doesn't affect the others. This enables you to specify dependencies on a per workflow basis, while being able to share code easily between them. This makes maintainability and deployment easier, but more on that later.",[805,806,807,822],"table",{},[808,809,810],"thead",{},[811,812,813,817,819],"tr",{},[814,815,816],"th",{},"#",[814,818,460],{},[814,820,821],{},"Demonstrates",[823,824,825,845,868],"tbody",{},[811,826,827,833,838],{},[828,829,830],"td",{},[787,831,832],{},"W01",[828,834,835],{},[792,836,837],{},"hello_world",[828,839,840,841,844],{},"Minimal ",[792,842,843],{},"@workflow"," that logs the SDK version. This is a sanity check that your environment is wired correctly. No hardware, no connection to the platform is required.",[811,846,847,852,857],{},[828,848,849],{},[787,850,851],{},"W02",[828,853,854],{},[792,855,856],{},"liquid_handling",[828,858,859,860,770,862,864,865,867],{},"8-channel plate-to-plate transfer on a Hamilton Microlab STAR. Runs with our mocked Microlab STAR to simulate the workflow run by default. Exercises the full ",[760,861,460],{"href":769},[760,863,464],{"href":773}," -> ",[760,866,468],{"href":776}," layer without hardware.",[811,869,870,875,880],{},[828,871,872],{},[787,873,874],{},"W03",[828,876,877],{},[792,878,879],{},"plateloc_sealer",[828,881,882,883,887,888,891,892,894],{},"Operator-guided plate sealing. Shows ",[760,884,886],{"href":885},"\u002Fautomate\u002Fconcepts\u002Fhuman-in-the-loop\u002F","human in the loop"," with ",[792,889,890],{},"pause_flow_run()"," inside a ",[760,893,448],{"href":773},".",[756,896,897,898,901,902,905,906,909,910,894],{},"Each workflow is a self-contained Python package at the repo root. The sibling ",[792,899,900],{},"shared\u002F"," library holds the cross-workflow pieces (per-instrument config, custom labware, reusable ",[792,903,904],{},"@step"," steps, helpers) and is consumed by each workflow via ",[792,907,908],{},"shared = { path = \"..\u002Fshared\", editable = true }"," in its ",[792,911,912],{},"[tool.uv.sources]",[779,914,916],{"id":915},"project-structure","Project structure",[756,918,919,920,922,923,926,927,894],{},"The directory layout maps directly onto the taxonomy. Reusable ",[792,921,904],{}," implementations live under ",[792,924,925],{},"steps\u002F{component}\u002F","; full protocols live under ",[792,928,929],{},"workflows\u002Fw{NN}_{name}\u002F",[931,932,937],"pre",{"className":933,"code":935,"language":936},[934],"language-text","workflow-template\u002F                       # uv workspace root (monorepo)\n├── shared\u002F                              # Shared library package. Add as many custom packages.\n│   ├── src\u002Fshared\u002F\n│   │   ├── config\u002F                      # Device configs (plateloc.py, microlab_star.py, …)\n│   │   ├── library\u002F                     # Custom labware definitions\n│   │   │   └── labware\u002F\n│   │   ├── steps\u002F                       # Custom step library: reusable @step functions by component\n│   │   │   ├── plateloc\u002F\n│   │   │   │   ├── _helpers.py          # Plain async SDK wrappers (not tracked)\n│   │   │   │   └── _steps.py            # @step public API\n│   │   │   └── liquid_handler\u002F\n│   │   │       ├── _helpers.py\n│   │   │       └── _steps.py\n│   │   └── utils\u002F                       # operator_input.py, etc.\n│   ├── tests\u002F\n│   ├── pyproject.toml\n│   └── uv.lock\n│\n├── w01-hello-world\u002F                     # Standalone workflow app\n│   ├── src\u002Fw01_hello_world\u002F\n│   │   ├── __main__.py                  # `uv run workflow` entrypoint\n│   │   └── workflow.py\n│   ├── tests\u002F\n│   ├── pyproject.toml                   # workflow specific pyproject.toml\n│   └── uv.lock\n│\n├── w02-liquid-handling\u002F                 # Standalone workflow app\n│   ├── src\u002Fw02_liquid_handling\u002F\n│   │   ├── __main__.py\n│   │   ├── workflow.py\n│   │   ├── phase_01_setup.py\n│   │   └── phase_02_transfer.py\n│   └── ...\n│\n├── w03-plateloc-sealer\u002F                 # Standalone workflow app\n│   └── ...\n│\n├── scripts\u002F\n│   └── deploy.py                        # See usage in pyproject.toml [tool.unitelabs.workflow])\n│\n├── .github\u002F                             # CI\n├── .gitlab-ci.yml\n├── .env \u002F .env.example                  # BASE_URL, AUTH_URL, CLIENT_ID, CLIENT_SECRET, API_URL\n├── pytest.ini\n├── ruff.toml\n├── workflow-template.code-workspace     # VS Code multi-root workspace\n└──  README.md\n","text",[792,938,935],{"__ignoreMap":939},"",[756,941,942,943,950],{},"The repository's ",[760,944,947],{"href":945,"rel":946},"https:\u002F\u002Fgitlab.com\u002Funitelabs\u002Fworkflows\u002Fworkflow-template\u002F-\u002Fblob\u002Fmain\u002FAGENTS.md",[764],[792,948,949],{},"AGENTS.md"," is the authoritative authoring guide for retry policy, naming conventions, and what belongs where.",[952,953,955],"callout",{"icon":954},"i-heroicons-information-circle",[756,956,957,960,961,964],{},[787,958,959],{},"Why per-workflow packages instead of a uv workspace?"," Per-workflow SDK pins need to diverge across tenants and instrument generations. Standalone packages let each workflow lock its own ",[792,962,963],{},"unitelabs-*"," versions without dragging the others along.",[779,966,968],{"id":967},"clone-and-deploy","Clone and deploy",[756,970,971],{},"End-to-end: clone the repo, run workflows W01-W03 in your IDE, then deploy a workflow to the platform.",[973,974,976],"h3",{"id":975},"_1-clone-the-repository","1. Clone the repository",[931,978,982],{"className":979,"code":980,"language":981,"meta":939,"style":939},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","git clone https:\u002F\u002Fgitlab.com\u002Funitelabs\u002Fworkflows\u002Fworkflow-template.git\ncd workflow-template\n","bash",[792,983,984,1000],{"__ignoreMap":939},[985,986,989,993,997],"span",{"class":987,"line":988},"line",1,[985,990,992],{"class":991},"sBMFI","git",[985,994,996],{"class":995},"sfazB"," clone",[985,998,999],{"class":995}," https:\u002F\u002Fgitlab.com\u002Funitelabs\u002Fworkflows\u002Fworkflow-template.git\n",[985,1001,1003,1007],{"class":987,"line":1002},2,[985,1004,1006],{"class":1005},"s2Zo4","cd",[985,1008,1009],{"class":995}," workflow-template\n",[756,1011,1012,1013,1016,1017,1020,1021,1023,1024,1027],{},"In your file explorer, navigate into the cloned ",[792,1014,1015],{},"workflow-template\u002F"," directory and open ",[792,1018,1019],{},"workflow-template.code-workspace"," with VS Code. It opens directly into the pre-configured multi-root workspace, with each workflow and ",[792,1022,900],{}," loaded as a side-by-side root. After you sync dependencies in step 3, the per-folder ",[792,1025,1026],{},".venv"," is recognized natively.",[973,1029,1031],{"id":1030},"_2-configure-credentials","2. Configure credentials",[756,1033,1034,1035,1038,1039,1042],{},"Copy ",[792,1036,1037],{},".env.example"," to ",[792,1040,1041],{},".env"," and fill in the four values. These credentials are required for the UniteLabs Python client object to establish a connection to the platform API for e.g. connector communication:",[931,1044,1046],{"className":979,"code":1045,"language":981,"meta":939,"style":939},"cp .env.example .env\n",[792,1047,1048],{"__ignoreMap":939},[985,1049,1050,1053,1056],{"class":987,"line":988},[985,1051,1052],{"class":991},"cp",[985,1054,1055],{"class":995}," .env.example",[985,1057,1058],{"class":995}," .env\n",[931,1060,1062],{"className":979,"code":1061,"filename":1041,"language":981,"meta":939,"style":939},"BASE_URL=https:\u002F\u002Fapi.\u003Cyour-tenant>.unitelabs.io\u002F\nAUTH_URL=https:\u002F\u002Fauth.\u003Cyour-tenant>.unitelabs.io\u002Frealms\u002F\u003Ctenant-id>\u002Fprotocol\u002Fopenid-connect\u002F\nCLIENT_ID=\u003Cyour-client-id>\nCLIENT_SECRET=\u003Cyour-client-secret>\n",[792,1063,1064,1089,1118,1133],{"__ignoreMap":939},[985,1065,1066,1070,1074,1077,1080,1083,1086],{"class":987,"line":988},[985,1067,1069],{"class":1068},"sTEyZ","BASE_URL",[985,1071,1073],{"class":1072},"sMK4o","=",[985,1075,1076],{"class":995},"https:\u002F\u002Fapi.",[985,1078,1079],{"class":1072},"\u003C",[985,1081,1082],{"class":995},"your-tenant",[985,1084,1085],{"class":1072},">",[985,1087,1088],{"class":995},".unitelabs.io\u002F\n",[985,1090,1091,1094,1096,1099,1101,1103,1105,1108,1110,1113,1115],{"class":987,"line":1002},[985,1092,1093],{"class":1068},"AUTH_URL",[985,1095,1073],{"class":1072},[985,1097,1098],{"class":995},"https:\u002F\u002Fauth.",[985,1100,1079],{"class":1072},[985,1102,1082],{"class":995},[985,1104,1085],{"class":1072},[985,1106,1107],{"class":995},".unitelabs.io\u002Frealms\u002F",[985,1109,1079],{"class":1072},[985,1111,1112],{"class":995},"tenant-id",[985,1114,1085],{"class":1072},[985,1116,1117],{"class":995},"\u002Fprotocol\u002Fopenid-connect\u002F\n",[985,1119,1121,1124,1127,1130],{"class":987,"line":1120},3,[985,1122,1123],{"class":1068},"CLIENT_ID",[985,1125,1126],{"class":1072},"=\u003C",[985,1128,1129],{"class":995},"your-client-id",[985,1131,1132],{"class":1072},">\n",[985,1134,1136,1139,1141,1144],{"class":987,"line":1135},4,[985,1137,1138],{"class":1068},"CLIENT_SECRET",[985,1140,1126],{"class":1072},[985,1142,1143],{"class":995},"your-client-secret",[985,1145,1132],{"class":1072},[952,1147,1148],{"icon":954},[756,1149,1150,1151,1154,1155,1158,1159,1161],{},"Need help getting these values? See ",[760,1152,77],{"href":1153},"\u002Fget-started\u002Fsetup\u002Fsdk-installation\u002F"," for how to set the credentials. W02 and W03 will also require access to UniteLabs private packages. If you have not set up a ",[792,1156,1157],{},".netrc"," file yet to get access, follow the instructions in the ",[760,1160,77],{"href":1153}," section.",[973,1163,1165],{"id":1164},"_3-install-a-workflows-dependencies","3. Install a workflow's dependencies",[756,1167,1168,1169,1172],{},"Each workflow syncs independently. Sync ",[792,1170,1171],{},"shared"," first, then any workflow you want to run locally:",[931,1174,1176],{"className":979,"code":1175,"language":981,"meta":939,"style":939},"uv sync --directory shared\nuv sync --directory w01-hello-world\nuv sync --directory w02-liquid-handling\nuv sync --directory w03-plateloc-sealer\n",[792,1177,1178,1192,1203,1214],{"__ignoreMap":939},[985,1179,1180,1183,1186,1189],{"class":987,"line":988},[985,1181,1182],{"class":991},"uv",[985,1184,1185],{"class":995}," sync",[985,1187,1188],{"class":995}," --directory",[985,1190,1191],{"class":995}," shared\n",[985,1193,1194,1196,1198,1200],{"class":987,"line":1002},[985,1195,1182],{"class":991},[985,1197,1185],{"class":995},[985,1199,1188],{"class":995},[985,1201,1202],{"class":995}," w01-hello-world\n",[985,1204,1205,1207,1209,1211],{"class":987,"line":1120},[985,1206,1182],{"class":991},[985,1208,1185],{"class":995},[985,1210,1188],{"class":995},[985,1212,1213],{"class":995}," w02-liquid-handling\n",[985,1215,1216,1218,1220,1222],{"class":987,"line":1135},[985,1217,1182],{"class":991},[985,1219,1185],{"class":995},[985,1221,1188],{"class":995},[985,1223,1224],{"class":995}," w03-plateloc-sealer\n",[756,1226,1227,1228,1231,1232,1234,1235,1237],{},"Each command creates the workflow's ",[792,1229,1230],{},".venv\u002F"," with its declared dependencies and the ",[792,1233,1171],{}," library installed editable. Edits to ",[792,1236,900],{}," are picked up without re-sync.",[973,1239,1241],{"id":1240},"_4-run-w01-hello-world","4. Run W01 Hello World",[756,1243,1244],{},"If you can run this workflow, you have successfully installed the UniteLabs SDK and executed a workflow using the workflow hierarchy. You are one step closer to deploying to the platform!",[756,1246,1247],{},"From the project root, run the following command:",[931,1249,1251],{"className":979,"code":1250,"language":981,"meta":939,"style":939},"uv run --directory w01-hello-world workflow\n",[792,1252,1253],{"__ignoreMap":939},[985,1254,1255,1257,1260,1262,1265],{"class":987,"line":988},[985,1256,1182],{"class":991},[985,1258,1259],{"class":995}," run",[985,1261,1188],{"class":995},[985,1263,1264],{"class":995}," w01-hello-world",[985,1266,1267],{"class":995}," workflow\n",[756,1269,1270],{},"You can also navigate into the workflow project and run it directly from there using",[931,1272,1274],{"className":979,"code":1273,"language":981,"meta":939,"style":939},"uv run workflow\n",[792,1275,1276],{"__ignoreMap":939},[985,1277,1278,1280,1282],{"class":987,"line":988},[985,1279,1182],{"class":991},[985,1281,1259],{"class":995},[985,1283,1267],{"class":995},[973,1285,1287],{"id":1286},"_5-run-w02-liquid-handling-locally-against-the-mock","5. Run W02 Liquid Handling locally against the mock",[756,1289,1290],{},"W02 runs end-to-end against the liquid handling mock, with no hardware and no credentials. The mock lives in the LH SDK, is stateless, and only validates that the workflow will run (a compiler-style check that inputs are theoretically valid). It does not simulate a device, so you will not see realistic timing or device state, but it is the fastest way to verify your environment and catch configuration errors.",[931,1292,1294],{"className":979,"code":1293,"language":981,"meta":939,"style":939},"uv run --directory w02-liquid-handling workflow\n",[792,1295,1296],{"__ignoreMap":939},[985,1297,1298,1300,1302,1304,1307],{"class":987,"line":988},[985,1299,1182],{"class":991},[985,1301,1259],{"class":995},[985,1303,1188],{"class":995},[985,1305,1306],{"class":995}," w02-liquid-handling",[985,1308,1267],{"class":995},[756,1310,758,1311,1313,1314,1317],{},[792,1312,447],{}," console script is declared in each workflow's ",[792,1315,1316],{},"[project.scripts]",". You should see workflow engine logs for the setup phase followed by eight column-by-column transfers in the transfer phase.",[952,1319,1321],{"icon":1320},"i-heroicons-light-bulb",[756,1322,1323,1324,1327,1328,1330],{},"Pass extra args via the same command, e.g. ",[792,1325,1326],{},"uv run --directory w02-liquid-handling workflow --hardware"," to run against a real Hamilton Microlab STAR. That path requires ",[792,1329,1041],{}," credentials and a reachable device.",[973,1332,1334],{"id":1333},"_6-deploy-a-workflow-to-the-platform","6. Deploy a workflow to the platform",[756,1336,1337],{},"Requirements before the first deploy:",[1339,1340,1341],"ul",{},[1342,1343,1344,1345,1347,1348,795,1350,795,1352,795,1354,1356,1357,1360],"li",{},"A populated ",[792,1346,1041],{}," at the repo root (",[792,1349,1069],{},[792,1351,1093],{},[792,1353,1123],{},[792,1355,1138],{},"). This is the same one you set up in step 2. ",[792,1358,1359],{},"scripts\u002Fdeploy.py"," loads it automatically and uses it to authenticate against the platform.",[756,1362,1363,1365,1366,1369,1370,1373],{},[792,1364,1359],{}," discovers workflows by globbing ",[792,1367,1368],{},"w*-*\u002Fpyproject.toml",", builds a bundle (workflow dir verbatim + ",[792,1371,1372],{},"shared\u002Fsrc\u002Fshared\u002F"," hoisted flat at the bundle root), and POSTs\u002FPATCHes it to the platform.",[931,1375,1377],{"className":979,"code":1376,"language":981,"meta":939,"style":939},"# Deploy every workflow\nuv run scripts\u002Fdeploy.py --all\n\n# Deploy a single workflow by slug\nuv run scripts\u002Fdeploy.py w02-liquid-handling\n\n# Deploy as DEV (display name prefixed [DEV] on the platform)\nuv run scripts\u002Fdeploy.py w02-liquid-handling --channel dev\n",[792,1378,1379,1385,1397,1403,1408,1419,1424,1430],{"__ignoreMap":939},[985,1380,1381],{"class":987,"line":988},[985,1382,1384],{"class":1383},"sHwdD","# Deploy every workflow\n",[985,1386,1387,1389,1391,1394],{"class":987,"line":1002},[985,1388,1182],{"class":991},[985,1390,1259],{"class":995},[985,1392,1393],{"class":995}," scripts\u002Fdeploy.py",[985,1395,1396],{"class":995}," --all\n",[985,1398,1399],{"class":987,"line":1120},[985,1400,1402],{"emptyLinePlaceholder":1401},true,"\n",[985,1404,1405],{"class":987,"line":1135},[985,1406,1407],{"class":1383},"# Deploy a single workflow by slug\n",[985,1409,1411,1413,1415,1417],{"class":987,"line":1410},5,[985,1412,1182],{"class":991},[985,1414,1259],{"class":995},[985,1416,1393],{"class":995},[985,1418,1213],{"class":995},[985,1420,1422],{"class":987,"line":1421},6,[985,1423,1402],{"emptyLinePlaceholder":1401},[985,1425,1427],{"class":987,"line":1426},7,[985,1428,1429],{"class":1383},"# Deploy as DEV (display name prefixed [DEV] on the platform)\n",[985,1431,1433,1435,1437,1439,1441,1444],{"class":987,"line":1432},8,[985,1434,1182],{"class":991},[985,1436,1259],{"class":995},[985,1438,1393],{"class":995},[985,1440,1306],{"class":995},[985,1442,1443],{"class":995}," --channel",[985,1445,1446],{"class":995}," dev\n",[756,1448,1449,1450,1453],{},"See ",[760,1451,499],{"href":1452},"\u002Fautomate\u002Fguides\u002Fdeploy-a-workflow\u002F"," for the full CLI reference.",[756,1455,1456],{},"Open the UniteLabs Workflows page to confirm the workflow appears with the correct name and description.",[973,1458,1460],{"id":1459},"_7-run-w03-plateloc-sealer-against-a-simulated-connector","7. Run W03 PlateLoc Sealer against a simulated connector",[756,1462,1463,1464,1467],{},"W03 drives a real connector instead of an in-SDK mock. From the workflow's perspective the simulation behaves 1:1 like the physical device, including state and transitions, because the simulation lives inside the ",[787,1465,1466],{},"connector"," itself, not inside the SDK.",[756,1469,1470],{},"Requirements before the first run:",[1339,1472,1473,1480],{},[1342,1474,1475,1476,894],{},"A running connector simulating a PlateLoc connected to the platform. Verify it appears on the Devices page. See how to ",[760,1477,1479],{"href":1478},"\u002Fintegrate\u002Fwhat-is-a-connector\u002F","start a connector",[1342,1481,1482,1484],{},[792,1483,1041],{}," to authenticate against the platform and reach the connector.",[756,1486,1487],{},"Start the workflow:",[931,1489,1491],{"className":979,"code":1490,"language":981,"meta":939,"style":939},"uv run --directory w03-plateloc-sealer workflow\n",[792,1492,1493],{"__ignoreMap":939},[985,1494,1495,1497,1499,1501,1504],{"class":987,"line":988},[985,1496,1182],{"class":991},[985,1498,1259],{"class":995},[985,1500,1188],{"class":995},[985,1502,1503],{"class":995}," w03-plateloc-sealer",[985,1505,1267],{"class":995},[756,1507,1508],{},"The flow runs two phases:",[1510,1511,1512,1521],"ol",{},[1342,1513,1514,1517,1518,1520],{},[787,1515,1516],{},"Prepare"," connects to the PlateLoc, moves the stage to the OUT position, and calls ",[792,1519,890],{}," so the operator can place a plate.",[1342,1522,1523,1526],{},[787,1524,1525],{},"Seal"," resumes after operator confirmation and moves the stage to the IN position to seal the plate.",[756,1528,1529,1530,1533,1534,1538,1539,1542,1543,1546,1547,1550,1551,1553],{},"While the workflow is paused, open the run in the UniteLabs Workflows page. An ",[787,1531,1532],{},"Input required"," banner appears at the top of the run with the message ",[1535,1536,1537],"em",{},"\"This workflow is waiting for user input to continue\"",". Click ",[787,1540,1541],{},"Provide Input",", tick the ",[787,1544,1545],{},"Confirmed"," checkbox in the dialog, and click ",[787,1548,1549],{},"Submit Input"," to resume the run. This is the canonical ",[760,1552,886],{"href":885}," pattern: a phase parks the run on an explicit operator checkpoint rather than polling or sleeping.",[952,1555,1556],{"icon":954},[756,1557,1558,1559,1562,1563,1566,1567,894],{},"The device name is resolved from ",[792,1560,1561],{},"shared\u002Fsrc\u002Fshared\u002Fconfig\u002Fplateloc.py"," (",[792,1564,1565],{},"INSTRUMENT_NAME","). If your connector is registered under a different name on the platform, override it: ",[792,1568,1569],{},"uv run --directory w03-plateloc-sealer workflow --device-name \"\u003Cyour-name>\"",[779,1571,1573],{"id":1572},"releasing-a-workflow","Releasing a workflow",[756,1575,1576,1577,1580,1581,1584],{},"Each workflow ships independently via a git tag of the form ",[792,1578,1579],{},"\u003Cslug>\u002Fv\u003CX.Y.Z>"," (slug = ",[792,1582,1583],{},"[project].name",", kebab-case).",[756,1586,1587,1588,1591],{},"To release ",[792,1589,1590],{},"w02-liquid-handling v1.2.0",":",[931,1593,1595],{"className":979,"code":1594,"language":981,"meta":939,"style":939},"# 1. Bump the workflow's version\n$EDITOR w02-liquid-handling\u002Fpyproject.toml\n# (set [project].version = \"1.2.0\")\n\n# 2. Commit\ngit commit -am \"release: w02-liquid-handling v1.2.0\"\n\n# 3. Tag and push\ngit tag w02-liquid-handling\u002Fv1.2.0\ngit push origin main --tags\n",[792,1596,1597,1602,1607,1612,1616,1621,1640,1644,1649,1660],{"__ignoreMap":939},[985,1598,1599],{"class":987,"line":988},[985,1600,1601],{"class":1383},"# 1. Bump the workflow's version\n",[985,1603,1604],{"class":987,"line":1002},[985,1605,1606],{"class":1068},"$EDITOR w02-liquid-handling\u002Fpyproject.toml\n",[985,1608,1609],{"class":987,"line":1120},[985,1610,1611],{"class":1383},"# (set [project].version = \"1.2.0\")\n",[985,1613,1614],{"class":987,"line":1135},[985,1615,1402],{"emptyLinePlaceholder":1401},[985,1617,1618],{"class":987,"line":1410},[985,1619,1620],{"class":1383},"# 2. Commit\n",[985,1622,1623,1625,1628,1631,1634,1637],{"class":987,"line":1421},[985,1624,992],{"class":991},[985,1626,1627],{"class":995}," commit",[985,1629,1630],{"class":995}," -am",[985,1632,1633],{"class":1072}," \"",[985,1635,1636],{"class":995},"release: w02-liquid-handling v1.2.0",[985,1638,1639],{"class":1072},"\"\n",[985,1641,1642],{"class":987,"line":1426},[985,1643,1402],{"emptyLinePlaceholder":1401},[985,1645,1646],{"class":987,"line":1432},[985,1647,1648],{"class":1383},"# 3. Tag and push\n",[985,1650,1652,1654,1657],{"class":987,"line":1651},9,[985,1653,992],{"class":991},[985,1655,1656],{"class":995}," tag",[985,1658,1659],{"class":995}," w02-liquid-handling\u002Fv1.2.0\n",[985,1661,1663,1665,1668,1671,1674],{"class":987,"line":1662},10,[985,1664,992],{"class":991},[985,1666,1667],{"class":995}," push",[985,1669,1670],{"class":995}," origin",[985,1672,1673],{"class":995}," main",[985,1675,1676],{"class":995}," --tags\n",[756,1678,1679,1680,1683,1684,1687,1688,1691,1692,1695],{},"CI matches the per-workflow tag pattern and runs ",[792,1681,1682],{},"scripts\u002Fdeploy.py --git-tag w02-liquid-handling\u002Fv1.2.0 --channel prd",". The script parses the tag, verifies the pyproject version matches ",[792,1685,1686],{},"1.2.0"," (refuses otherwise, since pyproject is the source of truth), ships the bundle, and adds ",[792,1689,1690],{},"v1.2.0"," to the platform tags. See ",[760,1693,507],{"href":1694},"\u002Fautomate\u002Fguides\u002Fcicd-for-workflows\u002F"," for the three-channel deploy model.",[779,1697,1699],{"id":1698},"adding-a-new-workflow","Adding a new workflow",[756,1701,1702,1703,1708],{},"Mechanical checklist (see ",[760,1704,1706],{"href":945,"rel":1705},[764],[792,1707,949],{}," for the full authoring rules):",[1510,1710,1711,1718,1750,1757,1763],{},[1342,1712,1713,1714,1717],{},"Create ",[792,1715,1716],{},"w{**}-{kebab-name}\u002F"," at the repo root.",[1342,1719,1720,1721],{},"Inside it, create:\n",[1339,1722,1723,1734,1744],{},[1342,1724,1725,1727,1728,1730,1731,1733],{},[792,1726,794],{}," mirroring an existing workflow (set ",[792,1729,1583],{},", version, description, dependencies, ",[792,1732,802],{},").",[1342,1735,1736,1739,1740,1743],{},[792,1737,1738],{},"src\u002Fw{**}_{snake_name}\u002Fworkflow.py"," (the ",[792,1741,1742],{},"@flow(retries=0)"," function).",[1342,1745,1746,1749],{},[792,1747,1748],{},"src\u002Fw{**}_{snake_name}\u002Fphase_{**}_{name}.py"," files for each phase.",[1342,1751,1752,1753,1756],{},"Add new shared code to ",[792,1754,1755],{},"shared\u002Fsrc\u002Fshared\u002F{config,library,steps,utils}\u002F"," if needed.",[1342,1758,1759,1762],{},[792,1760,1761],{},"uv sync --directory w{**}-{kebab-name}"," to generate the workflow's lockfile.",[1342,1764,1765,1766,1769,1770,1773],{},"Add the workflow's path to ",[792,1767,1768],{},".vscode\u002Fworkflow-template.code-workspace"," ",[792,1771,1772],{},"folders"," array.",[756,1775,1776,1777,1779],{},"No central registry to edit. ",[792,1778,1359],{}," discovers workflows automatically.",[779,1781,1783],{"id":1782},"next-steps","Next steps",[1339,1785,1786,1798,1808,1816,1825],{},[1342,1787,1788,1791,1792,1797],{},[787,1789,1790],{},"Author your own workflow",": follow the rules in ",[760,1793,1795],{"href":945,"rel":1794},[764],[792,1796,949],{}," (layer rules, retry policy, naming conventions).",[1342,1799,1800,1804,1805,1807],{},[760,1801,1802],{"href":1452},[787,1803,499],{},": the full ",[792,1806,1359],{}," CLI reference.",[1342,1809,1810,1815],{},[760,1811,1812],{"href":1694},[787,1813,1814],{},"Set up CI\u002FCD",": wire deploys to GitHub Actions or GitLab CI with the three-channel (dev\u002Fstg\u002Fprd) model.",[1342,1817,1818,1824],{},[760,1819,1821],{"href":1820},"\u002Fautomate\u002Fguides\u002Fworkflows-api\u002F",[787,1822,1823],{},"Trigger runs via the API",": start a deployed workflow programmatically.",[1342,1826,1827,1833],{},[760,1828,1830],{"href":1829},"\u002Fautomate\u002Fguides\u002Fbasic-hitl\u002F",[787,1831,1832],{},"Add human-in-the-loop steps",": use W02 as the reference pattern.",[1835,1836,1837],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":939,"searchDepth":988,"depth":1002,"links":1839},[1840,1841,1842,1851,1852,1853],{"id":781,"depth":1002,"text":782},{"id":915,"depth":1002,"text":916},{"id":967,"depth":1002,"text":968,"children":1843},[1844,1845,1846,1847,1848,1849,1850],{"id":975,"depth":1120,"text":976},{"id":1030,"depth":1120,"text":1031},{"id":1164,"depth":1120,"text":1165},{"id":1240,"depth":1120,"text":1241},{"id":1286,"depth":1120,"text":1287},{"id":1333,"depth":1120,"text":1334},{"id":1459,"depth":1120,"text":1460},{"id":1572,"depth":1002,"text":1573},{"id":1698,"depth":1002,"text":1699},{"id":1782,"depth":1002,"text":1783},"Clone a production-ready monorepo, run a workflow in simulation, and deploy any of the three reference workflows to the platform.","md",null,{},{"title":438,"description":1854},"vn3TkMPfYulX-dm1gye9wVgFNc9fKX98vjKrhPqIT60",[1861,1863],{"title":434,"path":435,"stem":436,"description":1862},"Workflows are the core automation primitive in UniteLabs: reproducible, versioned processes that coordinate instruments, data, and scientific logic.",{"title":442,"path":443,"stem":444,"description":1864},"Clone the workflow template, run the hello-world example locally, and scaffold your own first workflow in under 15 minutes.",1783607747404]