No new framework. Just your Python, reflected into a UI.
A note on versions — the IvoryOS in the Nature Communications paper was one app, UI and hardware control together. This page describes 2.0, a from-scratch rearchitecture into the three pieces below. Parts are shipped, parts are still being built, and each section says which.
Holds the drivers and their schemas. Where you assemble a stack and design against it.
Reflects your drivers into a UI and actually runs them. Works with no network at all.
Coordinates several Cores as one workflow. Early prototype.
Introspection, not integration.
Most orchestration tools need a plugin written against their SDK before they can control an instrument. IvoryOS instead inspects the Python you’ve already written — method names, type hints, docstrings, default values — and builds a matching form automatically. There is no schema to author by hand and no plugin API to keep in sync. Rename a parameter in your driver, and the generated interface updates with it.
def set_flow_rate(
self, rate: float
):
"""mL/min, 0-50"""
...This is why onboarding a new instrument is writing normal Python, not learning IvoryOS — and it’s the same mechanism that lets a driver contributed by one lab work, unmodified, in another.
You can write the Python. So can a model.
Scientists sweep parameters, engineers write drivers, and models now write workflow code too. The gap is in between: someone has to see what is about to run, before it runs.
And it compounds. The schema closes both gaps by giving all three the same thing to look at.
One place the workflow lives
Ten experiments in, workflows are usually scattered across notebooks and nobody is sure which version ran last week. Here they are stored, versioned and findable.
A preview before anything moves
Whoever proposed the step — a colleague or an assistant — you see the real parameters and their values before hardware does.
The driver stays the driver
The engineer writes ordinary Python. No interface code to keep in sync, and nothing to rewrite when the workflow changes.
Built for what wet-lab automation actually needs.
This is the Optimize page that Core serves beside your instruments. Every field on it maps directly to one of the capabilities on the right, generated from your own driver’s parameters.
Prep / Main / Cleanup phases
Setup and teardown steps run once per workflow; the main sequence is what repeats, gets batched, or gets optimized.
Batch-aware execution
Mark a step as “per-sample” or “batch.” A batch step runs once per group of N samples — for equipment that processes several samples at once — instead of once per row.
Closed-loop optimization
Ax, BayBE, and NIMO are wired in behind one suggest/observe interface, with parallel-trial batches, live convergence plots, and per-objective early-stop criteria.
Human-in-the-loop pauses
A workflow can pause and ask a person for a value — load a sample, confirm a reading — then resume exactly where it left off, from any device on the network.
Full run history
Every run, step, phase, and parameter is recorded to SQLite or Postgres — queryable later, not just streamed to a CSV and forgotten.
Typed, validated parameters
Every generated form inherits your driver's real type hints, so a string typed into a float field is caught before it ever reaches your hardware.
When one queue stops being enough.
Core already coordinates every instrument on its own network, but as one linear workflow, one queue, at a time. That holds until a lab has two things that need to happen on their own clocks. These are the three cases that made us start building Cloud.
Two cadences, one workflow
One station needs a step every four minutes, the next every five. Core runs one queue, so today they take turns. Cloud lets each keep its own timeline.
A sample that moves
Synthesis on one platform, analysis on another, and a physical transfer in between. The handoff is the part that has to be scheduled, and the run and its data have to travel with the sample.
An instrument two platforms share
A lightly used instrument rarely deserves its own platform. Give it its own Core and both sides reserve time on it, instead of discovering the conflict when an arm is already moving.
Drivers. Every one still runs in-process inside its own local Core, and Cloud only ever talks to a Core’s API. Hardware control stays exactly as local as it is today, and a lab keeps working if Cloud is unreachable.
The dashboard exists. The cross-Core orchestration protocol does not yet. This is the least mature part of 2.0 and the furthest from a release — the three cases above are why we are building it, not a description of what runs today.
Design your lab before you install a thing.
A directory of instrument drivers, optimizer plugins and workflow templates, contributed by the community. Because every contributed driver is introspected once and its schema stored, picking a stack and opening a working Designer are the same click — with nothing installed and no instrument on the bench.
A driver is contributed
Someone shares a Python driver to the Hub, which registers its install metadata: the package, its constructor arguments, how to launch it.
Its schema is captured too
The same introspection Core runs against real hardware runs once against the contributed driver, and the resulting schema is stored on the row beside it.
The Designer opens on it
Pick a stack and the full Designer opens in your browser, forms and all. It only ever needed the schema, never a live connection.