Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
43c2c66
Add the Lab inventory bridge
marpaia Aug 27, 2026
90d043e
Load SBOLInventory documents from lab.toml
marpaia Aug 27, 2026
b1e221d
Add EBEF inventory ingestion acceptance coverage
marpaia Aug 27, 2026
b1ec5d5
Preserve SBOL design identities through checked IR
marpaia Aug 27, 2026
7681c20
Index active SBOLInventory material lots
marpaia Aug 27, 2026
ab47546
Bind build requirements to exact material lots
marpaia Aug 27, 2026
775bc51
Use SBOLInventory capability IRIs in workflow contracts
marpaia Aug 27, 2026
ab29381
Emit typed workflow capability requirements
marpaia Aug 27, 2026
779a225
Declare asset-bound execution adapters
marpaia Aug 27, 2026
c952de0
Define the asset adapter contract
marpaia Aug 28, 2026
9962c12
Bind adapters to exact capability offerings
marpaia Aug 28, 2026
da6e060
Instantiate reachable capability requirements
marpaia Aug 28, 2026
e5af3fd
Preserve typed capability offering parameters
marpaia Aug 28, 2026
27c208a
Ground capability parameter constraints
marpaia Aug 28, 2026
38f8737
Allocate requirements across facility offerings
marpaia Aug 28, 2026
74d9926
Define the generic execution plan format
marpaia Aug 28, 2026
53bf683
Project facility allocation into execution plans
marpaia Aug 28, 2026
1e2c858
Add facility-wide planning to the CLI
marpaia Aug 28, 2026
c6a7e9b
Package frozen execution plan inputs
marpaia Aug 28, 2026
e648417
Preflight generic execution plans
marpaia Aug 28, 2026
5a6dd47
Bind execution ledgers to reviewed plans
marpaia Aug 28, 2026
490a5a6
Execute exact facility plan bindings
marpaia Aug 28, 2026
7b935d1
Run reviewed facility plans
marpaia Aug 28, 2026
3c5d528
Write SBOLInventory run provenance
marpaia Aug 28, 2026
7ae38e2
Remove the workcell compiler target
marpaia Aug 28, 2026
7e40668
Remove the workcell runtime format
marpaia Aug 28, 2026
1ec1b78
Add semantic capability simulation documents
marpaia Aug 28, 2026
2238302
Run reviewed plans in simulation mode
marpaia Aug 28, 2026
e1c80c1
Add EBEF-derived facility simulation acceptance
marpaia Aug 28, 2026
9299048
Supersede workcell architecture with facility graphs
marpaia Aug 28, 2026
b64efab
Use SBOLInventory in the Golden Gate example
marpaia Aug 28, 2026
5eafdb1
Resolve catalog names through exact inventory identities
marpaia Aug 28, 2026
56918b8
Use SBOLInventory in the extended Golden Gate example
marpaia Aug 28, 2026
85118a0
Lower protocols through allocated facility adapters
marpaia Aug 28, 2026
5111369
Derive Golden Gate protocols from facility plans
marpaia Aug 28, 2026
f6b53ee
Freeze facility lowerings in reviewed plans
marpaia Aug 28, 2026
5fe7f10
Remove independent target selection
marpaia Aug 28, 2026
9dd7355
Make adapter profiles implementation-only
marpaia Aug 28, 2026
ad006c3
Separate method selection from facility allocation
marpaia Aug 28, 2026
76297d4
Require reviewed facility plans for execution
marpaia Aug 28, 2026
292e0ac
Author package-local artifact kinds in Python
marpaia Aug 28, 2026
b94b539
Report biological products from lab build
marpaia Aug 28, 2026
bffc525
Build facility outputs from lab build
marpaia Aug 28, 2026
aa9c4f8
Make facility output paths readable
marpaia Aug 28, 2026
640c946
Preserve build roots in artifact paths
marpaia Aug 28, 2026
060eb29
Use sbol.io for SBOLInventory vocabulary
marpaia Aug 28, 2026
e8e9ece
Document the EBEF facility model
marpaia Aug 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 35 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ members = [
"crates/lab-compiler",
"crates/lab-ide",
"crates/lab-ide-wasm",
"crates/lab-inventory",
"crates/lab-instruments",
"crates/lab-language",
"crates/lab-language-server",
Expand Down Expand Up @@ -40,9 +41,11 @@ rusb = "0.9"
# SBOL 3 terms, serialization, and validation. Designs are read from and
# written to SBOL documents, so the standard's object model is the compiler's
# own rather than something a backend projects onto at the end.
sbol3 = "1"
sbol3 = { git = "https://github.com/SynBioDex/sbol-rs", rev = "2ecae3718ebb87dbdbf7112ed4d7f42c0155eea4" }
sbol-inventory = { git = "https://github.com/SynBioDex/sbol-rs", rev = "2ecae3718ebb87dbdbf7112ed4d7f42c0155eea4" }
semver = "1"
thiserror = "2"
time = { version = "0.3", features = ["formatting"] }
toml = "0.8"
lsp-server = "0.7"
lsp-types = "0.97"
Expand Down Expand Up @@ -75,6 +78,7 @@ hamilton-star = { version = "0.1.0", default-features = false }
lab-ide = { path = "crates/lab-ide", version = "0.1.2" }
inheco-sila = "0.1.0"
lab-ide-wasm = { path = "crates/lab-ide-wasm", version = "0.1.2" }
lab-inventory = { path = "crates/lab-inventory", version = "0.1.2" }
lab-instruments = { path = "crates/lab-instruments", version = "0.1.2" }
lab-language = { path = "crates/lab-language", version = "0.1.2" }
lab-language-server = { path = "crates/lab-language-server", version = "0.1.2" }
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ SBOL is not a third way in. It is the vocabulary designs are written and exchang

Lab is working toward a world in which laboratory work is portable, inspectable, and reliable across manual benches, automation, and cloud labs.

Today, protocols commonly entangle scientific intent with site-specific procedures. Lab separates them. A program describes biological designs, physical materials, workflows, and acceptance criteria; the compiler progressively specializes that program for the capabilities, policies, inventory, and hardware of a target laboratory.
Today, protocols commonly entangle scientific intent with site-specific procedures. Lab separates them. A program describes biological designs, physical materials, workflows, and acceptance criteria; the compiler progressively specializes that program against the capabilities, policies, inventory, and hardware of a selected facility.

One biological program should be adaptable to many valid execution environments without erasing what the scientist meant.

Expand All @@ -35,7 +35,7 @@ Lab treats laboratory automation as a compilation and control problem:

- the type system models biological artifacts, physical materials, durable effects, and evidence;
- two frontends, Python and Lab, lower to one checked module, which is the portable boundary nothing downstream reaches behind;
- **LAIR**, the Lab Automation Intermediate Representation, preserves meaning as programs are progressively lowered from portable intent to target-specific operations;
- **LAIR**, the Lab Automation Intermediate Representation, preserves meaning as programs are progressively lowered from portable intent to method-selected procedures and facility-bound device operations;
- the compiler checks types, action contracts, and material ownership while keeping specialization decisions inspectable;
- a durable runtime will execute idempotent actions, recover around failures, react to observations, and preserve lineage from intent to outcome.

Expand Down
1 change: 1 addition & 0 deletions crates/lab-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ anyhow.workspace = true
clap.workspace = true
flate2 = "1.1.9"
lab-compiler.workspace = true
lab-inventory.workspace = true
lab-runfmt.workspace = true
# The runner needs the live USB transport the workspace dependency keeps
# off by default.
Expand Down
61 changes: 29 additions & 32 deletions crates/lab-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ lab check
lab build
```

`lab.toml` anchors package identity and the build entry. Source modules are discovered recursively under `src/` and receive stable names from their package and relative path. Same-package imports and recursive path dependencies are compiled through checked module interfaces. `lab build` writes verified portable module IR plus a package index under `.lab/build/` and a deterministic `lab.lock` at the project root.
`lab.toml` anchors package identity and the build entry. Source modules are discovered recursively under `src/` and receive stable names from their package and relative path. Same-package imports and recursive path dependencies are compiled through checked module interfaces. Every `lab build` writes verified portable module IR, `capability_requirements.json`, `capability_instances.json` for runnable packages, an optional `adapter_bindings.json`, and a package index under `.lab/build/`, plus a deterministic `lab.lock` at the project root. The requirement file describes every checked workflow template and contains no facility allocation. The instance file expands only templates reachable from the exact entry module's `main` workflow, preserves every resolved workflow call site, and rejects recursive expansion rather than inventing a finite run. When the runnable package selects an SBOLInventory document, the same build then allocates those instances, invokes adapters selected through exact Asset bindings, emits their protocol bundles and PDFs, and freezes everything in `.lab/build/plan.execution.json`. The package index's optional `facility` section records relative paths to the allocation, lowering manifest, reviewed plan, bundle roots, protocols, and PDFs.

`lab plan` exposes that facility phase as a separate command, writing it under `.lab/plan/` without the portable module bundle. It requires an SBOLInventory document, applies the package's exact facility selector, allocates every reachable capability instance to one exact offering and Asset, and writes `facility_allocation.json` plus a validated `plan.execution.json`. Candidate ordering never chooses an asset: zero eligible offerings is an explained failure, and several eligible offerings require an explicit allocation policy. A planning-only or manual facility needs no adapter declaration. When an allocated Asset has a compatible lowering adapter, both `lab build` and `lab plan` emit its protocols and freeze its exact driver, profile, triggering requirements, child paths, formats, and digests in the reviewed plan.

A `lab.toml` may instead declare a workspace, grouping member packages under one root:

Expand All @@ -31,48 +33,43 @@ default-member = "packages/device"

A workspace root owns membership and nothing else; each member stays an ordinary package. `default-member` names the package a single-package command acts on, and is required once a workspace has more than one member.

## Building for a bench

`lab build --target <name>` reads `targets/<name>.toml`, lowers the default member and everything it depends on as one program, and hands the verified result to the backend that profile names:

```sh
lab build --target opentrons-ot2
```
## Facility-derived lowering

The target's artifacts are written under `.lab/build/<name>/`, and the build prints the path of every runnable automation protocol it emitted, ready to hand to an instrument application. A target profile describes the laboratory — modules, labware, deck slots, pipettes, mounts, and capacity — and never the science; reaction chemistry belongs to the designs in `src/`. Every profile field defaults to the backend's reference bench, so a profile states only what differs, and unknown keys are rejected rather than ignored. A profile's filename is its name; the file itself declares only which backend consumes it.
The portable frontend of `lab build` never contains an instrument selector: `[build]` names only the experiment entry, and the CLI has no `--target` mode. When the package names a facility document, the build derives device choice by matching the experiment's capability requirements against that validated facility. With no facility document, the same command stops after portable compilation.

Editors and control planes use the compiler-owned target contract rather than copying backend structs. It reports each backend's JSON Schema, complete default, catalog choices, capabilities, and workcell station kinds; validation runs the same cross-field semantics as a build and returns canonical TOML, canonical JSON, the compiler and schema versions, and a SHA-256:
An `[inventory]` table selects the SBOLInventory graph. Local adapter declarations connect exact Asset IRIs in that graph to installed Lab implementations:

```sh
lab targets describe
lab --json targets describe
lab targets default opentrons.flex --name flex-bay-1
lab targets validate targets/flex-bay-1.toml
lab --json targets render targets/flex-bay-1.toml
```toml
[inventory]
document = "inventory/facility.ttl"
# Required when the document has several facilities:
facility = "https://example.org/facilities/example-lab"

[[execution.adapters]]
asset = "https://example.org/facilities/example-lab/star-1"
driver = "hamilton.star"
profile = "adapters/star-1.toml"
```

The shipped backends are `opentrons.ot2`, `opentrons.flex`, `hamilton.star`, and `workcell`. `describe` is the discovery authority for the exact compiler binary in use; consumers should not assume that list remains fixed.
Each adapter declaration binds an implementation to one exact catalog Asset. Facility facts remain in RDF, driver selection is never inferred from product metadata, and endpoints and credentials remain local runtime configuration. The old symbolic `materials` and `artifacts` arrays are accepted only as a mutually exclusive migration form.

A package that usually compiles for one bench names it in the manifest instead of on every invocation:
The facility is the lowering surface. The facility phase shared by `lab build` and `lab plan` resolves exact MaterialLots, allocates requirements to CapabilityOfferings and their owning Assets, and invokes only the adapters attached to those selected Assets. The reviewed plan freezes the inventory, allocation, staged adapter profiles, and every emitted device and support artifact by SHA-256. Whole-program adapters produce one reviewed lowering bundle covering all of their triggering requirements; Lab does not pretend that one generated protocol corresponds to one arbitrary requirement.

```toml
[build]
entry = "src/programs/main.lab"
target = "opentrons-ot2"
```sh
lab build
lab run .lab/build --dry-run
```

`lab build` then produces that bench's protocols, `--target <name>` compiles for a different one, and `--no-target` stops at portable module IR.

An `[inventory]` table states what the laboratory has on hand, and a target build resolves every artifact dependency against it:
`lab adapters describe` is the discovery authority for the exact compiler binary. Its `lab.adapter-catalog.v1` output keeps semantic SBOLInventory capability IRIs separate from implementation features and declares accepted control modes, emitted document formats, configuration schemas, and actual planning, lowering, simulation, and runtime services. The explicit driver argument selects validation code; neither an adapter profile nor an Asset's manufacturer or model can select another implementation. `lab.adapter-profile.v2` contains no backend or Asset selector, rejects the removed `[target]` table, and places OT-2 API-version configuration under `[protocol]`.

```toml
[inventory]
materials = ["BsaI", "T4_DNA_ligase", "pSB1C3"]
artifacts = ["composite_plasmid_1"]
```sh
lab adapters describe
lab --json adapters describe --driver opentrons.flex
lab adapters default opentrons.flex --name flex-bay-1
lab adapters validate opentrons.flex adapters/flex-bay-1.toml
lab --json adapters render opentrons.flex adapters/flex-bay-1.toml
```

`materials` are consumables a reaction may draw on; `artifacts` are already realized and are not built again. Both default to empty, so a package that declares no inventory builds everything from nothing and reports what it is missing.

All read-oriented commands support `--json` for editor and automation clients:

```sh
Expand All @@ -82,4 +79,4 @@ lab check --json

Path dependencies may optionally carry a semver requirement, which is checked against the dependency manifest. Registry dependencies remain explicitly unsupported and fail closed; adding them requires a registry protocol and integrity model rather than silent fallback.

`lab run <run-directory> --dry-run` validates and narrates reviewed Hamilton STAR or workcell run documents without touching hardware. A live workcell run connects the supported stations, confirms every handoff with the operator, and appends a durable node ledger so `--resume` can continue without repeating completed motion.
`lab run <reviewed-plan-directory> --dry-run` validates the frozen inventory, exact bindings, adapter profiles, every reviewed child artifact, and the dependency DAG, then narrates every node without touching hardware. `lab run <reviewed-plan-directory> --simulate` walks the same exact plan through simulation adapters and writes `inventory-simulation.ttl`; `lab run <reviewed-plan-directory>` uses live executors and writes `inventory-after.ttl`. Both modes append a durable node ledger so `--resume` can continue without repeating completed work, but simulation and live ledgers are intentionally incompatible. Material movements and manual nodes remain explicit operator confirmations in either mode.
Loading